kdecore Library API Documentation

kshell.cpp

00001 /* 00002 This file is part of the KDE libraries 00003 00004 Copyright (c) 2003 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., 59 Temple Place - Suite 330, 00019 Boston, MA 02111-1307, USA. 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 // before the notilde label, as a tilde does not match anyway 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 }; // 0-32 \'"$`<>|;&(){}*?# 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; // well, QString::empty, in fact. qt sucks ;) 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 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 10 18:54:56 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003