kdecore Library API Documentation

kstandarddirs.cpp

00001 /* This file is part of the KDE libraries
00002    Copyright (C) 1999 Sirtaj Singh Kang <taj@kde.org>
00003    Copyright (C) 1999 Stephan Kulow <coolo@kde.org>
00004    Copyright (C) 1999 Waldo Bastian <bastian@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 version 2 as published by the Free Software Foundation.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
00019 */
00020 
00021 /*
00022  * Author: Stephan Kulow <coolo@kde.org> and Sirtaj Singh Kang <taj@kde.org>
00023  * Version: $Id: kstandarddirs.cpp,v 1.168.2.1 2004/01/20 11:18:33 ossi Exp $
00024  * Generated:   Thu Mar  5 16:05:28 EST 1998
00025  */
00026 
00027 #include "config.h"
00028 
00029 #include <stdlib.h>
00030 #include <assert.h>
00031 #include <errno.h>
00032 #ifdef HAVE_SYS_STAT_H
00033 #include <sys/stat.h>
00034 #endif
00035 #include <sys/types.h>
00036 #include <dirent.h>
00037 #include <pwd.h>
00038 
00039 #include <qregexp.h>
00040 #include <qasciidict.h>
00041 #include <qdict.h>
00042 #include <qdir.h>
00043 #include <qfileinfo.h>
00044 #include <qstring.h>
00045 #include <qstringlist.h>
00046 
00047 #include "kstandarddirs.h"
00048 #include "kconfig.h"
00049 #include "kdebug.h"
00050 #include "kinstance.h"
00051 #include "kshell.h"
00052 #include <sys/param.h>
00053 #include <unistd.h>
00054 
00055 template class QDict<QStringList>;
00056 
00057 class KStandardDirs::KStandardDirsPrivate
00058 {
00059 public:
00060    KStandardDirsPrivate()
00061     : restrictionsActive(false),
00062       dataRestrictionActive(false)
00063    { }
00064 
00065    bool restrictionsActive;
00066    bool dataRestrictionActive;
00067    QAsciiDict<bool> restrictions;
00068    QStringList xdgdata_prefixes;
00069    QStringList xdgconf_prefixes;
00070 };
00071 
00072 static const char* const types[] = {"html", "icon", "apps", "sound",
00073                   "data", "locale", "services", "mime",
00074                   "servicetypes", "config", "exe",
00075                   "wallpaper", "lib", "pixmap", "templates",
00076                   "module", "qtplugins",
00077                   "xdgdata-apps", "xdgdata-dirs", "xdgconf-menu",
00078                               "kcfg", 0 };
00079 
00080 static int tokenize( QStringList& token, const QString& str,
00081         const QString& delim );
00082 
00083 KStandardDirs::KStandardDirs( ) : addedCustoms(false)
00084 {
00085     d = new KStandardDirsPrivate;
00086     dircache.setAutoDelete(true);
00087     relatives.setAutoDelete(true);
00088     absolutes.setAutoDelete(true);
00089     savelocations.setAutoDelete(true);
00090     addKDEDefaults();
00091 }
00092 
00093 KStandardDirs::~KStandardDirs()
00094 {
00095     delete d;
00096 }
00097 
00098 bool KStandardDirs::isRestrictedResource(const char *type, const QString& relPath) const
00099 {
00100    if (!d || !d->restrictionsActive)
00101       return false;
00102 
00103    if (d->restrictions[type])
00104       return true;
00105 
00106    if (strcmp(type, "data")==0)
00107    {
00108       applyDataRestrictions(relPath);
00109       if (d->dataRestrictionActive)
00110       {
00111          d->dataRestrictionActive = false;
00112          return true;
00113       }
00114    }
00115    return false;
00116 }
00117 
00118 void KStandardDirs::applyDataRestrictions(const QString &relPath) const
00119 {
00120    QString key;
00121    int i = relPath.find('/');
00122    if (i != -1)
00123       key = "data_"+relPath.left(i);
00124    else
00125       key = "data_"+relPath;
00126 
00127    if (d && d->restrictions[key.latin1()])
00128       d->dataRestrictionActive = true;
00129 }
00130 
00131 
00132 QStringList KStandardDirs::allTypes() const
00133 {
00134     QStringList list;
00135     for (int i = 0; types[i] != 0; ++i)
00136         list.append(QString::fromLatin1(types[i]));
00137     return list;
00138 }
00139 
00140 void KStandardDirs::addPrefix( const QString& _dir )
00141 {
00142     if (_dir.isNull())
00143     return;
00144 
00145     QString dir = _dir;
00146     if (dir.at(dir.length() - 1) != '/')
00147     dir += '/';
00148 
00149     if (!prefixes.contains(dir)) {
00150     prefixes.append(dir);
00151     dircache.clear();
00152     }
00153 }
00154 
00155 void KStandardDirs::addXdgConfigPrefix( const QString& _dir )
00156 {
00157     if (_dir.isNull())
00158     return;
00159 
00160     QString dir = _dir;
00161     if (dir.at(dir.length() - 1) != '/')
00162     dir += '/';
00163 
00164     if (!d->xdgconf_prefixes.contains(dir)) {
00165     d->xdgconf_prefixes.append(dir);
00166     dircache.clear();
00167     }
00168 }
00169 
00170 void KStandardDirs::addXdgDataPrefix( const QString& _dir )
00171 {
00172     if (_dir.isNull())
00173     return;
00174 
00175     QString dir = _dir;
00176     if (dir.at(dir.length() - 1) != '/')
00177     dir += '/';
00178 
00179     if (!d->xdgdata_prefixes.contains(dir)) {
00180     d->xdgdata_prefixes.append(dir);
00181     dircache.clear();
00182     }
00183 }
00184 
00185 
00186 QString KStandardDirs::kfsstnd_prefixes()
00187 {
00188    return prefixes.join(":");
00189 }
00190 
00191 bool KStandardDirs::addResourceType( const char *type,
00192                      const QString& relativename )
00193 {
00194     if (relativename.isNull())
00195        return false;
00196 
00197     QStringList *rels = relatives.find(type);
00198     if (!rels) {
00199     rels = new QStringList();
00200     relatives.insert(type, rels);
00201     }
00202     QString copy = relativename;
00203     if (copy.at(copy.length() - 1) != '/')
00204     copy += '/';
00205     if (!rels->contains(copy)) {
00206     rels->prepend(copy);
00207     dircache.remove(type); // clean the cache
00208     return true;
00209     }
00210     return false;
00211 }
00212 
00213 bool KStandardDirs::addResourceDir( const char *type,
00214                     const QString& absdir)
00215 {
00216     QStringList *paths = absolutes.find(type);
00217     if (!paths) {
00218     paths = new QStringList();
00219     absolutes.insert(type, paths);
00220     }
00221     QString copy = absdir;
00222     if (copy.at(copy.length() - 1) != '/')
00223       copy += '/';
00224 
00225     if (!paths->contains(copy)) {
00226     paths->append(copy);
00227     dircache.remove(type); // clean the cache
00228     return true;
00229     }
00230     return false;
00231 }
00232 
00233 QString KStandardDirs::findResource( const char *type,
00234                      const QString& filename ) const
00235 {
00236     if (filename.at(0) == '/')
00237     return filename; // absolute dirs are absolute dirs, right? :-/
00238 
00239 #if 0
00240 kdDebug() << "Find resource: " << type << endl;
00241 for (QStringList::ConstIterator pit = prefixes.begin();
00242      pit != prefixes.end();
00243      pit++)
00244 {
00245   kdDebug() << "Prefix: " << *pit << endl;
00246 }
00247 #endif
00248 
00249     QString dir = findResourceDir(type, filename);
00250     if (dir.isNull())
00251     return dir;
00252     else return dir + filename;
00253 }
00254 
00255 static Q_UINT32 updateHash(const QString &file, Q_UINT32 hash)
00256 {
00257     QCString cFile = QFile::encodeName(file);
00258     struct stat buff;
00259     if ((access(cFile, R_OK) == 0) &&
00260         (stat( cFile, &buff ) == 0) &&
00261         (S_ISREG( buff.st_mode )))
00262     {
00263        hash = hash + (Q_UINT32) buff.st_ctime;
00264     }
00265     return hash;
00266 }
00267 
00268 Q_UINT32 KStandardDirs::calcResourceHash( const char *type,
00269                   const QString& filename, bool deep) const
00270 {
00271     Q_UINT32 hash = 0;
00272 
00273     if (filename.at(0) == '/')
00274     {
00275         // absolute dirs are absolute dirs, right? :-/
00276     return updateHash(filename, hash);
00277     }
00278     if (d && d->restrictionsActive && (strcmp(type, "data")==0))
00279        applyDataRestrictions(filename);
00280     QStringList candidates = resourceDirs(type);
00281     QString fullPath;
00282 
00283     for (QStringList::ConstIterator it = candidates.begin();
00284      it != candidates.end(); it++)
00285     {
00286         hash = updateHash(*it + filename, hash);
00287         if (!deep && hash)
00288            return hash;
00289     }
00290     return hash;
00291 }
00292 
00293 
00294 QStringList KStandardDirs::findDirs( const char *type,
00295                                      const QString& reldir ) const
00296 {
00297     QDir testdir;
00298     QStringList list;
00299     if (reldir.startsWith("/"))
00300     {
00301         testdir.setPath(reldir);
00302         if (testdir.exists())
00303         {
00304             if (reldir.endsWith("/"))
00305                list.append(reldir);
00306             else
00307                list.append(reldir+'/');
00308         }
00309         return list;
00310     }
00311 
00312     checkConfig();
00313 
00314     if (d && d->restrictionsActive && (strcmp(type, "data")==0))
00315        applyDataRestrictions(reldir);
00316     QStringList candidates = resourceDirs(type);
00317 
00318     for (QStringList::ConstIterator it = candidates.begin();
00319          it != candidates.end(); it++) {
00320         testdir.setPath(*it + reldir);
00321         if (testdir.exists())
00322             list.append(testdir.absPath() + '/');
00323     }
00324 
00325     return list;
00326 }
00327 
00328 QString KStandardDirs::findResourceDir( const char *type,
00329                     const QString& filename) const
00330 {
00331 #ifndef NDEBUG
00332     if (filename.isEmpty()) {
00333       kdWarning() << "filename for type " << type << " in KStandardDirs::findResourceDir is not supposed to be empty!!" << endl;
00334       return QString::null;
00335     }
00336 #endif
00337 
00338     if (d && d->restrictionsActive && (strcmp(type, "data")==0))
00339        applyDataRestrictions(filename);
00340     QStringList candidates = resourceDirs(type);
00341     QString fullPath;
00342 
00343     for (QStringList::ConstIterator it = candidates.begin();
00344      it != candidates.end(); it++)
00345       if (exists(*it + filename))
00346     return *it;
00347 
00348 #ifndef NDEBUG
00349     if(false && type != "locale")
00350       kdDebug() << "KStdDirs::findResDir(): can't find \"" << filename << "\" in type \"" << type << "\"." << endl;
00351 #endif
00352 
00353     return QString::null;
00354 }
00355 
00356 bool KStandardDirs::exists(const QString &fullPath)
00357 {
00358     struct stat buff;
00359     if (access(QFile::encodeName(fullPath), R_OK) == 0 && stat( QFile::encodeName(fullPath), &buff ) == 0)
00360     if (fullPath.at(fullPath.length() - 1) != '/') {
00361         if (S_ISREG( buff.st_mode ))
00362         return true;
00363     } else
00364         if (S_ISDIR( buff.st_mode ))
00365         return true;
00366     return false;
00367 }
00368 
00369 static void lookupDirectory(const QString& path, const QString &relPart,
00370                 const QRegExp &regexp,
00371                 QStringList& list,
00372                 QStringList& relList,
00373                 bool recursive, bool unique)
00374 {
00375   QString pattern = regexp.pattern();
00376   if (recursive || pattern.contains('?') || pattern.contains('*'))
00377   {
00378     // We look for a set of files.
00379     DIR *dp = opendir( QFile::encodeName(path));
00380     if (!dp)
00381       return;
00382 
00383     assert(path.at(path.length() - 1) == '/');
00384 
00385     struct dirent *ep;
00386     struct stat buff;
00387 
00388     QString _dot(".");
00389     QString _dotdot("..");
00390 
00391     while( ( ep = readdir( dp ) ) != 0L )
00392     {
00393       QString fn( QFile::decodeName(ep->d_name));
00394       if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1).latin1() == '~')
00395     continue;
00396 
00397       if (!recursive && !regexp.exactMatch(fn))
00398     continue; // No match
00399 
00400       QString pathfn = path + fn;
00401       if ( stat( QFile::encodeName(pathfn), &buff ) != 0 ) {
00402     kdDebug() << "Error stat'ing " << pathfn << " : " << perror << endl;
00403     continue; // Couldn't stat (e.g. no read permissions)
00404       }
00405       if ( recursive ) {
00406     if ( S_ISDIR( buff.st_mode )) {
00407       lookupDirectory(pathfn + '/', relPart + fn + '/', regexp, list, relList, recursive, unique);
00408     }
00409         if (!regexp.exactMatch(fn))
00410       continue; // No match
00411       }
00412       if ( S_ISREG( buff.st_mode))
00413       {
00414         if (!unique || !relList.contains(relPart + fn))
00415         {
00416         list.append( pathfn );
00417         relList.append( relPart + fn );
00418         }
00419       }
00420     }
00421     closedir( dp );
00422   }
00423   else
00424   {
00425      // We look for a single file.
00426      QString fn = pattern;
00427      QString pathfn = path + fn;
00428      struct stat buff;
00429      if ( stat( QFile::encodeName(pathfn), &buff ) != 0 )
00430         return; // File not found
00431      if ( S_ISREG( buff.st_mode))
00432      {
00433        if (!unique || !relList.contains(relPart + fn))
00434        {
00435          list.append( pathfn );
00436          relList.append( relPart + fn );
00437        }
00438      }
00439   }
00440 }
00441 
00442 static void lookupPrefix(const QString& prefix, const QString& relpath,
00443                          const QString& relPart,
00444              const QRegExp &regexp,
00445              QStringList& list,
00446              QStringList& relList,
00447              bool recursive, bool unique)
00448 {
00449     if (relpath.isNull()) {
00450        lookupDirectory(prefix, relPart, regexp, list,
00451                relList, recursive, unique);
00452        return;
00453     }
00454     QString path;
00455     QString rest;
00456 
00457     if (relpath.length())
00458     {
00459        int slash = relpath.find('/');
00460        if (slash < 0)
00461        rest = relpath.left(relpath.length() - 1);
00462        else {
00463        path = relpath.left(slash);
00464        rest = relpath.mid(slash + 1);
00465        }
00466     }
00467 
00468     assert(prefix.at(prefix.length() - 1) == '/');
00469 
00470     struct stat buff;
00471 
00472     if (path.contains('*') || path.contains('?')) {
00473 
00474     QRegExp pathExp(path, true, true);
00475     DIR *dp = opendir( QFile::encodeName(prefix) );
00476     if (!dp) {
00477         return;
00478     }
00479 
00480     struct dirent *ep;
00481 
00482         QString _dot(".");
00483         QString _dotdot("..");
00484 
00485     while( ( ep = readdir( dp ) ) != 0L )
00486         {
00487         QString fn( QFile::decodeName(ep->d_name));
00488         if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1) == '~')
00489             continue;
00490 
00491         if (pathExp.search(fn) == -1)
00492             continue; // No match
00493         QString rfn = relPart+fn;
00494         fn = prefix + fn;
00495         if ( stat( QFile::encodeName(fn), &buff ) != 0 ) {
00496             kdDebug() << "Error statting " << fn << " : " << perror << endl;
00497             continue; // Couldn't stat (e.g. no permissions)
00498         }
00499         if ( S_ISDIR( buff.st_mode ))
00500             lookupPrefix(fn + '/', rest, rfn + '/', regexp, list, relList, recursive, unique);
00501         }
00502 
00503     closedir( dp );
00504     } else {
00505         // Don't stat, if the dir doesn't exist we will find out
00506         // when we try to open it.
00507         lookupPrefix(prefix + path + '/', rest,
00508                      relPart + path + '/', regexp, list,
00509                      relList, recursive, unique);
00510     }
00511 }
00512 
00513 QStringList
00514 KStandardDirs::findAllResources( const char *type,
00515                      const QString& filter,
00516                  bool recursive,
00517                      bool unique,
00518                                  QStringList &relList) const
00519 {
00520     QStringList list;
00521     QString filterPath;
00522     QString filterFile;
00523 
00524     if (filter.length())
00525     {
00526        int slash = filter.findRev('/');
00527        if (slash < 0)
00528        filterFile = filter;
00529        else {
00530        filterPath = filter.left(slash + 1);
00531        filterFile = filter.mid(slash + 1);
00532        }
00533     }
00534 
00535     checkConfig();
00536 
00537     QStringList candidates;
00538     if (filterPath.startsWith("/")) // absolute path
00539     {
00540         filterPath = filterPath.mid(1);
00541         candidates << "/";
00542     }
00543     else
00544     {
00545         if (d && d->restrictionsActive && (strcmp(type, "data")==0))
00546             applyDataRestrictions(filter);
00547         candidates = resourceDirs(type);
00548     }
00549     if (filterFile.isEmpty())
00550     filterFile = "*";
00551 
00552     QRegExp regExp(filterFile, true, true);
00553 
00554     for (QStringList::ConstIterator it = candidates.begin();
00555          it != candidates.end(); it++)
00556     {
00557         lookupPrefix(*it, filterPath, "", regExp, list,
00558                      relList, recursive, unique);
00559     }
00560 
00561     return list;
00562 }
00563 
00564 QStringList
00565 KStandardDirs::findAllResources( const char *type,
00566                      const QString& filter,
00567                  bool recursive,
00568                      bool unique) const
00569 {
00570     QStringList relList;
00571     return findAllResources(type, filter, recursive, unique, relList);
00572 }
00573 
00574 QString
00575 KStandardDirs::realPath(const QString &dirname)
00576 {
00577     char realpath_buffer[MAXPATHLEN + 1];
00578     memset(realpath_buffer, 0, MAXPATHLEN + 1);
00579 
00580     /* If the path contains symlinks, get the real name */
00581     if (realpath( QFile::encodeName(dirname).data(), realpath_buffer) != 0) {
00582         // succes, use result from realpath
00583         int len = strlen(realpath_buffer);
00584         realpath_buffer[len] = '/';
00585         realpath_buffer[len+1] = 0;
00586         return QFile::decodeName(realpath_buffer);
00587     }
00588 
00589     return dirname;
00590 }
00591 
00592 void KStandardDirs::createSpecialResource(const char *type)
00593 {
00594    char hostname[256];
00595    hostname[0] = 0;
00596    gethostname(hostname, 255);
00597    QString dir = QString("%1%2-%3").arg(localkdedir()).arg(type).arg(hostname);
00598    char link[1024];
00599    link[1023] = 0;
00600    int result = readlink(QFile::encodeName(dir).data(), link, 1023);
00601    if ((result == -1) && (errno == ENOENT))
00602    {
00603       QString srv = findExe(QString::fromLatin1("lnusertemp"), KDEDIR+QString::fromLatin1("/bin"));
00604       if (srv.isEmpty())
00605          srv = findExe(QString::fromLatin1("lnusertemp"));
00606       if (!srv.isEmpty())
00607       {
00608          system(QFile::encodeName(srv)+" "+type);
00609          result = readlink(QFile::encodeName(dir).data(), link, 1023);
00610       }
00611    }
00612    if (result > 0)
00613    {
00614       link[result] = 0;
00615       if (link[0] == '/')
00616          dir = QFile::decodeName(link);
00617       else
00618          dir = QDir::cleanDirPath(dir+QFile::decodeName(link));
00619    }
00620    addResourceDir(type, dir+'/');
00621 }
00622 
00623 QStringList KStandardDirs::resourceDirs(const char *type) const
00624 {
00625     QStringList *candidates = dircache.find(type);
00626 
00627     if (!candidates) { // filling cache
00628         if (strcmp(type, "socket") == 0)
00629            const_cast<KStandardDirs *>(this)->createSpecialResource(type);
00630         else if (strcmp(type, "tmp") == 0)
00631            const_cast<KStandardDirs *>(this)->createSpecialResource(type);
00632         else if (strcmp(type, "cache") == 0)
00633            const_cast<KStandardDirs *>(this)->createSpecialResource(type);
00634 
00635         QDir testdir;
00636 
00637         candidates = new QStringList();
00638         QStringList *dirs;
00639 
00640         bool restrictionActive = false;
00641         if (d && d->restrictionsActive)
00642         {
00643            if (d->dataRestrictionActive)
00644               restrictionActive = true;
00645            else if (d->restrictions["all"])
00646               restrictionActive = true;
00647            else if (d->restrictions[type])
00648               restrictionActive = true;
00649            d->dataRestrictionActive = false; // Reset
00650         }
00651 
00652         dirs = relatives.find(type);
00653         if (dirs)
00654         {
00655             bool local = true;
00656             const QStringList *prefixList = 0;
00657             if (strncmp(type, "xdgdata-", 8) == 0)
00658                 prefixList = &(d->xdgdata_prefixes);
00659             else if (strncmp(type, "xdgconf-", 8) == 0)
00660                 prefixList = &(d->xdgconf_prefixes);
00661             else
00662                 prefixList = &prefixes;
00663 
00664             for (QStringList::ConstIterator pit = prefixList->begin();
00665                  pit != prefixList->end();
00666                  pit++)
00667             {
00668                 for (QStringList::ConstIterator it = dirs->begin();
00669                      it != dirs->end(); ++it) {
00670                     QString path = realPath(*pit + *it);
00671                     testdir.setPath(path);
00672                     if (local && restrictionActive)
00673                        continue;
00674                     if ((local || testdir.exists()) && !candidates->contains(path))
00675                         candidates->append(path);
00676                 }
00677                 // UGLY HACK - Chris Cheney
00678                 if (local && ("config" == type))
00679                    candidates->append("/etc/kde3/");
00680                 //
00681                 local = false;
00682             }
00683         }
00684         dirs = absolutes.find(type);
00685         if (dirs)
00686             for (QStringList::ConstIterator it = dirs->begin();
00687                  it != dirs->end(); ++it)
00688             {
00689                 testdir.setPath(*it);
00690                 if (testdir.exists())
00691                 {
00692                     QString filename = realPath(*it);
00693                     if (!candidates->contains(filename))
00694                         candidates->append(filename);
00695                 }
00696             }
00697         dircache.insert(type, candidates);
00698     }
00699 
00700 #if 0
00701     kdDebug() << "found dirs for resource " << type << ":" << endl;
00702     for (QStringList::ConstIterator pit = candidates->begin();
00703      pit != candidates->end();
00704      pit++)
00705     {
00706     fprintf(stderr, "%s\n", (*pit).latin1());
00707     }
00708 #endif
00709 
00710 
00711   return *candidates;
00712 }
00713 
00714 QStringList KStandardDirs::systemPaths( const QString& pstr )
00715 {
00716     QStringList tokens;
00717     QString p = pstr;
00718 
00719     if( p.isNull() ) 
00720     {
00721     p = getenv( "PATH" );
00722     }
00723 
00724     tokenize( tokens, p, ":\b" );
00725 
00726     QStringList exePaths;
00727 
00728     // split path using : or \b as delimiters
00729     for( unsigned i = 0; i < tokens.count(); i++ )
00730     {
00731     p = tokens[ i ];
00732 
00733         if ( p[ 0 ] == '~' )
00734         {
00735             int len = p.find( '/' );
00736             if ( len == -1 )
00737                 len = p.length();
00738             if ( len == 1 )
00739             {
00740                 p.replace( 0, 1, QDir::homeDirPath() );
00741             }
00742             else
00743             {
00744                 QString user = p.mid( 1, len - 1 );
00745                 struct passwd *dir = getpwnam( user.local8Bit().data() );
00746                 if ( dir && strlen( dir->pw_dir ) )
00747                     p.replace( 0, len, QString::fromLocal8Bit( dir->pw_dir ) );
00748             }
00749         }
00750 
00751     exePaths << p;
00752     }
00753 
00754     return exePaths;
00755 }
00756 
00757 
00758 QString KStandardDirs::findExe( const QString& appname,
00759                 const QString& pstr, bool ignore)
00760 {
00761     QFileInfo info;
00762 
00763     // absolute path ?
00764     if (appname.startsWith(QString::fromLatin1("/")))
00765     {
00766         info.setFile( appname );
00767         if( info.exists() && ( ignore || info.isExecutable() )
00768             && info.isFile() ) {
00769             return appname;
00770         }
00771         return QString::null;
00772     }
00773 
00774     QString p = QString("%1/%2").arg(__KDE_BINDIR).arg(appname);
00775     info.setFile( p );
00776     if( info.exists() && ( ignore || info.isExecutable() )
00777          && ( info.isFile() || info.isSymLink() )  ) {
00778          return p;
00779     }
00780 
00781     QStringList exePaths = systemPaths( pstr );
00782     for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); it++)
00783     {
00784     p = (*it) + "/";
00785     p += appname;
00786 
00787     // Check for executable in this tokenized path
00788     info.setFile( p );
00789 
00790     if( info.exists() && ( ignore || info.isExecutable() )
00791            && ( info.isFile() || info.isSymLink() )  ) {
00792         return p;
00793     }
00794     }
00795 
00796     // If we reach here, the executable wasn't found.
00797     // So return empty string.
00798 
00799     return QString::null;
00800 }
00801 
00802 int KStandardDirs::findAllExe( QStringList& list, const QString& appname,
00803             const QString& pstr, bool ignore )
00804 {
00805     QFileInfo info;
00806     QString p;
00807     list.clear();
00808 
00809     QStringList exePaths = systemPaths( pstr );
00810     for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); it++)
00811     {
00812     p = (*it) + "/";
00813     p += appname;
00814 
00815     info.setFile( p );
00816 
00817     if( info.exists() && (ignore || info.isExecutable())
00818         && info.isFile() ) {
00819         list.append( p );
00820     }
00821     }
00822 
00823     return list.count();
00824 }
00825 
00826 static int tokenize( QStringList& tokens, const QString& str,
00827              const QString& delim )
00828 {
00829     int len = str.length();
00830     QString token = "";
00831 
00832     for( int index = 0; index < len; index++)
00833     {
00834     if ( delim.find( str[ index ] ) >= 0 )
00835     {
00836         tokens.append( token );
00837         token = "";
00838     }
00839     else
00840     {
00841         token += str[ index ];
00842     }
00843     }
00844     if ( token.length() > 0 )
00845     {
00846     tokens.append( token );
00847     }
00848 
00849     return tokens.count();
00850 }
00851 
00852 QString KStandardDirs::kde_default(const char *type) {
00853     if (!strcmp(type, "data"))
00854     return "share/apps/";
00855     if (!strcmp(type, "html"))
00856     return "share/doc/kde/HTML/";
00857     if (!strcmp(type, "icon"))
00858     return "share/icons/";
00859     if (!strcmp(type, "config"))
00860     return "share/config/";
00861     if (!strcmp(type, "pixmap"))
00862     return "share/pixmaps/";
00863     if (!strcmp(type, "apps"))
00864     return "share/applnk/";
00865     if (!strcmp(type, "sound"))
00866     return "share/sounds/";
00867     if (!strcmp(type, "locale"))
00868     return "share/locale/";
00869     if (!strcmp(type, "services"))
00870     return "share/services/";
00871     if (!strcmp(type, "servicetypes"))
00872     return "share/servicetypes/";
00873     if (!strcmp(type, "mime"))
00874     return "share/mimelnk/";
00875     if (!strcmp(type, "cgi"))
00876     return "lib/cgi-bin/";
00877     if (!strcmp(type, "wallpaper"))
00878     return "share/wallpapers/";
00879     if (!strcmp(type, "templates"))
00880     return "share/templates/";
00881     if (!strcmp(type, "exe"))
00882     return "bin/";
00883     if (!strcmp(type, "lib"))
00884     return "lib/";
00885     if (!strcmp(type, "module"))
00886     return "lib/kde3/";
00887     if (!strcmp(type, "qtplugins"))
00888         return "lib/kde3/plugins";
00889     if (!strcmp(type, "xdgdata-apps"))
00890         return "applications/";
00891     if (!strcmp(type, "xdgdata-dirs"))
00892         return "desktop-directories/";
00893     if (!strcmp(type, "xdgconf-menu"))
00894         return "menus/";
00895     if (!strcmp(type, "kcfg"))
00896     return "share/config.kcfg";
00897     qFatal("unknown resource type %s", type);
00898     return QString::null;
00899 }
00900 
00901 QString KStandardDirs::saveLocation(const char *type,
00902                     const QString& suffix,
00903                     bool create) const
00904 {
00905     checkConfig();
00906 
00907     QString *pPath = savelocations.find(type);
00908     if (!pPath)
00909     {
00910        QStringList *dirs = relatives.find(type);
00911        if (!dirs && (
00912                      (strcmp(type, "socket") == 0) ||
00913                      (strcmp(type, "tmp") == 0) ||
00914                      (strcmp(type, "cache") == 0) ))
00915        {
00916           (void) resourceDirs(type); // Generate socket|tmp|cache resource.
00917           dirs = relatives.find(type); // Search again.
00918        }
00919        if (dirs)
00920        {
00921           // Check for existence of typed directory + suffix
00922           if (strncmp(type, "xdgdata-", 8) == 0)
00923              pPath = new QString(realPath(localxdgdatadir() + dirs->last()));
00924           else if (strncmp(type, "xdgconf-", 8) == 0)
00925              pPath = new QString(realPath(localxdgconfdir() + dirs->last()));
00926           else
00927              pPath = new QString(realPath(localkdedir() + dirs->last()));
00928        }
00929        else {
00930           dirs = absolutes.find(type);
00931           if (!dirs)
00932              qFatal("KStandardDirs: The resource type %s is not registered", type);
00933           pPath = new QString(realPath(dirs->last()));
00934        }
00935 
00936        savelocations.insert(type, pPath);
00937     }
00938     QString fullPath = *pPath + suffix;
00939 
00940     struct stat st;
00941     if (stat(QFile::encodeName(fullPath), &st) != 0 || !(S_ISDIR(st.st_mode))) {
00942     if(!create) {
00943 #ifndef NDEBUG
00944         qDebug("save location %s doesn't exist", fullPath.latin1());
00945 #endif
00946         return fullPath;
00947     }
00948     if(!makeDir(fullPath, 0700)) {
00949             qWarning("failed to create %s", fullPath.latin1());
00950         return fullPath;
00951     }
00952         dircache.remove(type);
00953     }
00954     return fullPath;
00955 }
00956 
00957 QString KStandardDirs::relativeLocation(const char *type, const QString &absPath)
00958 {
00959     QString fullPath = absPath;
00960     int i = absPath.findRev('/');
00961     if (i != -1)
00962     {
00963        fullPath = realPath(absPath.left(i+1))+absPath.mid(i+1); // Normalize
00964     }
00965 
00966     QStringList candidates = resourceDirs(type);
00967 
00968     for (QStringList::ConstIterator it = candidates.begin();
00969      it != candidates.end(); it++)
00970       if (fullPath.startsWith(*it))
00971       {
00972     return fullPath.mid((*it).length());
00973       }
00974 
00975     return absPath;
00976 }
00977 
00978 
00979 bool KStandardDirs::makeDir(const QString& dir, int mode)
00980 {
00981     // we want an absolute path
00982     if (dir.at(0) != '/')
00983         return false;
00984 
00985     QString target = dir;
00986     uint len = target.length();
00987 
00988     // append trailing slash if missing
00989     if (dir.at(len - 1) != '/')
00990         target += '/';
00991 
00992     QString base("");
00993     uint i = 1;
00994 
00995     while( i < len )
00996     {
00997         struct stat st;
00998         int pos = target.find('/', i);
00999         base += target.mid(i - 1, pos - i + 1);
01000         QCString baseEncoded = QFile::encodeName(base);
01001         // bail out if we encountered a problem
01002         if (stat(baseEncoded, &st) != 0)
01003         {
01004           // Directory does not exist....
01005           // Or maybe a dangling symlink ?
01006           if (lstat(baseEncoded, &st) == 0)
01007               (void)unlink(baseEncoded); // try removing
01008 
01009       if ( mkdir(baseEncoded, (mode_t) mode) != 0) {
01010         perror("trying to create local folder");
01011         return false; // Couldn't create it :-(
01012       }
01013         }
01014         i = pos + 1;
01015     }
01016     return true;
01017 }
01018 
01019 static QString readEnvPath(const char *env)
01020 {
01021    QCString c_path = getenv(env);
01022    if (c_path.isEmpty())
01023       return QString::null;
01024    return QFile::decodeName(c_path);
01025 }
01026 
01027 void KStandardDirs::addKDEDefaults()
01028 {
01029     QStringList kdedirList;
01030 
01031     // begin KDEDIRS
01032     QString kdedirs = readEnvPath("KDEDIRS");
01033     if (!kdedirs.isEmpty())
01034     {
01035     tokenize(kdedirList, kdedirs, ":");
01036     }
01037     else
01038     {
01039     QString kdedir = readEnvPath("KDEDIR");
01040     if (!kdedir.isEmpty())
01041         {
01042            kdedir = KShell::tildeExpand(kdedir);
01043        kdedirList.append(kdedir);
01044         }
01045     }
01046     // UGLY HACK - Chris Cheney
01047     kdedirList.append("/usr/local");
01048     //
01049     kdedirList.append(KDEDIR);
01050 
01051 #ifdef __KDE_EXECPREFIX
01052     QString execPrefix(__KDE_EXECPREFIX);
01053     if (execPrefix!="NONE")
01054        kdedirList.append(execPrefix);
01055 #endif
01056 
01057     // We treat root differently to prevent a "su" shell messing up the
01058     // file permissions in the user's home directory.
01059     QString localKdeDir = readEnvPath(getuid() ? "KDEHOME" : "KDEROOTHOME");
01060     if (!localKdeDir.isEmpty())
01061     {
01062        if (localKdeDir[localKdeDir.length()-1] != '/')
01063           localKdeDir += '/';
01064     }
01065     else
01066     {
01067        localKdeDir =  QDir::homeDirPath() + "/.kde/";
01068     }
01069 
01070     if (localKdeDir != "-/")
01071     {
01072         localKdeDir = KShell::tildeExpand(localKdeDir);
01073         addPrefix(localKdeDir);
01074     }
01075 
01076     for (QStringList::ConstIterator it = kdedirList.begin();
01077      it != kdedirList.end(); it++)
01078     {
01079         QString dir = KShell::tildeExpand(*it);
01080     addPrefix(dir);
01081     }
01082     // end KDEDIRS
01083 
01084     // begin XDG_CONFIG_XXX
01085     QStringList xdgdirList;
01086     QString xdgdirs = readEnvPath("XDG_CONFIG_DIRS");
01087     if (!xdgdirs.isEmpty())
01088     {
01089     tokenize(xdgdirList, xdgdirs, ":");
01090     }
01091     else
01092     {
01093     xdgdirList.clear();
01094         xdgdirList.append("/etc/xdg");
01095         xdgdirList.append(KDESYSCONFDIR "/xdg");
01096     }
01097 
01098     QString localXdgDir = readEnvPath("XDG_CONFIG_HOME");
01099     if (!localXdgDir.isEmpty())
01100     {
01101        if (localXdgDir[localXdgDir.length()-1] != '/')
01102           localXdgDir += '/';
01103     }
01104     else
01105     {
01106        localXdgDir =  QDir::homeDirPath() + "/.config/";
01107     }
01108 
01109     localXdgDir = KShell::tildeExpand(localXdgDir);
01110     addXdgConfigPrefix(localXdgDir);
01111 
01112     for (QStringList::ConstIterator it = xdgdirList.begin();
01113      it != xdgdirList.end(); it++)
01114     {
01115         QString dir = KShell::tildeExpand(*it);
01116     addXdgConfigPrefix(dir);
01117     }
01118     // end XDG_CONFIG_XXX
01119 
01120     // begin XDG_DATA_XXX
01121     xdgdirs = readEnvPath("XDG_DATA_DIRS");
01122     if (!xdgdirs.isEmpty())
01123     {
01124     tokenize(xdgdirList, xdgdirs, ":");
01125     }
01126     else
01127     {
01128     xdgdirList.clear();
01129         for (QStringList::ConstIterator it = kdedirList.begin();
01130            it != kdedirList.end(); it++)
01131         {
01132            QString dir = *it;
01133            if (dir[dir.length()-1] != '/')
01134              dir += '/';
01135            xdgdirList.append(dir+"share/");
01136         }
01137 
01138         xdgdirList.append("/usr/local/share/");
01139         xdgdirList.append("/usr/share/");
01140     }
01141 
01142     localXdgDir = readEnvPath("XDG_DATA_HOME");
01143     if (!localXdgDir.isEmpty())
01144     {
01145        if (localXdgDir[localXdgDir.length()-1] != '/')
01146           localXdgDir += '/';
01147     }
01148     else
01149     {
01150        localXdgDir = QDir::homeDirPath() + "/.local/share/";
01151     }
01152 
01153     localXdgDir = KShell::tildeExpand(localXdgDir);
01154     addXdgDataPrefix(localXdgDir);
01155 
01156     for (QStringList::ConstIterator it = xdgdirList.begin();
01157      it != xdgdirList.end(); it++)
01158     {
01159         QString dir = KShell::tildeExpand(*it);
01160     addXdgDataPrefix(dir);
01161     }
01162     // end XDG_DATA_XXX
01163 
01164 
01165     uint index = 0;
01166     while (types[index] != 0) {
01167     addResourceType(types[index], kde_default(types[index]));
01168     index++;
01169     }
01170 
01171     addResourceDir("home", QDir::homeDirPath());
01172 }
01173 
01174 void KStandardDirs::checkConfig() const
01175 {
01176     if (!addedCustoms && KGlobal::_instance && KGlobal::_instance->_config)
01177         const_cast<KStandardDirs*>(this)->addCustomized(KGlobal::_instance->_config);
01178 }
01179 
01180 bool KStandardDirs::addCustomized(KConfig *config)
01181 {
01182     if (addedCustoms) // there are already customized entries
01183         return false; // we just quite and hope they are the right ones
01184 
01185     // save the numbers of config directories. If this changes,
01186     // we will return true to give KConfig a chance to reparse
01187     uint configdirs = resourceDirs("config").count();
01188 
01189     // reading the prefixes in
01190     QString oldGroup = config->group();
01191     config->setGroup("Directories");
01192 
01193     QStringList list;
01194     QStringList::ConstIterator it;
01195     list = config->readListEntry("prefixes");
01196     for (it = list.begin(); it != list.end(); it++)
01197     addPrefix(*it);
01198 
01199     // iterating over all entries in the group Directories
01200     // to find entries that start with dir_$type
01201     QMap<QString, QString> entries = config->entryMap("Directories");
01202 
01203     QMap<QString, QString>::ConstIterator it2;
01204     for (it2 = entries.begin(); it2 != entries.end(); it2++)
01205     {
01206     QString key = it2.key();
01207     if (key.left(4) == "dir_") {
01208         // generate directory list, there may be more than 1.
01209         QStringList dirs = QStringList::split(',',
01210                           *it2);
01211         QStringList::Iterator sIt(dirs.begin());
01212         QString resType = key.mid(4, key.length());
01213         for (; sIt != dirs.end(); ++sIt) {
01214         addResourceDir(resType.latin1(), *sIt);
01215         }
01216     }
01217     }
01218 
01219     // Process KIOSK restrictions.
01220     config->setGroup("KDE Resource Restrictions");
01221     entries = config->entryMap("KDE Resource Restrictions");
01222     for (it2 = entries.begin(); it2 != entries.end(); it2++)
01223     {
01224     QString key = it2.key();
01225         if (!config->readBoolEntry(key, true))
01226         {
01227            d->restrictionsActive = true;
01228            d->restrictions.insert(key.latin1(), &d->restrictionsActive); // Anything will do
01229            dircache.remove(key.latin1());
01230         }
01231     }
01232 
01233     // save it for future calls - that will return
01234     addedCustoms = true;
01235     config->setGroup(oldGroup);
01236 
01237     // return true if the number of config dirs changed
01238     return (resourceDirs("config").count() != configdirs);
01239 }
01240 
01241 QString KStandardDirs::localkdedir() const
01242 {
01243     // Return the prefix to use for saving
01244     return prefixes.first();
01245 }
01246 
01247 QString KStandardDirs::localxdgdatadir() const
01248 {
01249     // Return the prefix to use for saving
01250     return d->xdgdata_prefixes.first();
01251 }
01252 
01253 QString KStandardDirs::localxdgconfdir() const
01254 {
01255     // Return the prefix to use for saving
01256     return d->xdgconf_prefixes.first();
01257 }
01258 
01259 // just to make code more readable without macros
01260 QString locate( const char *type,
01261         const QString& filename, const KInstance* inst )
01262 {
01263     return inst->dirs()->findResource(type, filename);
01264 }
01265 
01266 QString locateLocal( const char *type,
01267                  const QString& filename, const KInstance* inst )
01268 {
01269     return locateLocal(type, filename, true, inst);
01270 }
01271 
01272 QString locateLocal( const char *type,
01273                  const QString& filename, bool createDir, const KInstance* inst )
01274 {
01275     // try to find slashes. If there are some, we have to
01276     // create the subdir first
01277     int slash = filename.findRev('/')+1;
01278     if (!slash) // only one filename
01279     return inst->dirs()->saveLocation(type, QString::null, createDir) + filename;
01280 
01281     // split path from filename
01282     QString dir = filename.left(slash);
01283     QString file = filename.mid(slash);
01284     return inst->dirs()->saveLocation(type, dir, createDir) + file;
01285 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun May 16 22:01:21 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003