Fix #9521: Don't load at just removed docks that were part of a multi-dock station...
[openttd-github.git] / src / driver.cpp
blob417bde7072d32534eae436c53023e6acd58bec68
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
8 /** @file driver.cpp Base for all driver handling. */
10 #include "stdafx.h"
11 #include "debug.h"
12 #include "error.h"
13 #include "sound/sound_driver.hpp"
14 #include "music/music_driver.hpp"
15 #include "video/video_driver.hpp"
16 #include "string_func.h"
17 #include "table/strings.h"
18 #include <string>
19 #include <sstream>
21 #include "safeguards.h"
23 std::string _ini_videodriver; ///< The video driver a stored in the configuration file.
24 std::vector<Dimension> _resolutions; ///< List of resolutions.
25 Dimension _cur_resolution; ///< The current resolution.
26 bool _rightclick_emulate; ///< Whether right clicking is emulated.
28 std::string _ini_sounddriver; ///< The sound driver a stored in the configuration file.
30 std::string _ini_musicdriver; ///< The music driver a stored in the configuration file.
32 std::string _ini_blitter; ///< The blitter as stored in the configuration file.
33 bool _blitter_autodetected; ///< Was the blitter autodetected or specified by the user?
35 /**
36 * Get a string parameter the list of parameters.
37 * @param parm The parameters.
38 * @param name The parameter name we're looking for.
39 * @return The parameter value.
41 const char *GetDriverParam(const StringList &parm, const char *name)
43 if (parm.empty()) return nullptr;
45 size_t len = strlen(name);
46 for (auto &p : parm) {
47 if (p.compare(0, len, name) == 0) {
48 if (p.length() == len) return "";
49 if (p[len] == '=') return p.c_str() + len + 1;
52 return nullptr;
55 /**
56 * Get a boolean parameter the list of parameters.
57 * @param parm The parameters.
58 * @param name The parameter name we're looking for.
59 * @return The parameter value.
61 bool GetDriverParamBool(const StringList &parm, const char *name)
63 return GetDriverParam(parm, name) != nullptr;
66 /**
67 * Get an integer parameter the list of parameters.
68 * @param parm The parameters.
69 * @param name The parameter name we're looking for.
70 * @param def The default value if the parameter doesn't exist.
71 * @return The parameter value.
73 int GetDriverParamInt(const StringList &parm, const char *name, int def)
75 const char *p = GetDriverParam(parm, name);
76 return p != nullptr ? atoi(p) : def;
79 /**
80 * Find the requested driver and return its class.
81 * @param name the driver to select.
82 * @param type the type of driver to select
83 * @post Sets the driver so GetCurrentDriver() returns it too.
85 void DriverFactoryBase::SelectDriver(const std::string &name, Driver::Type type)
87 if (!DriverFactoryBase::SelectDriverImpl(name, type)) {
88 name.empty() ?
89 usererror("Failed to autoprobe %s driver", GetDriverTypeName(type)) :
90 usererror("Failed to select requested %s driver '%s'", GetDriverTypeName(type), name.c_str());
94 /**
95 * Find the requested driver and return its class.
96 * @param name the driver to select.
97 * @param type the type of driver to select
98 * @post Sets the driver so GetCurrentDriver() returns it too.
99 * @return True upon success, otherwise false.
101 bool DriverFactoryBase::SelectDriverImpl(const std::string &name, Driver::Type type)
103 if (GetDrivers().size() == 0) return false;
105 if (name.empty()) {
106 /* Probe for this driver, but do not fall back to dedicated/null! */
107 for (int priority = 10; priority > 0; priority--) {
108 Drivers::iterator it = GetDrivers().begin();
109 for (; it != GetDrivers().end(); ++it) {
110 DriverFactoryBase *d = (*it).second;
112 /* Check driver type */
113 if (d->type != type) continue;
114 if (d->priority != priority) continue;
116 if (type == Driver::DT_VIDEO && !_video_hw_accel && d->UsesHardwareAcceleration()) continue;
118 Driver *oldd = *GetActiveDriver(type);
119 Driver *newd = d->CreateInstance();
120 *GetActiveDriver(type) = newd;
122 const char *err = newd->Start({});
123 if (err == nullptr) {
124 Debug(driver, 1, "Successfully probed {} driver '{}'", GetDriverTypeName(type), d->name);
125 delete oldd;
126 return true;
129 *GetActiveDriver(type) = oldd;
130 Debug(driver, 1, "Probing {} driver '{}' failed with error: {}", GetDriverTypeName(type), d->name, err);
131 delete newd;
133 if (type == Driver::DT_VIDEO && _video_hw_accel && d->UsesHardwareAcceleration()) {
134 _video_hw_accel = false;
135 ErrorMessageData msg(STR_VIDEO_DRIVER_ERROR, STR_VIDEO_DRIVER_ERROR_NO_HARDWARE_ACCELERATION);
136 ScheduleErrorMessage(msg);
140 usererror("Couldn't find any suitable %s driver", GetDriverTypeName(type));
141 } else {
142 /* Extract the driver name and put parameter list in parm */
143 std::istringstream buffer(name);
144 std::string dname;
145 std::getline(buffer, dname, ':');
147 std::string param;
148 std::vector<std::string> parms;
149 while (std::getline(buffer, param, ',')) {
150 parms.push_back(param);
153 /* Find this driver */
154 Drivers::iterator it = GetDrivers().begin();
155 for (; it != GetDrivers().end(); ++it) {
156 DriverFactoryBase *d = (*it).second;
158 /* Check driver type */
159 if (d->type != type) continue;
161 /* Check driver name */
162 if (strcasecmp(dname.c_str(), d->name) != 0) continue;
164 /* Found our driver, let's try it */
165 Driver *newd = d->CreateInstance();
167 const char *err = newd->Start(parms);
168 if (err != nullptr) {
169 delete newd;
170 usererror("Unable to load driver '%s'. The error was: %s", d->name, err);
173 Debug(driver, 1, "Successfully loaded {} driver '{}'", GetDriverTypeName(type), d->name);
174 delete *GetActiveDriver(type);
175 *GetActiveDriver(type) = newd;
176 return true;
178 usererror("No such %s driver: %s\n", GetDriverTypeName(type), dname.c_str());
183 * Build a human readable list of available drivers, grouped by type.
184 * @param p The buffer to write to.
185 * @param last The last element in the buffer.
186 * @return The end of the written buffer.
188 char *DriverFactoryBase::GetDriversInfo(char *p, const char *last)
190 for (Driver::Type type = Driver::DT_BEGIN; type != Driver::DT_END; type++) {
191 p += seprintf(p, last, "List of %s drivers:\n", GetDriverTypeName(type));
193 for (int priority = 10; priority >= 0; priority--) {
194 Drivers::iterator it = GetDrivers().begin();
195 for (; it != GetDrivers().end(); it++) {
196 DriverFactoryBase *d = (*it).second;
197 if (d->type != type) continue;
198 if (d->priority != priority) continue;
199 p += seprintf(p, last, "%18s: %s\n", d->name, d->GetDescription());
203 p += seprintf(p, last, "\n");
206 return p;
210 * Construct a new DriverFactory.
211 * @param type The type of driver.
212 * @param priority The priority within the driver class.
213 * @param name The name of the driver.
214 * @param description A long-ish description of the driver.
216 DriverFactoryBase::DriverFactoryBase(Driver::Type type, int priority, const char *name, const char *description) :
217 type(type), priority(priority), name(name), description(description)
219 /* Prefix the name with driver type to make it unique */
220 char buf[32];
221 strecpy(buf, GetDriverTypeName(type), lastof(buf));
222 strecpy(buf + 5, name, lastof(buf));
224 Drivers &drivers = GetDrivers();
225 assert(drivers.find(buf) == drivers.end());
226 drivers.insert(Drivers::value_type(buf, this));
230 * Frees memory used for this->name
232 DriverFactoryBase::~DriverFactoryBase()
234 /* Prefix the name with driver type to make it unique */
235 char buf[32];
236 strecpy(buf, GetDriverTypeName(type), lastof(buf));
237 strecpy(buf + 5, this->name, lastof(buf));
239 Drivers::iterator it = GetDrivers().find(buf);
240 assert(it != GetDrivers().end());
242 GetDrivers().erase(it);
243 if (GetDrivers().empty()) delete &GetDrivers();