Skip to content

Latest commit

 

History

History
566 lines (463 loc) · 17.9 KB

ssudeviceinfo.cpp

File metadata and controls

566 lines (463 loc) · 17.9 KB
 
1
2
3
4
5
6
7
/**
* @file ssudeviceinfo.cpp
* @copyright 2013 2013 Jolla Ltd.
* @author Bernd Wachter <bwachter@lart.info>
* @date 2013
*/
Apr 20, 2013
Apr 20, 2013
8
9
10
11
#include <QTextStream>
#include <QDir>
Oct 14, 2016
Oct 14, 2016
12
#include <QDBusReply>
Jul 10, 2014
Jul 10, 2014
13
14
15
#include <QDBusConnection>
#include <QDBusArgument>
Apr 26, 2013
Apr 26, 2013
16
17
#include <sys/utsname.h>
Oct 14, 2013
Oct 14, 2013
18
#include "sandbox_p.h"
19
#include "ssudeviceinfo.h"
Aug 21, 2015
Aug 21, 2015
20
21
22
#include "ssucoreconfig_p.h"
#include "ssulog_p.h"
#include "ssuvariables_p.h"
Mar 19, 2013
Mar 19, 2013
23
24
25
#include "../constants.h"
May 24, 2017
May 24, 2017
26
27
SsuDeviceInfo::SsuDeviceInfo(const QString &model)
: QObject()
Oct 10, 2016
Oct 10, 2016
28
{
Mar 19, 2013
Mar 19, 2013
29
boardMappings = new SsuSettings(SSU_BOARD_MAPPING_CONFIGURATION, SSU_BOARD_MAPPING_CONFIGURATION_DIR);
Apr 1, 2013
Apr 1, 2013
30
if (!model.isEmpty())
Oct 10, 2016
Oct 10, 2016
31
cachedModel = model;
Oct 10, 2016
Oct 10, 2016
34
35
36
37
38
SsuDeviceInfo::~SsuDeviceInfo()
{
delete boardMappings;
}
Oct 10, 2016
Oct 10, 2016
39
40
41
QStringList SsuDeviceInfo::adaptationRepos()
{
QStringList result;
Mar 27, 2013
Mar 27, 2013
42
Oct 10, 2016
Oct 10, 2016
43
QString model = deviceVariant(true);
Mar 27, 2013
Mar 27, 2013
44
Oct 10, 2016
Oct 10, 2016
45
46
if (boardMappings->contains(model + "/adaptation-repos"))
result = boardMappings->value(model + "/adaptation-repos").toStringList();
Oct 10, 2016
Oct 10, 2016
48
return result;
Mar 27, 2013
Mar 27, 2013
49
50
}
Oct 10, 2016
Oct 10, 2016
51
52
53
54
QString SsuDeviceInfo::adaptationVariables(const QString &adaptationName, QHash<QString, QString> *storageHash)
{
SsuLog *ssuLog = SsuLog::instance();
QStringList adaptationRepoList = adaptationRepos();
Jun 20, 2019
Jun 20, 2019
55
56
QString model = deviceVariant(true);
Oct 10, 2016
Oct 10, 2016
57
58
59
60
61
62
// special handling for adaptation-repositories
// - check if repo is in right format (adaptation\d*)
// - check if the configuration has that many adaptation repos
// - export the entry in the adaptation list as %(adaptation)
// - look up variables for that adaptation, and export matching
// adaptation variable
Oct 10, 2016
Oct 10, 2016
63
QRegExp regex("adaptation\\d*", Qt::CaseSensitive, QRegExp::RegExp2);
Oct 10, 2016
Oct 10, 2016
64
if (regex.exactMatch(adaptationName)) {
Oct 10, 2016
Oct 10, 2016
65
regex.setPattern("\\d*");
Oct 10, 2016
Oct 10, 2016
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
regex.lastIndexIn(adaptationName);
int n = regex.cap().toInt();
if (!adaptationRepoList.isEmpty()) {
if (adaptationRepoList.size() <= n) {
ssuLog->print(LOG_INFO, "Note: repo index out of bounds, substituting 0" + adaptationName);
n = 0;
}
QString adaptationRepo = adaptationRepoList.at(n);
storageHash->insert("adaptation", adaptationRepo);
ssuLog->print(LOG_DEBUG, "Found first adaptation " + adaptationName);
QHash<QString, QString> h;
// add global variables for this model
if (boardMappings->contains(model + "/variables")) {
QStringList sections = boardMappings->value(model + "/variables").toStringList();
foreach (const QString &section, sections)
variableSection(section, &h);
}
// override with variables specific to this repository
variableSection(adaptationRepo, &h);
QHash<QString, QString>::const_iterator i = h.constBegin();
while (i != h.constEnd()) {
storageHash->insert(i.key(), i.value());
i++;
}
} else
ssuLog->print(LOG_INFO, "Note: adaptation repo for invalid repo requested " + adaptationName);
return "adaptation";
}
Jun 20, 2019
Jun 20, 2019
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// If adaptation has defined repository-specific-variables and it matches to the
// repository name then also get those variables.
else if (boardMappings->contains(model + "/repository-specific-variables")) {
QStringList sections = boardMappings->value(model + "/repository-specific-variables").toStringList();
if (sections.contains(model + "-" + adaptationName)) {
QHash<QString, QString> h;
variableSection(model + "-" + adaptationName, &h);
QHash<QString, QString>::const_iterator i = h.constBegin();
while (i != h.constEnd()) {
storageHash->insert(i.key(), i.value());
i++;
}
}
}
Oct 10, 2016
Oct 10, 2016
118
return adaptationName;
Apr 1, 2013
Apr 1, 2013
119
120
}
Oct 10, 2016
Oct 10, 2016
121
122
void SsuDeviceInfo::clearCache()
{
May 24, 2017
May 24, 2017
123
124
125
cachedFamily.clear();
cachedModel.clear();
cachedVariant.clear();
Jun 13, 2013
Jun 13, 2013
126
127
}
Oct 10, 2016
Oct 10, 2016
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
bool SsuDeviceInfo::contains(const QString &model)
{
QString oldModel = deviceModel();
bool found = false;
if (!model.isEmpty()) {
clearCache();
setDeviceModel(model);
}
if (!deviceVariant(false).isEmpty())
found = true;
if (boardMappings->childGroups().contains(deviceModel()))
found = true;
if (!model.isEmpty()) {
clearCache();
setDeviceModel(oldModel);
}
return found;
Jun 13, 2013
Jun 13, 2013
148
149
}
Oct 10, 2016
Oct 10, 2016
150
151
152
153
QString SsuDeviceInfo::deviceFamily()
{
if (!cachedFamily.isEmpty())
return cachedFamily;
Oct 10, 2016
Oct 10, 2016
155
QString model = deviceVariant(true);
Mar 9, 2018
Mar 9, 2018
157
if (boardMappings->contains(model + "/family")) {
Oct 10, 2016
Oct 10, 2016
158
cachedFamily = boardMappings->value(model + "/family").toString();
Mar 9, 2018
Mar 9, 2018
159
160
161
162
163
164
165
} else {
// In case family is not defined, lets use device variant, which
// falls back to device model. This way we can use the deviceFamily
// in common repository names where we want to have same feature package
// for multiple devices some of which have family and some which do not.
cachedFamily = model;
}
Oct 10, 2016
Oct 10, 2016
167
return cachedFamily;
Oct 10, 2016
Oct 10, 2016
170
171
172
173
QString SsuDeviceInfo::deviceVariant(bool fallback)
{
if (!cachedVariant.isEmpty())
return cachedVariant;
Mar 19, 2013
Mar 19, 2013
174
Oct 10, 2016
Oct 10, 2016
175
176
177
if (boardMappings->contains("variants/" + deviceModel())) {
cachedVariant = boardMappings->value("variants/" + deviceModel()).toString();
}
Mar 19, 2013
Mar 19, 2013
178
May 24, 2017
May 24, 2017
179
if (cachedVariant.isEmpty() && fallback)
Oct 10, 2016
Oct 10, 2016
180
return deviceModel();
Mar 29, 2013
Mar 29, 2013
181
Oct 10, 2016
Oct 10, 2016
182
return cachedVariant;
Mar 19, 2013
Mar 19, 2013
183
184
}
Oct 10, 2016
Oct 10, 2016
185
186
187
188
QString SsuDeviceInfo::deviceModel()
{
if (!cachedModel.isEmpty())
return cachedModel;
Oct 10, 2016
Oct 10, 2016
190
boardMappings->beginGroup("file.exists");
May 24, 2017
May 24, 2017
191
QStringList keys = boardMappings->allKeys();
Oct 10, 2016
Oct 10, 2016
193
194
195
// check if the device can be identified by testing for a file
foreach (const QString &key, keys) {
QString value = boardMappings->value(key).toString();
May 24, 2017
May 24, 2017
196
QDir dir;
Oct 10, 2016
Oct 10, 2016
197
198
199
200
if (dir.exists(Sandbox::map(value))) {
cachedModel = key;
break;
}
201
202
}
boardMappings->endGroup();
Oct 10, 2016
Oct 10, 2016
203
204
205
if (!cachedModel.isEmpty()) return cachedModel;
// check if the device can be identified by a string in /proc/cpuinfo
May 24, 2017
May 24, 2017
206
QFile procCpuinfo;
Oct 10, 2016
Oct 10, 2016
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
procCpuinfo.setFileName(Sandbox::map("/proc/cpuinfo"));
procCpuinfo.open(QIODevice::ReadOnly | QIODevice::Text);
if (procCpuinfo.isOpen()) {
QTextStream in(&procCpuinfo);
QString cpuinfo = in.readAll();
boardMappings->beginGroup("cpuinfo.contains");
keys = boardMappings->allKeys();
foreach (const QString &key, keys) {
QString value = boardMappings->value(key).toString();
if (cpuinfo.contains(value)) {
cachedModel = key;
break;
}
}
boardMappings->endGroup();
}
if (!cachedModel.isEmpty()) return cachedModel;
// mer-hybris adaptations: /etc/hw-release MER_HA_DEVICE variable
QString hwReleaseDevice = hwRelease()["MER_HA_DEVICE"];
if (!hwReleaseDevice.isEmpty()) {
boardMappings->beginGroup("hwrelease.device");
keys = boardMappings->allKeys();
foreach (const QString &key, keys) {
QString value = boardMappings->value(key).toString();
if (hwReleaseDevice == value) {
cachedModel = key;
break;
}
}
boardMappings->endGroup();
}
if (!cachedModel.isEmpty()) return cachedModel;
// check if the device can be identified by the kernel version string
struct utsname buf;
if (!uname(&buf)) {
QString utsRelease(buf.release);
boardMappings->beginGroup("uname-release.contains");
keys = boardMappings->allKeys();
foreach (const QString &key, keys) {
QString value = boardMappings->value(key).toString();
if (utsRelease.contains(value)) {
cachedModel = key;
break;
}
}
boardMappings->endGroup();
}
if (!cachedModel.isEmpty()) return cachedModel;
Oct 10, 2016
Oct 10, 2016
261
262
263
// check if there's a match on arch of generic fallback. This probably
// only makes sense for x86
boardMappings->beginGroup("arch.equals");
Apr 17, 2014
Apr 17, 2014
264
265
keys = boardMappings->allKeys();
Oct 10, 2016
Oct 10, 2016
266
SsuCoreConfig *settings = SsuCoreConfig::instance();
Apr 17, 2014
Apr 17, 2014
267
foreach (const QString &key, keys) {
Oct 10, 2016
Oct 10, 2016
268
269
270
271
272
QString value = boardMappings->value(key).toString();
if (settings->value("arch").toString() == value) {
cachedModel = key;
break;
}
Apr 26, 2013
Apr 26, 2013
273
274
}
boardMappings->endGroup();
Oct 10, 2016
Oct 10, 2016
275
if (cachedModel.isEmpty()) cachedModel = "UNKNOWN";
Oct 10, 2016
Oct 10, 2016
277
return cachedModel;
Jul 10, 2014
Jul 10, 2014
280
281
282
283
284
static QStringList
ofonoGetImeis()
{
QStringList result;
Oct 14, 2016
Oct 14, 2016
285
QDBusReply<QStringList> reply = QDBusConnection::systemBus().call(
Oct 10, 2016
Oct 10, 2016
286
287
QDBusMessage::createMethodCall("org.ofono", "/",
"org.nemomobile.ofono.ModemManager", "GetIMEI"));
Nov 24, 2015
Nov 24, 2015
288
Oct 14, 2016
Oct 14, 2016
289
290
if (reply.isValid()) {
result = reply.value();
Jul 10, 2014
Jul 10, 2014
291
}
Jul 10, 2014
Jul 10, 2014
293
294
295
return result;
}
Mar 13, 2015
Mar 13, 2015
296
297
298
299
300
301
302
static QStringList
getWlanMacs()
{
// Based on QtSystems' qnetworkinfo_linux.cpp
QStringList result;
QStringList dirs = QDir(QLatin1String("/sys/class/net/"))
Oct 10, 2016
Oct 10, 2016
303
.entryList(QStringList() << QLatin1String("wlan*"));
Mar 13, 2015
Mar 13, 2015
304
305
306
307
308
309
310
311
312
313
foreach (const QString &dir, dirs) {
QFile carrier(QString("/sys/class/net/%1/address").arg(dir));
if (carrier.open(QIODevice::ReadOnly)) {
result.append(QString::fromLatin1(carrier.readAll().simplified().data()));
}
}
return result;
}
static QString
Oct 10, 2016
Oct 10, 2016
314
normalizeUid(const QString &uid)
Mar 13, 2015
Mar 13, 2015
315
316
317
318
319
{
// Normalize by stripping colons, dashes and making it lowercase
return uid.trimmed().replace(":", "").replace("-", "").toLower();
}
Oct 10, 2016
Oct 10, 2016
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
QString SsuDeviceInfo::deviceUid()
{
SsuLog *ssuLog = SsuLog::instance();
QStringList imeis = ofonoGetImeis();
if (imeis.size() > 0) {
return imeis[0];
}
QStringList wlanMacs = getWlanMacs();
if (wlanMacs.size() > 0) {
return normalizeUid(wlanMacs[0]);
}
ssuLog->print(LOG_WARNING, "Could not get IMEI(s) from ofono, nor WLAN mac, trying fallback");
// The fallback list is taken from QtSystems' qdeviceinfo_linux.cpp
QStringList fallbackFiles;
fallbackFiles << "/sys/devices/virtual/dmi/id/product_uuid";
fallbackFiles << "/etc/machine-id";
fallbackFiles << "/etc/unique-id";
fallbackFiles << "/var/lib/dbus/machine-id";
foreach (const QString &filename, fallbackFiles) {
QFile machineId(filename);
Apr 9, 2019
Apr 9, 2019
344
if (machineId.open(QFile::ReadOnly | QFile::Text) && machineId.size() > 0) {
Oct 10, 2016
Oct 10, 2016
345
346
347
348
349
350
QTextStream in(&machineId);
return normalizeUid(in.readAll());
}
}
ssuLog->print(LOG_CRIT, "Could not read fallback UID - returning empty string");
May 24, 2017
May 24, 2017
351
return QString();
Mar 19, 2013
Mar 19, 2013
353
Oct 10, 2016
Oct 10, 2016
354
355
356
QStringList SsuDeviceInfo::disabledRepos()
{
QStringList result;
Mar 28, 2013
Mar 28, 2013
357
Oct 10, 2016
Oct 10, 2016
358
QString model = deviceVariant(true);
Mar 28, 2013
Mar 28, 2013
359
Oct 10, 2016
Oct 10, 2016
360
361
if (boardMappings->contains(model + "/disabled-repos"))
result = boardMappings->value(model + "/disabled-repos").toStringList();
Mar 28, 2013
Mar 28, 2013
362
Oct 10, 2016
Oct 10, 2016
363
return result;
Mar 28, 2013
Mar 28, 2013
364
365
}
May 24, 2017
May 24, 2017
366
QString SsuDeviceInfo::displayName(int type)
Oct 10, 2016
Oct 10, 2016
367
368
369
370
{
QString model = deviceModel();
QString variant = deviceVariant(false);
QString value, key;
Oct 24, 2013
Oct 24, 2013
371
Oct 10, 2016
Oct 10, 2016
372
switch (type) {
Oct 24, 2013
Oct 24, 2013
373
case Ssu::DeviceManufacturer:
Oct 10, 2016
Oct 10, 2016
374
375
key = "/deviceManufacturer";
break;
Oct 24, 2013
Oct 24, 2013
376
case Ssu::DeviceModel:
Oct 10, 2016
Oct 10, 2016
377
378
key = "/prettyModel";
break;
Oct 24, 2013
Oct 24, 2013
379
case Ssu::DeviceDesignation:
Oct 10, 2016
Oct 10, 2016
380
381
key = "/deviceDesignation";
break;
Oct 24, 2013
Oct 24, 2013
382
default:
May 24, 2017
May 24, 2017
383
return QString();
Oct 10, 2016
Oct 10, 2016
384
385
386
387
388
389
390
391
392
393
394
395
}
/*
* Go through different levels of fallbacks:
* 1. model specific setting
* 2. variant specific setting
* 3. global setting
* 4. return model name, or "UNKNOWN" in case query was for manufacturer
*/
if (boardMappings->contains(model + key))
value = boardMappings->value(model + key).toString();
May 24, 2017
May 24, 2017
396
else if (!variant.isEmpty() && boardMappings->contains(variant + key))
Oct 10, 2016
Oct 10, 2016
397
398
399
400
401
402
403
404
405
value = boardMappings->value(variant + key).toString();
else if (boardMappings->contains(key))
value = boardMappings->value(key).toString();
else if (type != Ssu::DeviceManufacturer)
value = model;
else
value = "UNKNOWN";
return value;
Oct 24, 2013
Oct 24, 2013
406
407
}
Mar 31, 2013
Mar 31, 2013
408
409
410
// this half belongs into repo-manager, as it not only handles board-specific
// repositories. Right now this one looks like the better place due to the
// connection to board specific stuff, though
Oct 10, 2016
Oct 10, 2016
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
QStringList SsuDeviceInfo::repos(bool rnd, int filter)
{
int adaptationCount = adaptationRepos().size();
QStringList result;
///@TODO move this to a hash, containing repo and enabled|disabled
/// write repos with enabled/disabled to disks
/// for the compat functions providing a stringlist, do the filtering
/// run only when creating the list, based on the enabled|disabled flags
if (filter == Ssu::NoFilter ||
filter == Ssu::BoardFilter ||
filter == Ssu::BoardFilterUserBlacklist) {
// for repo names we have adaptation0, adaptation1, ..., adaptationN
for (int i = 0; i < adaptationCount; i++)
result.append(QString("adaptation%1").arg(i));
// now read the release/rnd repos
SsuSettings repoSettings(SSU_REPO_CONFIGURATION, QSettings::IniFormat);
QString repoKey = (rnd ? "default-repos/rnd" : "default-repos/release");
if (repoSettings.contains(repoKey))
result.append(repoSettings.value(repoKey).toStringList());
// TODO: add specific repos (developer, sdk, ..)
// add device configured repos
if (boardMappings->contains(deviceVariant(true) + "/repos"))
result.append(boardMappings->value(deviceVariant(true) + "/repos").toStringList());
// add device configured repos only valid for rnd and/or release
repoKey = (rnd ? "/repos-rnd" : "/repos-release");
if (boardMappings->contains(deviceVariant(true) + repoKey))
result.append(boardMappings->value(deviceVariant(true) + repoKey).toStringList());
// read the disabled repositories for this device
// user can override repositories disabled here in the user configuration
foreach (const QString &key, disabledRepos())
result.removeAll(key);
}
result.removeDuplicates();
return result;
Mar 28, 2013
Mar 28, 2013
453
454
}
May 24, 2017
May 24, 2017
455
QVariant SsuDeviceInfo::variable(const QString &section, const QString &key)
Oct 10, 2016
Oct 10, 2016
456
457
458
{
/// @todo compat-setting as ssudeviceinfo guaranteed to prepend sections with var-;
/// SsuVariables does not have this guarantee. Remove from here as well.
May 24, 2017
May 24, 2017
459
460
461
QString varSection(section);
if (!varSection.startsWith("var-"))
varSection = "var-" + varSection;
Jul 6, 2013
Jul 6, 2013
462
May 24, 2017
May 24, 2017
463
return SsuVariables::variable(boardMappings, varSection, key);
Jun 13, 2013
Jun 13, 2013
464
465
}
May 24, 2017
May 24, 2017
466
void SsuDeviceInfo::variableSection(const QString &section, QHash<QString, QString> *storageHash)
Oct 10, 2016
Oct 10, 2016
467
{
May 24, 2017
May 24, 2017
468
469
470
QString varSection(section);
if (!varSection.startsWith("var-"))
varSection = "var-" + varSection;
Jul 5, 2013
Jul 5, 2013
471
May 24, 2017
May 24, 2017
472
SsuVariables::variableSection(boardMappings, varSection, storageHash);
Mar 27, 2013
Mar 27, 2013
473
474
}
May 24, 2017
May 24, 2017
475
void SsuDeviceInfo::setDeviceModel(const QString &model)
Oct 10, 2016
Oct 10, 2016
476
{
May 24, 2017
May 24, 2017
477
478
if (model.isEmpty())
cachedModel.clear();
Oct 10, 2016
Oct 10, 2016
479
480
else
cachedModel = model;
Mar 27, 2013
Mar 27, 2013
481
May 24, 2017
May 24, 2017
482
483
cachedFamily.clear();
cachedVariant.clear();
Mar 27, 2013
Mar 27, 2013
484
}
Apr 1, 2013
Apr 1, 2013
485
Oct 10, 2016
Oct 10, 2016
486
487
488
489
490
491
492
QVariant SsuDeviceInfo::value(const QString &key, const QVariant &value)
{
if (boardMappings->contains(deviceModel() + "/" + key)) {
return boardMappings->value(deviceModel() + "/" + key);
} else if (boardMappings->contains(deviceVariant() + "/" + key)) {
return boardMappings->value(deviceVariant() + "/" + key);
}
Apr 1, 2013
Apr 1, 2013
493
Oct 10, 2016
Oct 10, 2016
494
return value;
Apr 1, 2013
Apr 1, 2013
495
}
Apr 17, 2014
Apr 17, 2014
496
497
498
QMap<QString, QString> SsuDeviceInfo::hwRelease()
{
Oct 10, 2016
Oct 10, 2016
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
QMap<QString, QString> result;
// Specification of the format, encoding is similar to /etc/os-release
// http://www.freedesktop.org/software/systemd/man/os-release.html
QFile hwRelease("/etc/hw-release");
if (hwRelease.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&hwRelease);
// "All strings should be in UTF-8 format, and non-printable characters
// should not be used."
in.setCodec("UTF-8");
while (!in.atEnd()) {
QString line = in.readLine();
// "Lines beginning with "#" shall be ignored as comments."
if (line.startsWith('#')) {
continue;
}
QString key = line.section('=', 0, 0);
QString value = line.section('=', 1);
// Remove trailing whitespace in value
value = value.trimmed();
// POSIX.1-2001 says uppercase, digits and underscores.
//
// Bash uses "[a-zA-Z_]+[a-zA-Z0-9_]*", so we'll use that too,
// as we can safely assume that "shell-compatible variable
// assignments" means it should be compatible with bash.
//
// see http://stackoverflow.com/a/2821183
// and http://stackoverflow.com/a/2821201
if (!QRegExp("[a-zA-Z_]+[a-zA-Z0-9_]*").exactMatch(key)) {
qWarning("Invalid key in input line: '%s'", qPrintable(line));
continue;
}
// "Variable assignment values should be enclosed in double or
// single quotes if they include spaces, semicolons or other
// special characters outside of A-Z, a-z, 0-9."
if (((value.at(0) == '\'') || (value.at(0) == '"'))) {
if (value.at(0) != value.at(value.size() - 1)) {
qWarning("Quoting error in input line: '%s'", qPrintable(line));
continue;
}
// Remove the quotes
value = value.mid(1, value.size() - 2);
}
// "If double or single quotes or backslashes are to be used within
// variable assignments, they should be escaped with backslashes,
// following shell style."
value = value.replace("\\\"", "\"");
value = value.replace("\\'", "'");
value = value.replace("\\\\", "\\");
result[key] = value;
Apr 17, 2014
Apr 17, 2014
560
561
}
Oct 10, 2016
Oct 10, 2016
562
hwRelease.close();
Apr 17, 2014
Apr 17, 2014
563
564
}
Oct 10, 2016
Oct 10, 2016
565
return result;
Apr 17, 2014
Apr 17, 2014
566
}