kdecore Library: kshell.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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 }

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:10 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003