• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDECore

kshell.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, 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 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal