File indexing completed on 2025-01-19 04:23:30
0001 /* 0002 SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 // Own 0007 #include "ShellCommand.h" 0008 0009 // some versions of gcc(4.3) require explicit include 0010 #include <cstdlib> 0011 0012 // Qt 0013 #include <QDir> 0014 0015 using Konsole::ShellCommand; 0016 0017 ShellCommand::ShellCommand(const QString &fullCommand) 0018 { 0019 bool inQuotes = false; 0020 0021 QString builder; 0022 0023 for ( int i = 0 ; i < fullCommand.count() ; i++ ) { 0024 QChar ch = fullCommand[i]; 0025 0026 const bool isLastChar = ( i == fullCommand.count() - 1 ); 0027 const bool isQuote = ( ch == QLatin1Char('\'') || ch == QLatin1Char('\"') ); 0028 0029 if ( !isLastChar && isQuote ) { 0030 inQuotes = !inQuotes; 0031 } else { 0032 if ( (!ch.isSpace() || inQuotes) && !isQuote ) { 0033 builder.append(ch); 0034 } 0035 0036 if ( (ch.isSpace() && !inQuotes) || ( i == fullCommand.count()-1 ) ) { 0037 _arguments << builder; 0038 builder.clear(); 0039 } 0040 } 0041 } 0042 } 0043 0044 ShellCommand::ShellCommand(const QString &aCommand, const QStringList &aArguments) 0045 { 0046 _arguments = aArguments; 0047 0048 if (!_arguments.isEmpty()) { 0049 _arguments[0] = aCommand; 0050 } 0051 } 0052 0053 QString ShellCommand::fullCommand() const 0054 { 0055 QStringList quotedArgs(_arguments); 0056 for (int i = 0; i < quotedArgs.count(); i++) { 0057 QString arg = quotedArgs.at(i); 0058 bool hasSpace = false; 0059 for (int j = 0; j < arg.count(); j++) { 0060 if (arg[j].isSpace()) { 0061 hasSpace = true; 0062 } 0063 } 0064 if (hasSpace) { 0065 quotedArgs[i] = QLatin1Char('\"') + arg + QLatin1Char('\"'); 0066 } 0067 } 0068 return quotedArgs.join(QLatin1Char(' ')); 0069 } 0070 0071 QString ShellCommand::command() const 0072 { 0073 if (!_arguments.isEmpty()) { 0074 return _arguments[0]; 0075 } 0076 return QString(); 0077 } 0078 0079 QStringList ShellCommand::arguments() const 0080 { 0081 return _arguments; 0082 } 0083 0084 QStringList ShellCommand::expand(const QStringList &items) 0085 { 0086 QStringList result; 0087 result.reserve(items.size()); 0088 0089 for (const QString &item : items) { 0090 result << expand(item); 0091 } 0092 0093 return result; 0094 } 0095 0096 QString ShellCommand::expand(const QString &text) 0097 { 0098 QString result = text; 0099 expandEnv(result); 0100 return result; 0101 } 0102 0103 bool ShellCommand::isValidEnvCharacter(const QChar &ch) 0104 { 0105 const ushort code = ch.unicode(); 0106 return isValidLeadingEnvCharacter(ch) || ('0' <= code && code <= '9'); 0107 } 0108 0109 bool ShellCommand::isValidLeadingEnvCharacter(const QChar &ch) 0110 { 0111 const ushort code = ch.unicode(); 0112 return (code == '_') || ('A' <= code && code <= 'Z'); 0113 } 0114 0115 /* 0116 * expandEnv 0117 * 0118 * Expand environment variables in text. Escaped '$' characters are ignored. 0119 * Return true if any variables were expanded 0120 */ 0121 bool ShellCommand::expandEnv(QString &text) 0122 { 0123 // Current path 0124 if (text == "$PWD") { 0125 text = QDir::currentPath(); 0126 return true; 0127 } 0128 0129 const QLatin1Char dollarChar('$'); 0130 const QLatin1Char backslashChar('\\'); 0131 0132 int dollarPos = 0; 0133 bool expanded = false; 0134 0135 // find and expand all environment variables beginning with '$' 0136 while ((dollarPos = text.indexOf(dollarChar, dollarPos)) != -1) { 0137 // if '$' is the last character, there is no way of expanding 0138 if (dollarPos == text.length() - 1) { 0139 break; 0140 } 0141 0142 // skip escaped '$' 0143 if (dollarPos > 0 && text.at(dollarPos - 1) == backslashChar) { 0144 dollarPos++; 0145 continue; 0146 } 0147 0148 // if '$' is followed by an invalid leading character, skip this '$' 0149 if (!isValidLeadingEnvCharacter(text.at(dollarPos + 1))) { 0150 dollarPos++; 0151 continue; 0152 } 0153 0154 int endPos = dollarPos + 1; 0155 Q_ASSERT(endPos < text.length()); 0156 while (endPos < text.length() && isValidEnvCharacter(text.at(endPos))) { 0157 endPos++; 0158 } 0159 0160 const int len = endPos - dollarPos; 0161 const QString key = text.mid(dollarPos + 1, len - 1); 0162 const QString value = QString::fromLocal8Bit(qgetenv(key.toLocal8Bit().constData())); 0163 0164 if (!value.isEmpty()) { 0165 text.replace(dollarPos, len, value); 0166 expanded = true; 0167 dollarPos = dollarPos + value.length(); 0168 } else { 0169 dollarPos = endPos; 0170 } 0171 } 0172 0173 return expanded; 0174 }