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 if (++pos2 >= args.length()) {
00127
00128 ret += args.mid(pos);
00129 goto okret;
00130 }
00131 cc = args[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('$') && args[pos] == QLatin1Char('\'')) {
00174 pos++;
00175 for (;;) {
00176 if (pos >= args.length())
00177 goto quoteerr;
00178 c = args.unicode()[pos++];
00179 if (c == QLatin1Char('\''))
00180 break;
00181 if (c == QLatin1Char('\\')) {
00182 if (pos >= args.length())
00183 goto quoteerr;
00184 c = args.unicode()[pos++];
00185 switch (c.toAscii()) {
00186 case 'a': cret += QLatin1Char('\a'); break;
00187 case 'b': cret += QLatin1Char('\b'); break;
00188 case 'e': cret += QLatin1Char('\033'); break;
00189 case 'f': cret += QLatin1Char('\f'); break;
00190 case 'n': cret += QLatin1Char('\n'); break;
00191 case 'r': cret += QLatin1Char('\r'); break;
00192 case 't': cret += QLatin1Char('\t'); break;
00193 case '\\': cret += QLatin1Char('\\'); break;
00194 case '\'': cret += QLatin1Char('\''); break;
00195 case 'c': cret += args[pos++].toAscii() & 31; break;
00196 case 'x':
00197 {
00198 int hv = fromHex( args[pos] );
00199 if (hv < 0) {
00200 cret += QLatin1String("\\x");
00201 } else {
00202 int hhv = fromHex( args[++pos] );
00203 if (hhv > 0) {
00204 hv = hv * 16 + hhv;
00205 pos++;
00206 }
00207 cret += QChar( hv );
00208 }
00209 break;
00210 }
00211 default:
00212 if (c.toAscii() >= '0' && c.toAscii() <= '7') {
00213 char cAscii = c.toAscii();
00214 int hv = cAscii - '0';
00215 for (int i = 0; i < 2; i++) {
00216 c = args[pos];
00217 if (c.toAscii() < '0' || c.toAscii() > '7')
00218 break;
00219 hv = hv * 8 + (c.toAscii() - '0');
00220 pos++;
00221 }
00222 cret += QChar( hv );
00223 } else {
00224 cret += QLatin1Char('\\');
00225 cret += c;
00226 }
00227 break;
00228 }
00229 } else
00230 cret += c;
00231 }
00232 } else {
00233 if (c == QLatin1Char('\\')) {
00234 if (pos >= args.length())
00235 goto quoteerr;
00236 c = args.unicode()[pos++];
00237 } else if ((flags & AbortOnMeta) && isMeta( c ))
00238 goto metaerr;
00239 cret += c;
00240 }
00241 if (pos >= args.length())
00242 break;
00243 c = args.unicode()[pos++];
00244 } while (!c.isSpace());
00245 ret += cret;
00246 firstword = false;
00247 }
00248
00249 okret:
00250 if (err)
00251 *err = NoError;
00252 return ret;
00253
00254 quoteerr:
00255 if (err)
00256 *err = BadQuoting;
00257 return QStringList();
00258
00259 metaerr:
00260 if (err)
00261 *err = FoundMeta;
00262 return QStringList();
00263 }
00264
00265 inline static bool isSpecial( QChar cUnicode )
00266 {
00267 static const uchar iqm[] = {
00268 0xff, 0xff, 0xff, 0xff, 0xdd, 0x07, 0x00, 0xd8,
00269 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x38
00270 };
00271
00272 uint c = cUnicode.unicode ();
00273 return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
00274 }
00275
00276 QString KShell::quoteArg( const QString &arg )
00277 {
00278 if (!arg.length())
00279 return QString::fromLatin1("''");
00280 for (int i = 0; i < arg.length(); i++)
00281 if (isSpecial( arg.unicode()[i] )) {
00282 QChar q( QLatin1Char('\'') );
00283 return QString( arg ).replace( q, QLatin1String("'\\''") ).prepend( q ).append( q );
00284 }
00285 return arg;
00286 }