00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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, 0x10, 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
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 cc = args[pos2++];
00127 while (cc == QLatin1Char('_') ||
00128 (cc >= QLatin1Char('A') && cc <= QLatin1Char('Z')) ||
00129 (cc >= QLatin1Char('a') && cc <= QLatin1Char('z')) ||
00130 (cc >= QLatin1Char('0') && cc <= QLatin1Char('9')));
00131 if (cc == QLatin1Char('='))
00132 goto metaerr;
00133 }
00134 }
00135 notilde:
00136 do {
00137 if (c == QLatin1Char('\'')) {
00138 int spos = pos;
00139 do {
00140 if (pos >= args.length())
00141 goto quoteerr;
00142 c = args.unicode()[pos++];
00143 } while (c != QLatin1Char('\''));
00144 cret += args.mid(spos, pos-spos-1);
00145 } else if (c == QLatin1Char('"')) {
00146 for (;;) {
00147 if (pos >= args.length())
00148 goto quoteerr;
00149 c = args.unicode()[pos++];
00150 if (c == QLatin1Char('"'))
00151 break;
00152 if (c == QLatin1Char('\\')) {
00153 if (pos >= args.length())
00154 goto quoteerr;
00155 c = args.unicode()[pos++];
00156 if (c != QLatin1Char('"') &&
00157 c != QLatin1Char('\\') &&
00158 !((flags & AbortOnMeta) &&
00159 (c == QLatin1Char('$') ||
00160 c == QLatin1Char('`'))))
00161 cret += QLatin1Char('\\');
00162 } else if ((flags & AbortOnMeta) &&
00163 (c == QLatin1Char('$') ||
00164 c == QLatin1Char('`')))
00165 goto metaerr;
00166 cret += c;
00167 }
00168 } else if (c == QLatin1Char('$') && args[pos] == QLatin1Char('\'')) {
00169 pos++;
00170 for (;;) {
00171 if (pos >= args.length())
00172 goto quoteerr;
00173 c = args.unicode()[pos++];
00174 if (c == QLatin1Char('\''))
00175 break;
00176 if (c == QLatin1Char('\\')) {
00177 if (pos >= args.length())
00178 goto quoteerr;
00179 c = args.unicode()[pos++];
00180 switch (c.toAscii()) {
00181 case 'a': cret += QLatin1Char('\a'); break;
00182 case 'b': cret += QLatin1Char('\b'); break;
00183 case 'e': cret += QLatin1Char('\033'); break;
00184 case 'f': cret += QLatin1Char('\f'); break;
00185 case 'n': cret += QLatin1Char('\n'); break;
00186 case 'r': cret += QLatin1Char('\r'); break;
00187 case 't': cret += QLatin1Char('\t'); break;
00188 case '\\': cret += QLatin1Char('\\'); break;
00189 case '\'': cret += QLatin1Char('\''); break;
00190 case 'c': cret += args[pos++].toAscii() & 31; break;
00191 case 'x':
00192 {
00193 int hv = fromHex( args[pos] );
00194 if (hv < 0) {
00195 cret += QLatin1String("\\x");
00196 } else {
00197 int hhv = fromHex( args[++pos] );
00198 if (hhv > 0) {
00199 hv = hv * 16 + hhv;
00200 pos++;
00201 }
00202 cret += QChar( hv );
00203 }
00204 break;
00205 }
00206 default:
00207 if (c.toAscii() >= '0' && c.toAscii() <= '7') {
00208 char cAscii = c.toAscii();
00209 int hv = cAscii - '0';
00210 for (int i = 0; i < 2; i++) {
00211 c = args[pos];
00212 if (c.toAscii() < '0' || c.toAscii() > '7')
00213 break;
00214 hv = hv * 8 + (c.toAscii() - '0');
00215 pos++;
00216 }
00217 cret += QChar( hv );
00218 } else {
00219 cret += QLatin1Char('\\');
00220 cret += c;
00221 }
00222 break;
00223 }
00224 } else
00225 cret += c;
00226 }
00227 } else {
00228 if (c == QLatin1Char('\\')) {
00229 if (pos >= args.length())
00230 goto quoteerr;
00231 c = args.unicode()[pos++];
00232 } else if ((flags & AbortOnMeta) && isMeta( c ))
00233 goto metaerr;
00234 cret += c;
00235 }
00236 if (pos >= args.length())
00237 break;
00238 c = args.unicode()[pos++];
00239 } while (!c.isSpace());
00240 ret += cret;
00241 firstword = false;
00242 }
00243
00244 okret:
00245 if (err)
00246 *err = NoError;
00247 return ret;
00248
00249 quoteerr:
00250 if (err)
00251 *err = BadQuoting;
00252 return QStringList();
00253
00254 metaerr:
00255 if (err)
00256 *err = FoundMeta;
00257 return QStringList();
00258 }
00259
00260 inline static bool isSpecial( QChar cUnicode )
00261 {
00262 static const uchar iqm[] = {
00263 0xff, 0xff, 0xff, 0xff, 0xdd, 0x07, 0x00, 0xd8,
00264 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x38
00265 };
00266
00267 uint c = cUnicode.unicode ();
00268 return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
00269 }
00270
00271 QString KShell::quoteArg( const QString &arg )
00272 {
00273 if (!arg.length())
00274 return QString::fromLatin1("''");
00275 for (int i = 0; i < arg.length(); i++)
00276 if (isSpecial( arg.unicode()[i] )) {
00277 QChar q( QLatin1Char('\'') );
00278 return QString( arg ).replace( q, QLatin1String("'\\''") ).prepend( q ).append( q );
00279 }
00280 return arg;
00281 }