<commit_before>/***************************************************************************
 *   Copyright (C) 2007 by <NAME> <<EMAIL>>            *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include "xdgbasedirs_p.h"

#include "akonadi-prefix.h" // for prefix defines

#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QProcess>

#include <cstdlib>

static QStringList alternateExecPaths( const QString& path )
{
  QStringList pathList;

  pathList << path;

#if defined(Q_OS_WIN) //krazy:exclude=cpp
  pathList << path + QLatin1String( ".exe" );
#elif defined(Q_OS_MAC) //krazy:exclude=cpp
  pathList << path + QLatin1String( ".app/Contents/MacOS/" ) + path.section( QLatin1Char( '/' ), -1 );
#endif

  return pathList;
}

static QStringList splitPathList( const QString &pathList )
{
#if defined(Q_OS_WIN) //krazy:exclude=cpp
  return pathList.split( QLatin1Char( ';' ) );
#else
  return pathList.split( QLatin1Char( ':' ) );
#endif
}

namespace Akonadi {

class XdgBaseDirsPrivate
{
  public:
    XdgBaseDirsPrivate() {}

    ~XdgBaseDirsPrivate() {}
};

class XdgBaseDirsSingleton
{
public:
    QString homePath( const char *variable, const char *defaultSubDir );

    QStringList systemPathList( const char *variable, const char *defaultDirList );

  public:
    QString mConfigHome;
    QString mDataHome;

    QStringList mConfigDirs;
    QStringList mDataDirs;
    QStringList mExecutableDirs;
};

Q_GLOBAL_STATIC(XdgBaseDirsSingleton, instance)

}

using namespace Akonadi;

XdgBaseDirs::XdgBaseDirs() : d( new XdgBaseDirsPrivate() )
{
}

XdgBaseDirs::~XdgBaseDirs()
{
  delete d;
}

QString XdgBaseDirs::homePath( const char *resource )
{
  if ( qstrncmp( "data", resource, 4 ) == 0 ) {
    if ( instance()->mDataHome.isEmpty() ) {
      instance()->mDataHome = instance()->homePath( "XDG_DATA_HOME", ".local/share" );
    }
    return instance()->mDataHome;
  } else if ( qstrncmp( "config", resource, 6 ) == 0 ) {
    if ( instance()->mConfigHome.isEmpty() ) {
      instance()->mConfigHome = instance()->homePath( "XDG_CONFIG_HOME", ".config" );
    }
    return instance()->mConfigHome;
  }

  return QString();
}

QStringList XdgBaseDirs::systemPathList( const char *resource )
{
  if ( qstrncmp( "data", resource, 4 ) == 0 ) {
    if ( instance()->mDataDirs.isEmpty() ) {
      QStringList dataDirs = instance()->systemPathList( "XDG_DATA_DIRS", "/usr/local/share:/usr/share" );

#ifdef Q_OS_WIN
      const QString prefixDataDir = QLatin1String( AKONADIPREFIX "/" AKONADIDATA );
#else
      const QString prefixDataDir = QLatin1String( AKONADIDATA );
#endif
      if ( !dataDirs.contains( prefixDataDir ) ) {
        dataDirs << prefixDataDir;
      }

      // fallback for users with KDE in a different prefix and not correctly set up XDG_DATA_DIRS, hi David ;-)
      QProcess proc;
      // ### should probably rather be --path xdg-something
      const QStringList args = QStringList() << QLatin1String( "--prefix" );
      proc.start( QLatin1String( "kde4-config" ), args );
      if ( proc.waitForStarted() && proc.waitForFinished() && proc.exitCode() == 0 ) {
        proc.setReadChannel( QProcess::StandardOutput );
        foreach ( const QString &basePath, splitPathList( QString::fromLocal8Bit( proc.readLine().trimmed() ) ) ) {
          const QString path = basePath + QDir::separator() + QLatin1String( "share" );
          if ( !dataDirs.contains( path ) )
            dataDirs << path;
        }
      }

      instance()->mDataDirs = dataDirs;
    }
    return instance()->mDataDirs;
  } else if ( qstrncmp( "config", resource, 6 ) == 0 ) {
    if ( instance()->mConfigDirs.isEmpty() ) {
      QStringList configDirs = instance()->systemPathList( "XDG_CONFIG_DIRS", "/etc/xdg" );

#ifdef Q_OS_WIN
      const QString prefixConfigDir = QLatin1String( AKONADIPREFIX "/" AKONADICONFIG );
#else
      const QString prefixConfigDir = QLatin1String( AKONADICONFIG );
#endif
      if ( !configDirs.contains( prefixConfigDir ) ) {
        configDirs << prefixConfigDir;
      }

      instance()->mConfigDirs = configDirs;
    }
    return instance()->mConfigDirs;
  }

  return QStringList();
}

QString XdgBaseDirs::findResourceFile( const char *resource, const QString &relPath )
{
  QString fullPath = homePath( resource ) + QLatin1Char('/' ) + relPath;

  QFileInfo fileInfo( fullPath );
  if ( fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable() ) {
    return fullPath;
  }

  QStringList pathList = systemPathList( resource );

  QStringList::const_iterator it    = pathList.constBegin();
  QStringList::const_iterator endIt = pathList.constEnd();
  for ( ; it != endIt; ++it ) {
    fileInfo = QFileInfo( *it + QLatin1Char('/' ) + relPath );
    if ( fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable() ) {
      return fileInfo.absoluteFilePath();
    }
  }

  return QString();
}

QString XdgBaseDirs::findExecutableFile( const QString &relPath, const QStringList &searchPath )
{
  if ( instance()->mExecutableDirs.isEmpty() ) {
    QStringList executableDirs = instance()->systemPathList( "PATH", "/usr/local/bin:/usr/bin" );

    const QString prefixExecutableDir = QLatin1String( AKONADIPREFIX "/bin" );
    if ( !executableDirs.contains( prefixExecutableDir ) ) {
      executableDirs << prefixExecutableDir;
    }

    executableDirs += searchPath;

#if defined(Q_OS_MAC) //krazy:exclude=cpp
    executableDirs += QLatin1String(AKONADIBUNDLEPATH);
#endif
    qWarning( ) << "search paths: " << executableDirs;

    instance()->mExecutableDirs = executableDirs;
  }

  QStringList::const_iterator pathIt    = instance()->mExecutableDirs.constBegin();
  QStringList::const_iterator pathEndIt = instance()->mExecutableDirs.constEnd();
  for ( ; pathIt != pathEndIt; ++pathIt ) {
    QStringList fullPathList = alternateExecPaths(*pathIt + QLatin1Char( '/' ) + relPath );
<commit_msg>If we have a QCoreApplication instance, add the current programs application path to the search list for executables if it is not in the list yet. Helps on Windows when tool programs are installed together but into a location which is not in PATH<commit_after>/***************************************************************************
 *   Copyright (C) 2007 by <NAME> <<EMAIL>>            *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include "xdgbasedirs_p.h"

#include "akonadi-prefix.h" // for prefix defines

#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QProcess>

#include <cstdlib>

static QStringList alternateExecPaths( const QString& path )
{
  QStringList pathList;

  pathList << path;

#if defined(Q_OS_WIN) //krazy:exclude=cpp
  pathList << path + QLatin1String( ".exe" );
#elif defined(Q_OS_MAC) //krazy:exclude=cpp
  pathList << path + QLatin1String( ".app/Contents/MacOS/" ) + path.section( QLatin1Char( '/' ), -1 );
#endif

  return pathList;
}

static QStringList splitPathList( const QString &pathList )
{
#if defined(Q_OS_WIN) //krazy:exclude=cpp
  return pathList.split( QLatin1Char( ';' ) );
#else
  return pathList.split( QLatin1Char( ':' ) );
#endif
}

namespace Akonadi {

class XdgBaseDirsPrivate
{
  public:
    XdgBaseDirsPrivate() {}

    ~XdgBaseDirsPrivate() {}
};

class XdgBaseDirsSingleton
{
public:
    QString homePath( const char *variable, const char *defaultSubDir );

    QStringList systemPathList( const char *variable, const char *defaultDirList );

  public:
    QString mConfigHome;
    QString mDataHome;

    QStringList mConfigDirs;
    QStringList mDataDirs;
    QStringList mExecutableDirs;
};

Q_GLOBAL_STATIC(XdgBaseDirsSingleton, instance)

}

using namespace Akonadi;

XdgBaseDirs::XdgBaseDirs() : d( new XdgBaseDirsPrivate() )
{
}

XdgBaseDirs::~XdgBaseDirs()
{
  delete d;
}

QString XdgBaseDirs::homePath( const char *resource )
{
  if ( qstrncmp( "data", resource, 4 ) == 0 ) {
    if ( instance()->mDataHome.isEmpty() ) {
      instance()->mDataHome = instance()->homePath( "XDG_DATA_HOME", ".local/share" );
    }
    return instance()->mDataHome;
  } else if ( qstrncmp( "config", resource, 6 ) == 0 ) {
    if ( instance()->mConfigHome.isEmpty() ) {
      instance()->mConfigHome = instance()->homePath( "XDG_CONFIG_HOME", ".config" );
    }
    return instance()->mConfigHome;
  }

  return QString();
}

QStringList XdgBaseDirs::systemPathList( const char *resource )
{
  if ( qstrncmp( "data", resource, 4 ) == 0 ) {
    if ( instance()->mDataDirs.isEmpty() ) {
      QStringList dataDirs = instance()->systemPathList( "XDG_DATA_DIRS", "/usr/local/share:/usr/share" );

#ifdef Q_OS_WIN
      const QString prefixDataDir = QLatin1String( AKONADIPREFIX "/" AKONADIDATA );
#else
      const QString prefixDataDir = QLatin1String( AKONADIDATA );
#endif
      if ( !dataDirs.contains( prefixDataDir ) ) {
        dataDirs << prefixDataDir;
      }

      // fallback for users with KDE in a different prefix and not correctly set up XDG_DATA_DIRS, hi David ;-)
      QProcess proc;
      // ### should probably rather be --path xdg-something
      const QStringList args = QStringList() << QLatin1String( "--prefix" );
      proc.start( QLatin1String( "kde4-config" ), args );
      if ( proc.waitForStarted() && proc.waitForFinished() && proc.exitCode() == 0 ) {
        proc.setReadChannel( QProcess::StandardOutput );
        foreach ( const QString &basePath, splitPathList( QString::fromLocal8Bit( proc.readLine().trimmed() ) ) ) {
          const QString path = basePath + QDir::separator() + QLatin1String( "share" );
          if ( !dataDirs.contains( path ) )
            dataDirs << path;
        }
      }

      instance()->mDataDirs = dataDirs;
    }
    return instance()->mDataDirs;
  } else if ( qstrncmp( "config", resource, 6 ) == 0 ) {
    if ( instance()->mConfigDirs.isEmpty() ) {
      QStringList configDirs = instance()->systemPathList( "XDG_CONFIG_DIRS", "/etc/xdg" );

#ifdef Q_OS_WIN
      const QString prefixConfigDir = QLatin1String( AKONADIPREFIX "/" AKONADICONFIG );
#else
      const QString prefixConfigDir = QLatin1String( AKONADICONFIG );
#endif
      if ( !configDirs.contains( prefixConfigDir ) ) {
        configDirs << prefixConfigDir;
      }

      instance()->mConfigDirs = configDirs;
    }
    return instance()->mConfigDirs;
  }

  return QStringList();
}

QString XdgBaseDirs::findResourceFile( const char *resource, const QString &relPath )
{
  QString fullPath = homePath( resource ) + QLatin1Char('/' ) + relPath;

  QFileInfo fileInfo( fullPath );
  if ( fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable() ) {
    return fullPath;
  }

  QStringList pathList = systemPathList( resource );

  QStringList::const_iterator it    = pathList.constBegin();
  QStringList::const_iterator endIt = pathList.constEnd();
  for ( ; it != endIt; ++it ) {
    fileInfo = QFileInfo( *it + QLatin1Char('/' ) + relPath );
    if ( fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable() ) {
      return fileInfo.absoluteFilePath();
    }
  }

  return QString();
}

QString XdgBaseDirs::findExecutableFile( const QString &relPath, const QStringList &searchPath )
{
  if ( instance()->mExecutableDirs.isEmpty() ) {
    QStringList executableDirs = instance()->systemPathList( "PATH", "/usr/local/bin:/usr/bin" );

    const QString prefixExecutableDir = QLatin1String( AKONADIPREFIX "/bin" );
    if ( !executableDirs.contains( prefixExecutableDir ) ) {
      executableDirs << prefixExecutableDir;
    }

    if ( QCoreApplication::instance() != 0 ) {
        const QString appExecutableDir = QCoreApplication::instance()->applicationDirPath();
        if ( !executableDirs.contains( appExecutableDir ) ) {
          executableDirs << appExecutableDir;
        }
    }

    executableDirs += searchPath;

#if defined(Q_OS_MAC) //krazy:exclude=cpp
    executableDirs += QLatin1String(AKONADIBUNDLEPATH);
#endif
    qWarning( ) << "search paths: " << executableDirs;

    instance()->mExecutableDirs = executableDirs;
  }

  QStringList::const_iterator pathIt    = instance()->mExecutableDirs.constBegin();
  QStringList::const_iterator pathEndIt = instance()->mExecutableDirs.constEnd();
  for ( ; pathIt != pathEndIt; ++pathIt ) {
    QStringList fullPathList = alternateExecPaths(*pathIt + QLatin1Char( '/' ) + relPath );

{'fraction_non_alphanumeric': 0.13830872848493095, 'fraction_numerical': 0.006190897339955099, 'mean_word_length': 3.0329218106995883, 'pattern_counts': {'":': 0, '<': 62, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4970396', 'n_tokens_mistral': 4554, 'n_tokens_neox': 4388, 'n_words': 1095}