1 /*
2     Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
3 
4     Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19     02110-1301  USA.
20 */
21 
22 // Own
23 #include "ShellCommand.h"
24 
25 //some versions of gcc(4.3) require explicit include
26 #include <cstdlib>
27 
28 
29 using namespace Konsole;
30 
31 // expands environment variables in 'text'
32 // function copied from kdelibs/kio/kio/kurlcompletion.cpp
33 static bool expandEnv(QString & text);
34 
ShellCommand(const QString & fullCommand)35 ShellCommand::ShellCommand(const QString & fullCommand)
36 {
37     bool inQuotes = false;
38 
39     QString builder;
40 
41     for ( int i = 0 ; i < fullCommand.count() ; i++ ) {
42         QChar ch = fullCommand[i];
43 
44         const bool isLastChar = ( i == fullCommand.count() - 1 );
45         const bool isQuote = ( ch == QLatin1Char('\'') || ch == QLatin1Char('\"') );
46 
47         if ( !isLastChar && isQuote ) {
48             inQuotes = !inQuotes;
49         } else {
50             if ( (!ch.isSpace() || inQuotes) && !isQuote ) {
51                 builder.append(ch);
52             }
53 
54             if ( (ch.isSpace() && !inQuotes) || ( i == fullCommand.count()-1 ) ) {
55                 _arguments << builder;
56                 builder.clear();
57             }
58         }
59     }
60 }
ShellCommand(const QString & command,const QStringList & arguments)61 ShellCommand::ShellCommand(const QString & command , const QStringList & arguments)
62 {
63     _arguments = arguments;
64 
65     if ( !_arguments.isEmpty() ) {
66         _arguments[0] = command;
67     }
68 }
fullCommand() const69 QString ShellCommand::fullCommand() const
70 {
71     return _arguments.join(QLatin1Char(' '));
72 }
command() const73 QString ShellCommand::command() const
74 {
75     if ( !_arguments.isEmpty() ) {
76         return _arguments[0];
77     } else {
78         return QString();
79     }
80 }
arguments() const81 QStringList ShellCommand::arguments() const
82 {
83     return _arguments;
84 }
isRootCommand() const85 bool ShellCommand::isRootCommand() const
86 {
87     Q_ASSERT(0); // not implemented yet
88     return false;
89 }
isAvailable() const90 bool ShellCommand::isAvailable() const
91 {
92     Q_ASSERT(0); // not implemented yet
93     return false;
94 }
expand(const QStringList & items)95 QStringList ShellCommand::expand(const QStringList & items)
96 {
97     QStringList result;
98 
99     for(const QString &item : items) {
100         result << expand(item);
101     }
102 
103     return result;
104 }
expand(const QString & text)105 QString ShellCommand::expand(const QString & text)
106 {
107     QString result = text;
108     expandEnv(result);
109     return result;
110 }
111 
112 /*
113  * expandEnv
114  *
115  * Expand environment variables in text. Escaped '$' characters are ignored.
116  * Return true if any variables were expanded
117  */
expandEnv(QString & text)118 static bool expandEnv( QString & text )
119 {
120     // Find all environment variables beginning with '$'
121     //
122     int pos = 0;
123 
124     bool expanded = false;
125 
126     while ( (pos = text.indexOf(QLatin1Char('$'), pos)) != -1 ) {
127 
128         // Skip escaped '$'
129         //
130         if ( pos > 0 && text.at(pos-1) == QLatin1Char('\\') ) {
131             pos++;
132         }
133         // Variable found => expand
134         //
135         else {
136             // Find the end of the variable = next '/' or ' '
137             //
138             int pos2 = text.indexOf( QLatin1Char(' '), pos+1 );
139             int pos_tmp = text.indexOf( QLatin1Char('/'), pos+1 );
140 
141             if ( pos2 == -1 || (pos_tmp != -1 && pos_tmp < pos2) ) {
142                 pos2 = pos_tmp;
143             }
144 
145             if ( pos2 == -1 ) {
146                 pos2 = text.length();
147             }
148 
149             // Replace if the variable is terminated by '/' or ' '
150             // and defined
151             //
152             if ( pos2 >= 0 ) {
153                 int len = pos2 - pos;
154                 QString key = text.mid( pos+1, len-1);
155                 QString value =
156                     QString::fromLocal8Bit( qgetenv(key.toLocal8Bit().constData()) );
157 
158                 if ( !value.isEmpty() ) {
159                     expanded = true;
160                     text.replace( pos, len, value );
161                     pos = pos + value.length();
162                 } else {
163                     pos = pos2;
164                 }
165             }
166         }
167     }
168 
169     return expanded;
170 }
171