summaryrefslogtreecommitdiffstats
path: root/src/manager-lib/debugwrapper.cpp
blob: 9401f8aa6d43564162cee29fd175706f66a860f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright (C) 2021 The Qt Company Ltd.
// Copyright (C) 2019 Luxoft Sweden AB
// Copyright (C) 2018 Pelagicore AG
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:critical reason:data-parser

#include "debugwrapper.h"

using namespace Qt::StringLiterals;

QT_BEGIN_NAMESPACE_AM

namespace DebugWrapper {

bool parseSpecification(const QString &debugWrapperSpecification, QStringList &resultingCommand,
                        QMap<QString, QString> &resultingEnvironment)
{
    QStringList cmd;
    QMap<QString, QString> env;

    // split at ' ', but also accept escape sequences for '\ ', '\n' and '\\'
    // all leading FOO=BAR args will be converted to env var assignments
    bool escaped = false;
    bool canBeEnvVar = true;
    bool isEnvVar = false;
    static const QString program = u"%program%"_s;
    static const QString arguments = u"%arguments%"_s;
    int foundProgram = 0;
    int foundArguments = 0;
    QString str;
    QString value;
    QString *current = &str;
    qsizetype size = debugWrapperSpecification.size();
    for (qsizetype i = 0; i <= size; ++i) {
        const QChar c = (i < size) ? debugWrapperSpecification.at(i) : QChar(0);
        if (!escaped || c.isNull()) {
            switch (c.unicode()) {
            case '\\':
                escaped = true;
                break;
            case '=':
                // switch to value parsing if this can be an env var and if this is the first =
                // all other = are copied verbatim
                isEnvVar = canBeEnvVar;
                if (isEnvVar && current == &str)
                    current = &value;
                else
                    current->append(u'=');
                break;
            case ' ':
            case '\0':
                // found the end of an argument: add to env vars or cmd and reset state
                if (!str.isEmpty()) {
                    if (isEnvVar) {
                        env.insert(str, value);
                    } else {
                        cmd.append(str);

                        foundArguments = foundArguments || str.contains(arguments);
                        foundProgram = foundProgram || str.contains(program);
                    }
                }
                canBeEnvVar = isEnvVar; // stop parsing as envvar as soon as we get a normal arg
                isEnvVar = false;
                current = &str;
                str.clear();
                value.clear();
                break;
            default:
                current->append(c);
                break;
            }
        } else {
            switch (c.unicode()) {
            case '\\': current->append(u'\\'); break;
            case ' ':  current->append(u' '); break;
            case 'n':  current->append(u'\n'); break;
            default:   return false;
            }
            escaped = false;
        }
    }

    if (cmd.isEmpty() && env.isEmpty())
        return false;

    // convenience: if the spec doesn't include %program% or %arguments%, then simply append them
    if (!foundProgram)
        cmd << program;
    if (!foundArguments)
        cmd << arguments;

    resultingCommand = cmd;
    resultingEnvironment = env;
    return true;
}

QStringList substituteCommand(const QStringList &debugWrapperCommand, const QString &program,
                              const QStringList &arguments)
{
    QString stringifiedArguments = arguments.join(u' ');
    QStringList result;

    for (const QString &s : debugWrapperCommand) {
        if (s == u"%arguments%") {
            result << arguments;
        } else {
            QString str(s);
            str.replace(u"%program%"_s, program);
            str.replace(u"%arguments%"_s, stringifiedArguments);
            result << str;
        }
    }
    return result;
}

} // namespace DebugWrapper

QT_END_NAMESPACE_AM