File: ShellCommand.cpp

package info (click to toggle)
qmlkonsole 25.12.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,680 kB
  • sloc: cpp: 12,794; xml: 345; makefile: 3; sh: 1
file content (143 lines) | stat: -rw-r--r-- 3,524 bytes parent folder | download | duplicates (2)
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
    SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

// Own
#include "ShellCommand.h"

// KDE
#include <KShell>

using Konsole::ShellCommand;

ShellCommand::ShellCommand(const QString &aCommand)
    : _arguments(KShell::splitArgs(aCommand))
{
}

ShellCommand::ShellCommand(const QString &aCommand, const QStringList &aArguments)
    : _arguments(aArguments)
{
    if (!_arguments.isEmpty()) {
        _arguments[0] = aCommand;
    }
}

QString ShellCommand::fullCommand() const
{
    QStringList quotedArgs(_arguments);
    for (int i = 0; i < quotedArgs.size(); i++) {
        QString arg = quotedArgs.at(i);
        bool hasSpace = false;
        for (int j = 0; j < arg.size(); j++) {
            if (arg[j].isSpace()) {
                hasSpace = true;
            }
        }
        if (hasSpace) {
            quotedArgs[i] = QLatin1Char('\"') + arg + QLatin1Char('\"');
        }
    }
    return quotedArgs.join(QLatin1Char(' '));
}

QString ShellCommand::command() const
{
    if (!_arguments.isEmpty()) {
        return _arguments[0];
    }
    return QString();
}

QStringList ShellCommand::arguments() const
{
    return _arguments;
}

QStringList ShellCommand::expand(const QStringList &items)
{
    QStringList result;
    result.reserve(items.size());

    for (const QString &item : items) {
        result << expand(item);
    }

    return result;
}

QString ShellCommand::expand(const QString &text)
{
    QString result = text;
    expandEnv(result);
    return result;
}

bool ShellCommand::isValidEnvCharacter(const QChar &ch)
{
    const ushort code = ch.unicode();
    return isValidLeadingEnvCharacter(ch) || ('0' <= code && code <= '9');
}

bool ShellCommand::isValidLeadingEnvCharacter(const QChar &ch)
{
    const ushort code = ch.unicode();
    return (code == '_') || ('A' <= code && code <= 'Z');
}

/*
 * expandEnv
 *
 * Expand environment variables in text. Escaped '$' characters are ignored.
 * Return true if any variables were expanded
 */
bool ShellCommand::expandEnv(QString &text)
{
    const QLatin1Char dollarChar('$');
    const QLatin1Char backslashChar('\\');

    int dollarPos = 0;
    bool expanded = false;

    // find and expand all environment variables beginning with '$'
    while ((dollarPos = text.indexOf(dollarChar, dollarPos)) != -1) {
        // if '$' is the last character, there is no way of expanding
        if (dollarPos == text.length() - 1) {
            break;
        }

        // skip escaped '$'
        if (dollarPos > 0 && text.at(dollarPos - 1) == backslashChar) {
            dollarPos++;
            continue;
        }

        // if '$' is followed by an invalid leading character, skip this '$'
        if (!isValidLeadingEnvCharacter(text.at(dollarPos + 1))) {
            dollarPos++;
            continue;
        }

        int endPos = dollarPos + 1;
        Q_ASSERT(endPos < text.length());
        while (endPos < text.length() && isValidEnvCharacter(text.at(endPos))) {
            endPos++;
        }

        const int len = endPos - dollarPos;
        const QString key = text.mid(dollarPos + 1, len - 1);
        const QString value = QString::fromLocal8Bit(qgetenv(key.toLocal8Bit().constData()));

        if (!value.isEmpty()) {
            text.replace(dollarPos, len, value);
            expanded = true;
            dollarPos = dollarPos + value.length();
        } else {
            dollarPos = endPos;
        }
    }

    return expanded;
}