FlightGear next
FGDeviceConfigurationMap.cxx
Go to the documentation of this file.
1// FGDeviceConfigurationMap.cxx -- a map to access xml device configuration
2//
3// Written by Torsten Dreyer, started August 2009
4// Based on work from David Megginson, started May 2001.
5//
6// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
7// Copyright (C) 2001 David Megginson, david@megginson.com
8//
9// This program is free software; you can redistribute it and/or
10// modify it under the terms of the GNU General Public License as
11// published by the Free Software Foundation; either version 2 of the
12// License, or (at your option) any later version.
13//
14// This program is distributed in the hope that it will be useful, but
15// WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// General Public License for more details.
18//
19// You should have received a copy of the GNU General Public License
20// along with this program; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22//
23// $Id$
24
25#ifdef HAVE_CONFIG_H
26# include <config.h>
27#endif
28
30
31#include <simgear/debug/ErrorReportingCallback.hxx>
32#include <simgear/misc/sg_dir.hxx>
33#include <simgear/props/props_io.hxx>
34#include <simgear/structure/exception.hxx>
35
36#include <Main/globals.hxx>
39
40using simgear::PropertyList;
41using std::string;
42
47
49 SGPropertyNode* nodePath,
50 const std::string& nodeName)
51{
52 // scan for over-ride configurations, loaded via joysticks.xml, etc
53 for (auto preloaded : nodePath->getChildren(nodeName)) {
54 std::string suffix = computeSuffix(preloaded);
55 for (auto nameProp : preloaded->getChildren("name")) {
56 overrideDict[nameProp->getStringValue() + suffix] = preloaded;
57 } // of names iteration
58 } // of defined overrides iteration
59
60 scan_dir( SGPath(globals->get_fg_home(), relative_path));
61 scan_dir( SGPath(globals->get_fg_root(), relative_path));
62}
63
64std::string FGDeviceConfigurationMap::computeSuffix(SGPropertyNode_ptr node)
65{
66 if (node->hasChild("serial-number")) {
67 return std::string("::") + node->getStringValue("serial-number");
68 }
69
70 // allow specifying a device number / index in the override
71 if (node->hasChild("device-number")) {
72 std::ostringstream os;
73 os << "_" << node->getIntValue("device-number");
74 return os.str();
75 }
76
77 return{};
78}
79
83
84SGPropertyNode_ptr
86{
87 auto j = overrideDict.find(name);
88 if (j != overrideDict.end()) {
89 return j->second;
90 }
91
92// no override, check out list of config files
93 auto it = namePathMap.find(name);
94 if (it == namePathMap.end()) {
95 return {};
96 }
97
98 SGPropertyNode_ptr result(new SGPropertyNode);
99 try {
100 readProperties(it->second, result);
101 result->setStringValue("source", it->second.utf8Str());
102 } catch (sg_exception& e) {
103 simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::InputDeviceConfig,
104 "Failed to parse device configuration:" + e.getFormattedMessage(),
105 it->second);
106 return {};
107 }
108
109 return result;
110}
111
113{
114 auto j = overrideDict.find(name);
115 if (j != overrideDict.end()) {
116 return true;
117 }
118
119 return namePathMap.find(name) != namePathMap.end();
120}
121
122void FGDeviceConfigurationMap::scan_dir(const SGPath & path)
123{
124 SG_LOG(SG_INPUT, SG_DEBUG, "Scanning " << path << " for input devices");
125 if (!path.exists())
126 return;
127
130
131 simgear::Dir dir(path);
132 simgear::PathList children = dir.children(simgear::Dir::TYPE_FILE |
133 simgear::Dir::TYPE_DIR | simgear::Dir::NO_DOT_OR_DOTDOT);
134
135 for (SGPath path : children) {
136 if (path.isDir()) {
137 scan_dir(path);
138 } else if (path.extension() == "xml") {
139 if (cache->isCachedFileModified(path)) {
140 refreshCacheForFile(path);
141 } else {
142 readCachedData(path);
143 } // of cached file stamp is valid
144 } // of child is a file with '.xml' extension
145 } // of directory children iteration
146
147 txn.commit();
148}
149
150void FGDeviceConfigurationMap::readCachedData(const SGPath& path)
151{
153 for (string s : cache->readStringListProperty(path.utf8Str())) {
154 // important - only insert if not already present. This ensures
155 // user configs can override those in the base package, since they are
156 // searched first.
157 if (namePathMap.find(s) == namePathMap.end()) {
158 namePathMap.insert(std::make_pair(s, path));
159 }
160 } // of cached names iteration
161}
162
163void FGDeviceConfigurationMap::refreshCacheForFile(const SGPath& path)
164{
165 simgear::ErrorReportContext ectx("input-device", path.utf8Str());
166
167 SG_LOG(SG_INPUT, SG_DEBUG, "Reading device file " << path);
168 SGPropertyNode_ptr n(new SGPropertyNode);
169 try {
170 readProperties(path, n);
171 } catch (sg_exception& e) {
172 simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::InputDeviceConfig,
173 "Failed to load input device configuration:" + e.getFormattedMessage(),
174 path);
175 return;
176 }
177
178 std::string suffix = computeSuffix(n);
179 string_list names;
180 for (auto nameProp : n->getChildren("name")) {
181 const string name = nameProp->getStringValue() + suffix;
182 names.push_back(name);
183 // same comment as readCachedData: only insert if not already present
184 if (namePathMap.find(name) == namePathMap.end()) {
185 namePathMap.insert(std::make_pair(name, path));
186 }
187 }
188
190 if (!cache->isReadOnly()) {
191 cache->stampCacheFile(path);
192 cache->writeStringListProperty(path.utf8Str(), names);
193 }
194}
SGPropertyNode_ptr configurationForDeviceName(const std::string &name)
bool hasConfiguration(const std::string &name) const
const SGPath & get_fg_home() const
Definition globals.hxx:213
const SGPath & get_fg_root() const
Definition globals.hxx:189
void stampCacheFile(const SGPath &path, const std::string &sha={})
string_list readStringListProperty(const std::string &key)
void writeStringListProperty(const std::string &key, const string_list &values)
static NavDataCache * instance()
bool isCachedFileModified(const SGPath &path) const
const char * name
FGGlobals * globals
Definition globals.cxx:142
std::vector< std::string > string_list
Definition globals.hxx:36