58 static const char *driver_type_name[] = { "sound", "music", "video" }; |
58 static const char *driver_type_name[] = { "sound", "music", "video" }; |
59 return driver_type_name[type]; |
59 return driver_type_name[type]; |
60 } |
60 } |
61 |
61 |
62 protected: |
62 protected: |
63 /** |
63 void RegisterDriver(const char *name, Driver::Type type, int priority); |
64 * Register a driver internally, based on its name. |
|
65 * @param name the name of the driver. |
|
66 * @note an assert() will be trigger if 2 driver with the same name try to register. |
|
67 */ |
|
68 void RegisterDriver(const char *name, Driver::Type type, int priority) |
|
69 { |
|
70 /* Don't register nameless Drivers */ |
|
71 if (name == NULL) return; |
|
72 |
|
73 this->name = strdup(name); |
|
74 this->type = type; |
|
75 this->priority = priority; |
|
76 |
|
77 /* Prefix the name with driver type to make it unique */ |
|
78 char buf[32]; |
|
79 strecpy(buf, GetDriverTypeName(type), lastof(buf)); |
|
80 strecpy(buf + 5, name, lastof(buf)); |
|
81 |
|
82 #if !defined(NDEBUG) || defined(WITH_ASSERT) |
|
83 /* NDEBUG disables asserts and gives a warning: unused variable 'P' */ |
|
84 std::pair<Drivers::iterator, bool> P = |
|
85 #endif /* !NDEBUG */ |
|
86 GetDrivers().insert(Drivers::value_type(buf, this)); |
|
87 assert(P.second); |
|
88 } |
|
89 |
64 |
90 public: |
65 public: |
91 DriverFactoryBase() : |
66 DriverFactoryBase() : |
92 name(NULL) |
67 name(NULL) |
93 {} |
68 {} |
94 |
69 |
95 virtual ~DriverFactoryBase() { if (this->name != NULL) GetDrivers().erase(this->name); free(this->name); } |
70 virtual ~DriverFactoryBase() { if (this->name != NULL) GetDrivers().erase(this->name); free(this->name); } |
96 |
71 |
97 /** |
72 static const Driver *SelectDriver(const char *name, Driver::Type type); |
98 * Find the requested driver and return its class. |
73 static char *GetDriversInfo(char *p, const char *last); |
99 * @param name the driver to select. |
|
100 * @post Sets the driver so GetCurrentDriver() returns it too. |
|
101 */ |
|
102 static Driver *SelectDriver(const char *name, Driver::Type type) |
|
103 { |
|
104 if (GetDrivers().size() == 0) return NULL; |
|
105 |
|
106 if (*name == '\0') { |
|
107 /* Probe for this driver */ |
|
108 for (int priority = 10; priority >= 0; priority--) { |
|
109 Drivers::iterator it = GetDrivers().begin(); |
|
110 for (; it != GetDrivers().end(); ++it) { |
|
111 DriverFactoryBase *d = (*it).second; |
|
112 |
|
113 /* Check driver type */ |
|
114 if (d->type != type) continue; |
|
115 if (d->priority != priority) continue; |
|
116 |
|
117 Driver *newd = d->CreateInstance(); |
|
118 const char *err = newd->Start(NULL); |
|
119 if (err == NULL) { |
|
120 DEBUG(driver, 1, "Successfully probed %s driver '%s'", GetDriverTypeName(type), d->name); |
|
121 delete *GetActiveDriver(type); |
|
122 *GetActiveDriver(type) = newd; |
|
123 return newd; |
|
124 } |
|
125 |
|
126 DEBUG(driver, 1, "Probing %s driver '%s' failed with error: %s", GetDriverTypeName(type), d->name, err); |
|
127 delete newd; |
|
128 } |
|
129 } |
|
130 error("Couldn't find any suitable %s driver", GetDriverTypeName(type)); |
|
131 } else { |
|
132 char *parm; |
|
133 char buffer[256]; |
|
134 const char *parms[32]; |
|
135 |
|
136 /* Extract the driver name and put parameter list in parm */ |
|
137 strecpy(buffer, name, lastof(buffer)); |
|
138 parm = strchr(buffer, ':'); |
|
139 parms[0] = NULL; |
|
140 if (parm != NULL) { |
|
141 uint np = 0; |
|
142 /* Tokenize the parm. */ |
|
143 do { |
|
144 *parm++ = '\0'; |
|
145 if (np < lengthof(parms) - 1) |
|
146 parms[np++] = parm; |
|
147 while (*parm != '\0' && *parm != ',') |
|
148 parm++; |
|
149 } while (*parm == ','); |
|
150 parms[np] = NULL; |
|
151 } |
|
152 |
|
153 /* Find this driver */ |
|
154 Drivers::iterator it = GetDrivers().begin(); |
|
155 for (; it != GetDrivers().end(); ++it) { |
|
156 DriverFactoryBase *d = (*it).second; |
|
157 |
|
158 /* Check driver type */ |
|
159 if (d->type != type) continue; |
|
160 |
|
161 /* Check driver name */ |
|
162 if (strcasecmp(buffer, d->name) != 0) continue; |
|
163 |
|
164 /* Found our driver, let's try it */ |
|
165 Driver *newd = d->CreateInstance(); |
|
166 |
|
167 const char *err = newd->Start(parms); |
|
168 if (err != NULL) { |
|
169 delete newd; |
|
170 error("Unable to load driver '%s'. The error was: %s", d->name, err); |
|
171 } |
|
172 |
|
173 DEBUG(driver, 1, "Successfully loaded %s driver '%s'", GetDriverTypeName(type), d->name); |
|
174 delete *GetActiveDriver(type); |
|
175 *GetActiveDriver(type) = newd; |
|
176 return newd; |
|
177 } |
|
178 error("No such %s driver: %s\n", GetDriverTypeName(type), buffer); |
|
179 } |
|
180 } |
|
181 |
|
182 /** |
|
183 * Build a human readable list of available drivers, grouped by type. |
|
184 */ |
|
185 static char *GetDriversInfo(char *p, const char *last) |
|
186 { |
|
187 for (Driver::Type type = Driver::DT_BEGIN; type != Driver::DT_END; type++) { |
|
188 p += snprintf(p, last - p, "List of %s drivers:\n", GetDriverTypeName(type)); |
|
189 |
|
190 for (int priority = 10; priority >= 0; priority--) { |
|
191 Drivers::iterator it = GetDrivers().begin(); |
|
192 for (; it != GetDrivers().end(); it++) { |
|
193 DriverFactoryBase *d = (*it).second; |
|
194 if (d->type != type) continue; |
|
195 if (d->priority != priority) continue; |
|
196 p += snprintf(p, last - p, "%18s: %s\n", d->name, d->GetDescription()); |
|
197 } |
|
198 } |
|
199 |
|
200 p += snprintf(p, last - p, "\n"); |
|
201 } |
|
202 |
|
203 return p; |
|
204 } |
|
205 |
74 |
206 /** |
75 /** |
207 * Get a nice description of the driver-class. |
76 * Get a nice description of the driver-class. |
208 */ |
77 */ |
209 virtual const char *GetDescription() = 0; |
78 virtual const char *GetDescription() = 0; |