KDECore
kshell_unix.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of the KDE libraries 00003 00004 Copyright (c) 2003,2007 Oswald Buddenhagen <ossi@kde.org> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License as published by the Free Software Foundation; either 00009 version 2 of the License, or (at your option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 Library General Public License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to 00018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #include "kshell.h" 00023 #include "kshell_p.h" 00024 00025 #include <kuser.h> 00026 00027 #include <QtCore/QChar> 00028 #include <QtCore/QStringList> 00029 00030 static int fromHex( QChar cUnicode ) 00031 { 00032 char c = cUnicode.toAscii (); 00033 00034 if (c >= '0' && c <= '9') 00035 return c - '0'; 00036 else if (c >= 'A' && c <= 'F') 00037 return c - 'A' + 10; 00038 else if (c >= 'a' && c <= 'f') 00039 return c - 'a' + 10; 00040 return -1; 00041 } 00042 00043 inline static bool isQuoteMeta( QChar cUnicode ) 00044 { 00045 #if 0 // it's not worth it, especially after seeing gcc's asm output ... 00046 static const uchar iqm[] = { 00047 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 00048 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00 00049 }; // \'"$ 00050 00051 return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))); 00052 #else 00053 char c = cUnicode.toAscii(); 00054 return c == '\\' || c == '\'' || c == '"' || c == '$'; 00055 #endif 00056 } 00057 00058 inline static bool isMeta( QChar cUnicode ) 00059 { 00060 static const uchar iqm[] = { 00061 0x00, 0x00, 0x00, 0x00, 0xdc, 0x07, 0x00, 0xd8, 00062 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x38 00063 }; // \'"$`<>|;&(){}*?#[] 00064 00065 uint c = cUnicode.unicode(); 00066 00067 return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))); 00068 } 00069 00070 QStringList KShell::splitArgs( const QString &args, Options flags, Errors *err) 00071 { 00072 QStringList ret; 00073 bool firstword = flags & AbortOnMeta; 00074 00075 for (int pos = 0; ; ) { 00076 QChar c; 00077 do { 00078 if (pos >= args.length()) 00079 goto okret; 00080 c = args.unicode()[pos++]; 00081 } while (c.isSpace()); 00082 QString cret; 00083 if ((flags & TildeExpand) && c == QLatin1Char('~')) { 00084 int opos = pos; 00085 for (; ; pos++) { 00086 if (pos >= args.length()) 00087 break; 00088 c = args.unicode()[pos]; 00089 if (c == QLatin1Char('/') || c.isSpace()) 00090 break; 00091 if (isQuoteMeta( c )) { 00092 pos = opos; 00093 c = QLatin1Char('~'); 00094 goto notilde; 00095 } 00096 if ((flags & AbortOnMeta) && isMeta( c )) 00097 goto metaerr; 00098 } 00099 QString ccret = homeDir( args.mid(opos, pos-opos) ); 00100 if (ccret.isEmpty()) { 00101 pos = opos; 00102 c = QLatin1Char('~'); 00103 goto notilde; 00104 } 00105 if (pos >= args.length()) { 00106 ret += ccret; 00107 goto okret; 00108 } 00109 pos++; 00110 if (c.isSpace()) { 00111 ret += ccret; 00112 firstword = false; 00113 continue; 00114 } 00115 cret = ccret; 00116 } 00117 // before the notilde label, as a tilde does not match anyway 00118 if (firstword) { 00119 if (c == QLatin1Char('_') || 00120 (c >= QLatin1Char('A') && c <= QLatin1Char('Z')) || 00121 (c >= QLatin1Char('a') && c <= QLatin1Char('z'))) 00122 { 00123 int pos2 = pos; 00124 QChar cc; 00125 do { 00126 if (pos2 >= args.length()) { 00127 // Exactly one word 00128 ret += args.mid(pos - 1); 00129 goto okret; 00130 } 00131 cc = args.unicode()[pos2++]; 00132 } while (cc == QLatin1Char('_') || 00133 (cc >= QLatin1Char('A') && cc <= QLatin1Char('Z')) || 00134 (cc >= QLatin1Char('a') && cc <= QLatin1Char('z')) || 00135 (cc >= QLatin1Char('0') && cc <= QLatin1Char('9'))); 00136 if (cc == QLatin1Char('=')) 00137 goto metaerr; 00138 } 00139 } 00140 notilde: 00141 do { 00142 if (c == QLatin1Char('\'')) { 00143 int spos = pos; 00144 do { 00145 if (pos >= args.length()) 00146 goto quoteerr; 00147 c = args.unicode()[pos++]; 00148 } while (c != QLatin1Char('\'')); 00149 cret += args.mid(spos, pos-spos-1); 00150 } else if (c == QLatin1Char('"')) { 00151 for (;;) { 00152 if (pos >= args.length()) 00153 goto quoteerr; 00154 c = args.unicode()[pos++]; 00155 if (c == QLatin1Char('"')) 00156 break; 00157 if (c == QLatin1Char('\\')) { 00158 if (pos >= args.length()) 00159 goto quoteerr; 00160 c = args.unicode()[pos++]; 00161 if (c != QLatin1Char('"') && 00162 c != QLatin1Char('\\') && 00163 !((flags & AbortOnMeta) && 00164 (c == QLatin1Char('$') || 00165 c == QLatin1Char('`')))) 00166 cret += QLatin1Char('\\'); 00167 } else if ((flags & AbortOnMeta) && 00168 (c == QLatin1Char('$') || 00169 c == QLatin1Char('`'))) 00170 goto metaerr; 00171 cret += c; 00172 } 00173 } else if (c == QLatin1Char('$') && pos < args.length() && 00174 args.unicode()[pos] == QLatin1Char('\'')) { 00175 pos++; 00176 for (;;) { 00177 if (pos >= args.length()) 00178 goto quoteerr; 00179 c = args.unicode()[pos++]; 00180 if (c == QLatin1Char('\'')) 00181 break; 00182 if (c == QLatin1Char('\\')) { 00183 if (pos >= args.length()) 00184 goto quoteerr; 00185 c = args.unicode()[pos++]; 00186 switch (c.toAscii()) { 00187 case 'a': cret += QLatin1Char('\a'); break; 00188 case 'b': cret += QLatin1Char('\b'); break; 00189 case 'e': cret += QLatin1Char('\033'); break; 00190 case 'f': cret += QLatin1Char('\f'); break; 00191 case 'n': cret += QLatin1Char('\n'); break; 00192 case 'r': cret += QLatin1Char('\r'); break; 00193 case 't': cret += QLatin1Char('\t'); break; 00194 case '\\': cret += QLatin1Char('\\'); break; 00195 case '\'': cret += QLatin1Char('\''); break; 00196 case 'c': 00197 if (pos >= args.length()) 00198 goto quoteerr; 00199 cret += args.unicode()[pos++].toAscii() & 31; 00200 break; 00201 case 'x': 00202 { 00203 if (pos >= args.length()) 00204 goto quoteerr; 00205 int hv = fromHex( args.unicode()[pos++] ); 00206 if (hv < 0) 00207 goto quoteerr; 00208 if (pos < args.length()) { 00209 int hhv = fromHex( args.unicode()[pos] ); 00210 if (hhv > 0) { 00211 hv = hv * 16 + hhv; 00212 pos++; 00213 } 00214 cret += QChar( hv ); 00215 } 00216 break; 00217 } 00218 default: 00219 if (c.toAscii() >= '0' && c.toAscii() <= '7') { 00220 char cAscii = c.toAscii(); 00221 int hv = cAscii - '0'; 00222 for (int i = 0; i < 2; i++) { 00223 if (pos >= args.length()) 00224 break; 00225 c = args.unicode()[pos]; 00226 if (c.toAscii() < '0' || c.toAscii() > '7') 00227 break; 00228 hv = hv * 8 + (c.toAscii() - '0'); 00229 pos++; 00230 } 00231 cret += QChar( hv ); 00232 } else { 00233 cret += QLatin1Char('\\'); 00234 cret += c; 00235 } 00236 break; 00237 } 00238 } else 00239 cret += c; 00240 } 00241 } else { 00242 if (c == QLatin1Char('\\')) { 00243 if (pos >= args.length()) 00244 goto quoteerr; 00245 c = args.unicode()[pos++]; 00246 } else if ((flags & AbortOnMeta) && isMeta( c )) 00247 goto metaerr; 00248 cret += c; 00249 } 00250 if (pos >= args.length()) 00251 break; 00252 c = args.unicode()[pos++]; 00253 } while (!c.isSpace()); 00254 ret += cret; 00255 firstword = false; 00256 } 00257 00258 okret: 00259 if (err) 00260 *err = NoError; 00261 return ret; 00262 00263 quoteerr: 00264 if (err) 00265 *err = BadQuoting; 00266 return QStringList(); 00267 00268 metaerr: 00269 if (err) 00270 *err = FoundMeta; 00271 return QStringList(); 00272 } 00273 00274 inline static bool isSpecial( QChar cUnicode ) 00275 { 00276 static const uchar iqm[] = { 00277 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8, 00278 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78 00279 }; // 0-32 \'"$`<>|;&(){}*?#!~[] 00280 00281 uint c = cUnicode.unicode (); 00282 return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))); 00283 } 00284 00285 QString KShell::quoteArg( const QString &arg ) 00286 { 00287 if (!arg.length()) 00288 return QString::fromLatin1("''"); 00289 for (int i = 0; i < arg.length(); i++) 00290 if (isSpecial( arg.unicode()[i] )) { 00291 QChar q( QLatin1Char('\'') ); 00292 return QString( arg ).replace( q, QLatin1String("'\\''") ).prepend( q ).append( q ); 00293 } 00294 return arg; 00295 }
KDE 4.6 API Reference