tron@2186: /* $Id$ */ tron@2186: belugas@6125: /** @file driver.h */ belugas@6125: tron@2171: #ifndef DRIVER_H tron@2171: #define DRIVER_H tron@2171: peter1138@7170: #include "debug.h" rubidium@8112: #include "core/enum_type.hpp" rubidium@8214: #include "string_func.h" peter1138@7170: #include peter1138@7170: #include tron@2171: rubidium@7318: bool GetDriverParamBool(const char * const *parm, const char *name); rubidium@7318: int GetDriverParamInt(const char * const *parm, const char *name, int def); tron@2171: peter1138@7170: class Driver { peter1138@7170: public: peter1138@7170: virtual const char *Start(const char * const *parm) = 0; peter1138@7170: peter1138@7170: virtual void Stop() = 0; peter1138@7170: peter1138@7170: virtual ~Driver() { } peter1138@7170: peter1138@7170: enum Type { peter1138@7170: DT_BEGIN = 0, peter1138@7170: DT_SOUND = 0, peter1138@7170: DT_MUSIC, peter1138@7170: DT_VIDEO, peter1138@7170: DT_END, peter1138@7170: }; peter1138@7170: }; peter1138@7170: peter1138@7170: DECLARE_POSTFIX_INCREMENT(Driver::Type); peter1138@7170: peter1138@7170: peter1138@7170: class DriverFactoryBase { peter1138@7170: private: peter1138@7170: Driver::Type type; peter1138@7170: char *name; peter1138@7193: int priority; peter1138@7170: typedef std::map Drivers; peter1138@7170: peter1138@7170: static Drivers &GetDrivers() peter1138@7170: { peter1138@7170: static Drivers &s_drivers = *new Drivers(); peter1138@7170: return s_drivers; peter1138@7170: } peter1138@7170: peter1138@7170: static Driver **GetActiveDriver(Driver::Type type) peter1138@7170: { peter1138@7170: static Driver *s_driver[3] = { NULL, NULL, NULL }; peter1138@7170: return &s_driver[type]; peter1138@7170: } peter1138@7170: peter1138@7170: static const char *GetDriverTypeName(Driver::Type type) peter1138@7170: { peter1138@7170: static const char *driver_type_name[] = { "sound", "music", "video" }; peter1138@7170: return driver_type_name[type]; peter1138@7170: } peter1138@7170: peter1138@7170: protected: peter1138@7170: /** peter1138@7170: * Register a driver internally, based on its name. peter1138@7170: * @param name the name of the driver. peter1138@7170: * @note an assert() will be trigger if 2 driver with the same name try to register. peter1138@7170: */ peter1138@7193: void RegisterDriver(const char *name, Driver::Type type, int priority) peter1138@7170: { peter1138@7170: /* Don't register nameless Drivers */ peter1138@7170: if (name == NULL) return; peter1138@7170: peter1138@7170: this->name = strdup(name); peter1138@7170: this->type = type; peter1138@7193: this->priority = priority; peter1138@7170: peter1138@7170: /* Prefix the name with driver type to make it unique */ peter1138@7170: char buf[32]; peter1138@7170: strecpy(buf, GetDriverTypeName(type), lastof(buf)); peter1138@7170: strecpy(buf + 5, name, lastof(buf)); peter1138@7170: glx@8051: #if !defined(NDEBUG) || defined(WITH_ASSERT) truelight@7254: /* NDEBUG disables asserts and gives a warning: unused variable 'P' */ truelight@7254: std::pair P = truelight@7254: #endif /* !NDEBUG */ truelight@7254: GetDrivers().insert(Drivers::value_type(buf, this)); peter1138@7170: assert(P.second); peter1138@7170: } peter1138@7170: peter1138@7170: public: peter1138@7170: DriverFactoryBase() : peter1138@7170: name(NULL) peter1138@7170: {} peter1138@7170: peter1138@7170: virtual ~DriverFactoryBase() { if (this->name != NULL) GetDrivers().erase(this->name); free(this->name); } peter1138@7170: peter1138@7170: /** peter1138@7170: * Find the requested driver and return its class. peter1138@7170: * @param name the driver to select. peter1138@7170: * @post Sets the driver so GetCurrentDriver() returns it too. peter1138@7170: */ peter1138@7170: static Driver *SelectDriver(const char *name, Driver::Type type) peter1138@7170: { peter1138@7170: if (GetDrivers().size() == 0) return NULL; peter1138@7170: peter1138@7170: if (*name == '\0') { peter1138@7170: /* Probe for this driver */ peter1138@7193: for (int priority = 10; priority >= 0; priority--) { peter1138@7193: Drivers::iterator it = GetDrivers().begin(); peter1138@7193: for (; it != GetDrivers().end(); ++it) { peter1138@7193: DriverFactoryBase *d = (*it).second; peter1138@7170: peter1138@7193: /* Check driver type */ peter1138@7193: if (d->type != type) continue; peter1138@7193: if (d->priority != priority) continue; peter1138@7170: peter1138@7193: Driver *newd = d->CreateInstance(); peter1138@7170: const char *err = newd->Start(NULL); peter1138@7170: if (err == NULL) { peter1138@7170: DEBUG(driver, 1, "Successfully probed %s driver '%s'", GetDriverTypeName(type), d->name); peter1138@7170: delete *GetActiveDriver(type); peter1138@7170: *GetActiveDriver(type) = newd; peter1138@7170: return newd; peter1138@7170: } peter1138@7170: peter1138@7170: DEBUG(driver, 1, "Probing %s driver '%s' failed with error: %s", GetDriverTypeName(type), d->name, err); peter1138@7193: delete newd; peter1138@7170: } peter1138@7170: } peter1138@7170: error("Couldn't find any suitable %s driver", GetDriverTypeName(type)); peter1138@7170: } else { peter1138@7170: char *parm; peter1138@7170: char buffer[256]; peter1138@7170: const char *parms[32]; peter1138@7170: peter1138@7170: /* Extract the driver name and put parameter list in parm */ peter1138@7170: strecpy(buffer, name, lastof(buffer)); peter1138@7170: parm = strchr(buffer, ':'); peter1138@7170: parms[0] = NULL; peter1138@7170: if (parm != NULL) { peter1138@7170: uint np = 0; peter1138@7170: /* Tokenize the parm. */ peter1138@7170: do { peter1138@7170: *parm++ = '\0'; peter1138@7170: if (np < lengthof(parms) - 1) peter1138@7170: parms[np++] = parm; peter1138@7170: while (*parm != '\0' && *parm != ',') peter1138@7170: parm++; peter1138@7170: } while (*parm == ','); peter1138@7170: parms[np] = NULL; peter1138@7170: } peter1138@7170: peter1138@7170: /* Find this driver */ peter1138@7170: Drivers::iterator it = GetDrivers().begin(); peter1138@7170: for (; it != GetDrivers().end(); ++it) { peter1138@7170: DriverFactoryBase *d = (*it).second; peter1138@7170: peter1138@7170: /* Check driver type */ peter1138@7170: if (d->type != type) continue; peter1138@7170: peter1138@7170: /* Check driver name */ peter1138@7170: if (strcasecmp(buffer, d->name) != 0) continue; peter1138@7170: peter1138@7170: /* Found our driver, let's try it */ peter1138@7170: Driver *newd = d->CreateInstance(); peter1138@7170: peter1138@7170: const char *err = newd->Start(parms); peter1138@7170: if (err != NULL) { peter1138@7170: delete newd; peter1138@7170: error("Unable to load driver '%s'. The error was: %s", d->name, err); peter1138@7170: } peter1138@7170: peter1138@7170: DEBUG(driver, 1, "Successfully loaded %s driver '%s'", GetDriverTypeName(type), d->name); peter1138@7170: delete *GetActiveDriver(type); peter1138@7170: *GetActiveDriver(type) = newd; peter1138@7170: return newd; peter1138@7170: } peter1138@7170: error("No such %s driver: %s\n", GetDriverTypeName(type), buffer); peter1138@7170: } peter1138@7170: } peter1138@7170: peter1138@7170: /** peter1138@7170: * Build a human readable list of available drivers, grouped by type. peter1138@7170: */ peter1138@7170: static char *GetDriversInfo(char *p, const char *last) peter1138@7170: { peter1138@7170: for (Driver::Type type = Driver::DT_BEGIN; type != Driver::DT_END; type++) { peter1138@7170: p += snprintf(p, last - p, "List of %s drivers:\n", GetDriverTypeName(type)); peter1138@7170: peter1138@7193: for (int priority = 10; priority >= 0; priority--) { peter1138@7193: Drivers::iterator it = GetDrivers().begin(); peter1138@7193: for (; it != GetDrivers().end(); it++) { peter1138@7193: DriverFactoryBase *d = (*it).second; peter1138@7193: if (d->type != type) continue; peter1138@7193: if (d->priority != priority) continue; peter1138@7193: p += snprintf(p, last - p, "%18s: %s\n", d->name, d->GetDescription()); peter1138@7193: } peter1138@7170: } peter1138@7170: peter1138@7170: p += snprintf(p, last - p, "\n"); peter1138@7170: } peter1138@7170: peter1138@7170: return p; peter1138@7170: } peter1138@7170: peter1138@7170: /** peter1138@7170: * Get a nice description of the driver-class. peter1138@7170: */ peter1138@7170: virtual const char *GetDescription() = 0; peter1138@7170: peter1138@7170: /** peter1138@7170: * Create an instance of this driver-class. peter1138@7170: */ peter1138@7170: virtual Driver *CreateInstance() = 0; peter1138@7170: }; tron@2171: Darkvater@2436: #endif /* DRIVER_H */