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