# driver.h

Go to the documentation of this file.

    00001 /* $Id: driver.h 11777 2008-01-07 14:23:25Z rubidium $ */
    00002
    00005 #ifndef DRIVER_H
    00006 #define DRIVER_H
    00007
    00008 #include "debug.h"
    00009 #include "core/enum_type.hpp"
    00010 #include "string_func.h"
    00011 #include <string>
    00012 #include <map>
    00013
    00014 bool GetDriverParamBool(const char * const *parm, const char *name);
    00015 int GetDriverParamInt(const char * const *parm, const char *name, int def);
    00016
    00017 class Driver {
    00018 public:
    00019   virtual const char *Start(const char * const *parm) = 0;
    00020
    00021   virtual void Stop() = 0;
    00022
    00023   virtual ~Driver() { }
    00024
    00025   enum Type {
    00026     DT_BEGIN = 0,
    00027     DT_SOUND = 0,
    00028     DT_MUSIC,
    00029     DT_VIDEO,
    00030     DT_END,
    00031   };
    00032 };
    00033
    00034 DECLARE_POSTFIX_INCREMENT(Driver::Type);
    00035
    00036
    00037 class DriverFactoryBase {
    00038 private:
    00039   Driver::Type type;
    00040   char *name;
    00041   int priority;
    00042   typedef std::map<std::string, DriverFactoryBase *> Drivers;
    00043
    00044   static Drivers &GetDrivers()
    00045   {
    00046     static Drivers &s_drivers = *new Drivers();
    00047     return s_drivers;
    00048   }
    00049
    00050   static Driver **GetActiveDriver(Driver::Type type)
    00051   {
    00052     static Driver *s_driver[3] = { NULL, NULL, NULL };
    00053     return &s_driver[type];
    00054   }
    00055
    00056   static const char *GetDriverTypeName(Driver::Type type)
    00057   {
    00058     static const char *driver_type_name[] = { "sound", "music", "video" };
    00059     return driver_type_name[type];
    00060   }
    00061
    00062 protected:
    00068   void RegisterDriver(const char *name, Driver::Type type, int priority)
    00069   {
    00070     /* Don't register nameless Drivers */
    00071     if (name == NULL) return;
    00072
    00073     this->name = strdup(name);
    00074     this->type = type;
    00075     this->priority = priority;
    00076
    00077     /* Prefix the name with driver type to make it unique */
    00078     char buf[32];
    00079     strecpy(buf, GetDriverTypeName(type), lastof(buf));
    00080     strecpy(buf + 5, name, lastof(buf));
    00081
    00082 #if !defined(NDEBUG) || defined(WITH_ASSERT)
    00083     /* NDEBUG disables asserts and gives a warning: unused variable 'P' */
    00084     std::pair<Drivers::iterator, bool> P =
    00085 #endif /* !NDEBUG */
    00086     GetDrivers().insert(Drivers::value_type(buf, this));
    00087     assert(P.second);
    00088   }
    00089
    00090 public:
    00091   DriverFactoryBase() :
    00092     name(NULL)
    00093   {}
    00094
    00095   virtual ~DriverFactoryBase() { if (this->name != NULL) GetDrivers().erase(this->name); free(this->name); }
    00096
    00102   static Driver *SelectDriver(const char *name, Driver::Type type)
    00103   {
    00104     if (GetDrivers().size() == 0) return NULL;
    00105
    00106     if (*name == '\0') {
    00107       /* Probe for this driver */
    00108       for (int priority = 10; priority >= 0; priority--) {
    00109         Drivers::iterator it = GetDrivers().begin();
    00110         for (; it != GetDrivers().end(); ++it) {
    00111           DriverFactoryBase *d = (*it).second;
    00112
    00113           /* Check driver type */
    00114           if (d->type != type) continue;
    00115           if (d->priority != priority) continue;
    00116
    00117           Driver *newd = d->CreateInstance();
    00118           const char *err = newd->Start(NULL);
    00119           if (err == NULL) {
    00120             DEBUG(driver, 1, "Successfully probed %s driver '%s'", GetDriverTypeName(type), d->name);
    00121             delete *GetActiveDriver(type);
    00122             *GetActiveDriver(type) = newd;
    00123             return newd;
    00124           }
    00125
    00126           DEBUG(driver, 1, "Probing %s driver '%s' failed with error: %s", GetDriverTypeName(type), d->name, err);
    00127           delete newd;
    00128         }
    00129       }
    00130       error("Couldn't find any suitable %s driver", GetDriverTypeName(type));
    00131     } else {
    00132       char *parm;
    00133       char buffer[256];
    00134       const char *parms[32];
    00135
    00136       /* Extract the driver name and put parameter list in parm */
    00137       strecpy(buffer, name, lastof(buffer));
    00138       parm = strchr(buffer, ':');
    00139       parms[0] = NULL;
    00140       if (parm != NULL) {
    00141         uint np = 0;
    00142         /* Tokenize the parm. */
    00143         do {
    00144           *parm++ = '\0';
    00145           if (np < lengthof(parms) - 1)
    00146             parms[np++] = parm;
    00147           while (*parm != '\0' && *parm != ',')
    00148             parm++;
    00149         } while (*parm == ',');
    00150         parms[np] = NULL;
    00151       }
    00152
    00153       /* Find this driver */
    00154       Drivers::iterator it = GetDrivers().begin();
    00155       for (; it != GetDrivers().end(); ++it) {
    00156         DriverFactoryBase *d = (*it).second;
    00157
    00158         /* Check driver type */
    00159         if (d->type != type) continue;
    00160
    00161         /* Check driver name */
    00162         if (strcasecmp(buffer, d->name) != 0) continue;
    00163
    00164         /* Found our driver, let's try it */
    00165         Driver *newd = d->CreateInstance();
    00166
    00167         const char *err = newd->Start(parms);
    00168         if (err != NULL) {
    00169           delete newd;
    00170           error("Unable to load driver '%s'. The error was: %s", d->name, err);
    00171         }
    00172
    00173         DEBUG(driver, 1, "Successfully loaded %s driver '%s'", GetDriverTypeName(type), d->name);
    00174         delete *GetActiveDriver(type);
    00175         *GetActiveDriver(type) = newd;
    00176         return newd;
    00177       }
    00178       error("No such %s driver: %s\n", GetDriverTypeName(type), buffer);
    00179     }
    00180   }
    00181
    00185   static char *GetDriversInfo(char *p, const char *last)
    00186   {
    00187     for (Driver::Type type = Driver::DT_BEGIN; type != Driver::DT_END; type++) {
    00188       p += snprintf(p, last - p, "List of %s drivers:\n", GetDriverTypeName(type));
    00189
    00190       for (int priority = 10; priority >= 0; priority--) {
    00191         Drivers::iterator it = GetDrivers().begin();
    00192         for (; it != GetDrivers().end(); it++) {
    00193           DriverFactoryBase *d = (*it).second;
    00194           if (d->type != type) continue;
    00195           if (d->priority != priority) continue;
    00196           p += snprintf(p, last - p, "%18s: %s\n", d->name, d->GetDescription());
    00197         }
    00198       }
    00199
    00200       p += snprintf(p, last - p, "\n");
    00201     }
    00202
    00203     return p;
    00204   }
    00205
    00209   virtual const char *GetDescription() = 0;
    00210
    00214   virtual Driver *CreateInstance() = 0;
    00215 };
    00216
    00217 #endif /* DRIVER_H */