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
00024
#include <qfile.h>
00025
00026
#include <stdlib.h>
00027
#include <pwd.h>
00028
#include <sys/types.h>
00029
00030
static int fromHex(
QChar c )
00031 {
00032
if (c >=
'0' && c <=
'9')
00033
return c -
'0';
00034
else if (c >=
'A' && c <=
'F')
00035
return c -
'A' + 10;
00036
else if (c >=
'a' && c <=
'f')
00037
return c -
'a' + 10;
00038
return -1;
00039 }
00040
00041
inline static bool isQuoteMeta( uint c )
00042 {
00043
#if 0 // it's not worth it, especially after seeing gcc's asm output ...
00044
static const uchar iqm[] = {
00045 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00,
00046 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00
00047 };
00048
00049
return (c <
sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
00050
#else
00051
return c ==
'\\' || c ==
'\'' || c ==
'"' || c ==
'$';
00052
#endif
00053
}
00054
00055
inline static bool isMeta( uint c )
00056 {
00057
static const uchar iqm[] = {
00058 0x00, 0x00, 0x00, 0x00, 0xdc, 0x07, 0x00, 0xd8,
00059 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x38
00060 };
00061
00062
return (c <
sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
00063 }
00064
00065 QStringList KShell::splitArgs(
const QString &args,
int flags,
int *err )
00066 {
00067
QStringList ret;
00068
bool firstword = flags &
AbortOnMeta;
00069
00070
for (uint pos = 0; ; ) {
00071
QChar c;
00072
do {
00073
if (pos >= args.length())
00074
goto okret;
00075 c = args.unicode()[pos++];
00076 }
while (c.isSpace());
00077
QString cret;
00078
if ((flags &
TildeExpand) && c ==
'~') {
00079 uint opos = pos;
00080
for (; ; pos++) {
00081
if (pos >= args.length())
00082
break;
00083 c = args.unicode()[pos];
00084
if (c ==
'/' || c.isSpace())
00085
break;
00086
if (isQuoteMeta( c )) {
00087 pos = opos;
00088 c =
'~';
00089
goto notilde;
00090 }
00091
if ((flags &
AbortOnMeta) && isMeta( c ))
00092
goto metaerr;
00093 }
00094
QString ccret =
homeDir(
QConstString( args.unicode() + opos, pos - opos ).string() );
00095
if (ccret.isEmpty()) {
00096 pos = opos;
00097 c =
'~';
00098
goto notilde;
00099 }
00100
if (pos >= args.length()) {
00101 ret += ccret;
00102
goto okret;
00103 }
00104 pos++;
00105
if (c.isSpace()) {
00106 ret += ccret;
00107 firstword =
false;
00108
continue;
00109 }
00110 cret = ccret;
00111 }
00112
00113
if (firstword) {
00114
if (c ==
'_' || (c >=
'A' && c <= 'Z') || (c >=
'a' && c <=
'z')) {
00115 uint pos2 = pos;
00116
QChar cc;
00117
do
00118 cc = args[pos2++];
00119
while (cc ==
'_' || (cc >=
'A' && cc <=
'Z') ||
00120 (cc >=
'a' && cc <= 'z') || (cc >=
'0' && cc <=
'9'));
00121
if (cc ==
'=')
00122
goto metaerr;
00123 }
00124 }
00125 notilde:
00126
do {
00127
if (c ==
'\'') {
00128 uint spos = pos;
00129
do {
00130
if (pos >= args.length())
00131
goto quoteerr;
00132 c = args.unicode()[pos++];
00133 }
while (c !=
'\'');
00134 cret +=
QConstString( args.unicode() + spos, pos - spos - 1 ).string();
00135 }
else if (c ==
'"') {
00136
for (;;) {
00137
if (pos >= args.length())
00138
goto quoteerr;
00139 c = args.unicode()[pos++];
00140
if (c ==
'"')
00141
break;
00142
if (c ==
'\\') {
00143
if (pos >= args.length())
00144
goto quoteerr;
00145 c = args.unicode()[pos++];
00146
if (c !=
'"' && c !=
'\\' &&
00147 !((flags &
AbortOnMeta) && (c ==
'$' || c ==
'`')))
00148 cret +=
'\\';
00149 }
else if ((flags &
AbortOnMeta) && (c ==
'$' || c ==
'`'))
00150
goto metaerr;
00151 cret += c;
00152 }
00153 }
else if (c ==
'$' && args[pos] ==
'\'') {
00154 pos++;
00155
for (;;) {
00156
if (pos >= args.length())
00157
goto quoteerr;
00158 c = args.unicode()[pos++];
00159
if (c ==
'\'')
00160
break;
00161
if (c ==
'\\') {
00162
if (pos >= args.length())
00163
goto quoteerr;
00164 c = args.unicode()[pos++];
00165
switch (c) {
00166
case 'a': cret +=
'\a';
break;
00167
case 'b': cret +=
'\b';
break;
00168
case 'e': cret +=
'\033';
break;
00169
case 'f': cret +=
'\f';
break;
00170
case 'n': cret +=
'\n';
break;
00171
case 'r': cret +=
'\r';
break;
00172
case 't': cret +=
'\t';
break;
00173
case '\\': cret +=
'\\';
break;
00174
case '\'': cret +=
'\'';
break;
00175
case 'c': cret += args[pos++] & 31;
break;
00176
case 'x':
00177 {
00178
int hv = fromHex( args[pos] );
00179
if (hv < 0) {
00180 cret +=
"\\x";
00181 }
else {
00182
int hhv = fromHex( args[++pos] );
00183
if (hhv > 0) {
00184 hv = hv * 16 + hhv;
00185 pos++;
00186 }
00187 cret +=
QChar( hv );
00188 }
00189
break;
00190 }
00191
default:
00192
if (c >=
'0' && c <=
'7') {
00193
int hv = c -
'0';
00194
for (
int i = 0; i < 2; i++) {
00195 c = args[pos];
00196
if (c < '0' || c >
'7')
00197
break;
00198 hv = hv * 8 + (c -
'0');
00199 pos++;
00200 }
00201 cret +=
QChar( hv );
00202 }
else {
00203 cret +=
'\\';
00204 cret += c;
00205 }
00206
break;
00207 }
00208 }
else
00209 cret += c;
00210 }
00211 }
else {
00212
if (c ==
'\\') {
00213
if (pos >= args.length())
00214
goto quoteerr;
00215 c = args.unicode()[pos++];
00216
if (!c.isSpace() &&
00217 !((flags &
AbortOnMeta) ? isMeta( c ) : isQuoteMeta( c )))
00218 cret +=
'\\';
00219 }
else if ((flags &
AbortOnMeta) && isMeta( c ))
00220
goto metaerr;
00221 cret += c;
00222 }
00223
if (pos >= args.length())
00224
break;
00225 c = args.unicode()[pos++];
00226 }
while (!c.isSpace());
00227 ret += cret;
00228 firstword =
false;
00229 }
00230
00231 okret:
00232
if (err)
00233 *err =
NoError;
00234
return ret;
00235
00236 quoteerr:
00237
if (err)
00238 *err =
BadQuoting;
00239
return QStringList();
00240
00241 metaerr:
00242
if (err)
00243 *err =
FoundMeta;
00244
return QStringList();
00245 }
00246
00247
inline static bool isSpecial( uint c )
00248 {
00249
static const uchar iqm[] = {
00250 0xff, 0xff, 0xff, 0xff, 0xdd, 0x07, 0x00, 0xd8,
00251 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x38
00252 };
00253
00254
return (c <
sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
00255 }
00256
00257 QString KShell::joinArgs(
const QStringList &args )
00258 {
00259
QChar q(
'\'' );
00260
QString ret;
00261
for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it) {
00262
if (!ret.isEmpty())
00263 ret +=
' ';
00264
if (!(*it).length())
00265 ret.append( q ).append( q );
00266
else {
00267
for (uint i = 0; i < (*it).length(); i++)
00268
if (isSpecial((*it).unicode()[i])) {
00269
QString tmp(*it);
00270 tmp.replace( q,
"'\\''" );
00271 ret += q;
00272 tmp += q;
00273 ret += tmp;
00274
goto ex;
00275 }
00276 ret += *it;
00277 ex: ;
00278 }
00279 }
00280
return ret;
00281 }
00282
00283 QString KShell::joinArgs(
const char *
const *args,
int nargs )
00284 {
00285
if (!args)
00286
return QString::null;
00287
QChar q(
'\'' );
00288
QString ret;
00289
for (
const char *
const *argp = args; nargs && *argp; argp++, nargs--) {
00290
if (!ret.isEmpty())
00291 ret +=
' ';
00292
if (!**argp)
00293 ret.append( q ).append( q );
00294
else {
00295
QString tmp( QFile::decodeName( *argp ) );
00296
for (uint i = 0; i < tmp.length(); i++)
00297
if (isSpecial(tmp.unicode()[i])) {
00298 tmp.replace( q,
"'\\''" );
00299 ret += q;
00300 tmp += q;
00301 ret += tmp;
00302
goto ex;
00303 }
00304 ret += tmp;
00305 ex: ;
00306 }
00307 }
00308
return ret;
00309 }
00310
00311 QString KShell::joinArgsDQ(
const QStringList &args )
00312 {
00313
QChar q(
'\'' ), sp(
' ' ), bs(
'\\' );
00314
QString ret;
00315
for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it) {
00316
if (!ret.isEmpty())
00317 ret += sp;
00318
if (!(*it).length())
00319 ret.append( q ).append( q );
00320
else {
00321
for (uint i = 0; i < (*it).length(); i++)
00322
if (isSpecial((*it).unicode()[i])) {
00323 ret.append(
'$' ).append( q );
00324
for (uint pos = 0; pos < (*it).length(); pos++) {
00325
int c = (*it).unicode()[pos];
00326
if (c < 32) {
00327 ret += bs;
00328
switch (c) {
00329
case '\a': ret +=
'a';
break;
00330
case '\b': ret +=
'b';
break;
00331
case '\033': ret +=
'e';
break;
00332
case '\f': ret +=
'f';
break;
00333
case '\n': ret +=
'n';
break;
00334
case '\r': ret +=
'r';
break;
00335
case '\t': ret +=
't';
break;
00336
case '\034': ret +=
'c'; ret +=
'|';
break;
00337
default: ret +=
'c'; ret += c +
'@';
break;
00338 }
00339 }
else {
00340
if (c ==
'\'' || c ==
'\\')
00341 ret += bs;
00342 ret += c;
00343 }
00344 }
00345 ret.append( q );
00346
goto ex;
00347 }
00348 ret += *it;
00349 ex: ;
00350 }
00351 }
00352
return ret;
00353 }
00354
00355 QString KShell::tildeExpand(
const QString &fname )
00356 {
00357
if (fname[0] ==
'~') {
00358
int pos = fname.find(
'/' );
00359
if (pos < 0)
00360
return homeDir(
QConstString( fname.unicode() + 1, fname.length() - 1 ).string() );
00361
QString ret =
homeDir(
QConstString( fname.unicode() + 1, pos - 1 ).string() );
00362
if (!ret.isNull())
00363 ret +=
QConstString( fname.unicode() + pos, fname.length() - pos ).string();
00364
return ret;
00365 }
00366
return fname;
00367 }
00368
00369 QString KShell::homeDir(
const QString &user )
00370 {
00371
if (user.isEmpty())
00372
return QFile::decodeName( getenv(
"HOME" ) );
00373
struct passwd *pw = getpwnam( QFile::encodeName( user ).data() );
00374
if (!pw)
00375
return QString::null;
00376
return QFile::decodeName( pw->pw_dir );
00377 }