KDECore
kmacroexpander_unix.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of the KDE libraries 00003 00004 Copyright (c) 2002-2003 Oswald Buddenhagen <ossi@kde.org> 00005 Copyright (c) 2003 Waldo Bastian <bastian@kde.org> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #include "kmacroexpander_p.h" 00024 00025 #include "kshell.h" 00026 00027 #include <QtCore/QStringList> 00028 #include <QtCore/QStack> 00029 #include <QtCore/QRegExp> 00030 00031 namespace KMacroExpander { 00032 00033 enum Quoting { noquote, singlequote, doublequote, dollarquote, 00034 paren, subst, group, math }; 00035 typedef struct { 00036 Quoting current; 00037 bool dquote; 00038 } State; 00039 typedef struct { 00040 QString str; 00041 int pos; 00042 } Save; 00043 00044 } 00045 00046 using namespace KMacroExpander; 00047 00048 bool KMacroExpanderBase::expandMacrosShellQuote( QString &str, int &pos ) 00049 { 00050 int len; 00051 int pos2; 00052 ushort ec = d->escapechar.unicode(); 00053 State state = { noquote, false }; 00054 QStack<State> sstack; 00055 QStack<Save> ostack; 00056 QStringList rst; 00057 QString rsts; 00058 00059 while (pos < str.length()) { 00060 ushort cc = str.unicode()[pos].unicode(); 00061 if (ec != 0) { 00062 if (cc != ec) 00063 goto nohit; 00064 if (!(len = expandEscapedMacro( str, pos, rst ))) 00065 goto nohit; 00066 } else { 00067 if (!(len = expandPlainMacro( str, pos, rst ))) 00068 goto nohit; 00069 } 00070 if (len < 0) { 00071 pos -= len; 00072 continue; 00073 } 00074 if (state.dquote) { 00075 rsts = rst.join( QLatin1String(" ") ); 00076 rsts.replace( QRegExp(QLatin1String("([$`\"\\\\])")), QLatin1String("\\\\1") ); 00077 } else if (state.current == dollarquote) { 00078 rsts = rst.join( QLatin1String(" ") ); 00079 rsts.replace( QRegExp(QLatin1String("(['\\\\])")), QLatin1String("\\\\1") ); 00080 } else if (state.current == singlequote) { 00081 rsts = rst.join( QLatin1String(" ") ); 00082 rsts.replace( QLatin1Char('\''), QLatin1String("'\\''") ); 00083 } else { 00084 if (rst.isEmpty()) { 00085 str.remove( pos, len ); 00086 continue; 00087 } else { 00088 rsts = KShell::joinArgs( rst ); 00089 } 00090 } 00091 rst.clear(); 00092 str.replace( pos, len, rsts ); 00093 pos += rsts.length(); 00094 continue; 00095 nohit: 00096 if (state.current == singlequote) { 00097 if (cc == '\'') 00098 state = sstack.pop(); 00099 } else if (cc == '\\') { 00100 // always swallow the char -> prevent anomalies due to expansion 00101 pos += 2; 00102 continue; 00103 } else if (state.current == dollarquote) { 00104 if (cc == '\'') 00105 state = sstack.pop(); 00106 } else if (cc == '$') { 00107 cc = str.unicode()[++pos].unicode(); 00108 if (cc == '(') { 00109 sstack.push( state ); 00110 if (str.unicode()[pos + 1].unicode() == '(') { 00111 Save sav = { str, pos + 2 }; 00112 ostack.push( sav ); 00113 state.current = math; 00114 pos += 2; 00115 continue; 00116 } else { 00117 state.current = paren; 00118 state.dquote = false; 00119 } 00120 } else if (cc == '{') { 00121 sstack.push( state ); 00122 state.current = subst; 00123 } else if (!state.dquote) { 00124 if (cc == '\'') { 00125 sstack.push( state ); 00126 state.current = dollarquote; 00127 } else if (cc == '"') { 00128 sstack.push( state ); 00129 state.current = doublequote; 00130 state.dquote = true; 00131 } 00132 } 00133 // always swallow the char -> prevent anomalies due to expansion 00134 } else if (cc == '`') { 00135 str.replace( pos, 1, QLatin1String("$( " )); // add space -> avoid creating $(( 00136 pos2 = pos += 3; 00137 for (;;) { 00138 if (pos2 >= str.length()) { 00139 pos = pos2; 00140 return false; 00141 } 00142 cc = str.unicode()[pos2].unicode(); 00143 if (cc == '`') 00144 break; 00145 if (cc == '\\') { 00146 cc = str.unicode()[++pos2].unicode(); 00147 if (cc == '$' || cc == '`' || cc == '\\' || 00148 (cc == '"' && state.dquote)) 00149 { 00150 str.remove( pos2 - 1, 1 ); 00151 continue; 00152 } 00153 } 00154 pos2++; 00155 } 00156 str[pos2] = QLatin1Char(')'); 00157 sstack.push( state ); 00158 state.current = paren; 00159 state.dquote = false; 00160 continue; 00161 } else if (state.current == doublequote) { 00162 if (cc == '"') 00163 state = sstack.pop(); 00164 } else if (cc == '\'') { 00165 if (!state.dquote) { 00166 sstack.push( state ); 00167 state.current = singlequote; 00168 } 00169 } else if (cc == '"') { 00170 if (!state.dquote) { 00171 sstack.push( state ); 00172 state.current = doublequote; 00173 state.dquote = true; 00174 } 00175 } else if (state.current == subst) { 00176 if (cc == '}') 00177 state = sstack.pop(); 00178 } else if (cc == ')') { 00179 if (state.current == math) { 00180 if (str.unicode()[pos + 1].unicode() == ')') { 00181 state = sstack.pop(); 00182 pos += 2; 00183 } else { 00184 // false hit: the $(( was a $( ( in fact 00185 // ash does not care, but bash does 00186 pos = ostack.top().pos; 00187 str = ostack.top().str; 00188 ostack.pop(); 00189 state.current = paren; 00190 state.dquote = false; 00191 sstack.push( state ); 00192 } 00193 continue; 00194 } else if (state.current == paren) 00195 state = sstack.pop(); 00196 else 00197 break; 00198 } else if (cc == '}') { 00199 if (state.current == KMacroExpander::group) 00200 state = sstack.pop(); 00201 else 00202 break; 00203 } else if (cc == '(') { 00204 sstack.push( state ); 00205 state.current = paren; 00206 } else if (cc == '{') { 00207 sstack.push( state ); 00208 state.current = KMacroExpander::group; 00209 } 00210 pos++; 00211 } 00212 return sstack.empty(); 00213 }
KDE 4.6 API Reference