<commit_before>// KMail Account Manager

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "kmacctmgr.h"

#include "kmacctmaildir.h"
#include "kmacctlocal.h"
#include "kmacctexppop.h"
#include "kmacctimap.h"
#include "networkaccount.h"
using KMail::NetworkAccount;
#include "kmacctcachedimap.h"
#include "broadcaststatus.h"
#include "kmfiltermgr.h"
#include "globalsettings.h"

#include <klocale.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <kconfig.h>
#include <kapplication.h>

#include <qregexp.h>
#include <qvaluelist.h>

using KPIM::BroadcastStatus;

//-----------------------------------------------------------------------------
KMAcctMgr::KMAcctMgr(): QObject()
{
  mAcctList.setAutoDelete(TRUE);
  mAcctChecking.clear();
  mAcctTodo.clear();
  mTotalNewMailsArrived=0;
  mDisplaySummary = false;
}

//-----------------------------------------------------------------------------
KMAcctMgr::~KMAcctMgr()
{
  writeConfig(FALSE);
}

//-----------------------------------------------------------------------------
void KMAcctMgr::writeConfig(bool withSync)
{
  KConfig* config = KMKernel::config();
  QString groupName;

  KConfigGroupSaver saver(config, "General");
  config->writeEntry("accounts", mAcctList.count());

  // first delete all account groups in the config file:
  QStringList accountGroups =
    config->groupList().grep( QRegExp( "Account \\d+" ) );
  for ( QStringList::Iterator it = accountGroups.begin() ;
	it != accountGroups.end() ; ++it )
    config->deleteGroup( *it );

  // now write new account groups:
  int i = 1;
  for ( QPtrListIterator<KMAccount> it(mAcctList) ;
	it.current() ; ++it, ++i ) {
    groupName.sprintf("Account %d", i);
    KConfigGroupSaver saver(config, groupName);
    (*it)->writeConfig(*config);
  }
  if (withSync) config->sync();
}

//-----------------------------------------------------------------------------
void KMAcctMgr::readConfig(void)
{
  KConfig* config = KMKernel::config();
  KMAccount* acct;
  QString acctType, acctName;
  QCString groupName;
  int i, num;
  uint id;

  mAcctList.clear();

  KConfigGroup general(config, "General");
  num = general.readNumEntry("accounts", 0);

  for (i=1; i<=num; i++)
  {
    groupName.sprintf("Account %d", i);
    KConfigGroupSaver saver(config, groupName);
    acctType = config->readEntry("Type");
    // Provide backwards compatibility
    if (acctType == "advanced pop" || acctType == "experimental pop")
      acctType = "pop";
    acctName = config->readEntry("Name");
    id = config->readUnsignedNumEntry("Id", 0);
    if (acctName.isEmpty()) acctName = i18n("Account %1").arg(i);
    acct = create(acctType, acctName, id);
    if (!acct) continue;
    add(acct);
    acct->readConfig(*config);
  }
}

//-----------------------------------------------------------------------------
void KMAcctMgr::singleCheckMail(KMAccount *account, bool _interactive)
{
  newMailArrived = false;
  interactive = _interactive;

  // queue the account
  mAcctTodo.append(account);

  if (account->checkingMail())
  {
    kdDebug(5006) << "account " << account->name() << " busy, queuing" << endl;
    return;
  }

  processNextCheck(false);
}

//-----------------------------------------------------------------------------
void KMAcctMgr::processNextCheck(bool _newMail)
{
  kdDebug(5006) << "processNextCheck, remaining " << mAcctTodo.count() << endl;
  KMAccount *curAccount = 0;
  newMailArrived |= _newMail;

  KMAccount* acct;
  for ( acct = mAcctChecking.first(); acct; acct = mAcctChecking.next() )
  {
    if ( !acct->checkingMail() )
    {
      // check done
      kdDebug(5006) << "account " << acct->name() << " finished check" << endl;
      mAcctChecking.removeRef( acct );
      kmkernel->filterMgr()->deref();
      disconnect( acct, SIGNAL( finishedCheck( bool, CheckStatus ) ),
                  this, SLOT( processNextCheck( bool ) ) );
      QString hostname = hostForAccount( acct );
      if ( !hostname.isEmpty() ) {
        if ( mServerConnections.find( hostname ) != mServerConnections.end() ) {
          mServerConnections[hostname] -= 1;
          kdDebug(5006) << "connections to server " << hostname
                        << " now " << mServerConnections[hostname] << endl;
        }
      }
    }
  }
  if (mAcctChecking.isEmpty())
  {
    // all checks finished, display summary
    if ( mDisplaySummary )
      BroadcastStatus::instance()->setStatusMsgTransmissionCompleted(
          mTotalNewMailsArrived );
    emit checkedMail( newMailArrived, interactive, mTotalNewInFolder );
    mTotalNewMailsArrived = 0;
    mTotalNewInFolder.clear();
    mDisplaySummary = false;
  }
  if (mAcctTodo.isEmpty()) return;

  QString accountHostName;

  curAccount = 0;
  KMAcctList::Iterator it ( mAcctTodo.begin() );
  KMAcctList::Iterator last ( mAcctTodo.end() );
  for ( ; it != last; it++ )
  {
    accountHostName = hostForAccount(*it);
    kdDebug(5006) << "for host " << accountHostName
                  << " current connections="
                  << (mServerConnections.find(accountHostName)==mServerConnections.end() ? 0 : mServerConnections[accountHostName])
                  << " and limit is " << GlobalSettings::maxConnectionsPerHost()
                  << endl;
    bool connectionLimitForHostReached =
      !accountHostName.isNull() &&
      GlobalSettings::maxConnectionsPerHost() > 0 &&
      mServerConnections.find( accountHostName ) != mServerConnections.end() &&
      mServerConnections[accountHostName] >= GlobalSettings::maxConnectionsPerHost();
    kdDebug(5006) << "connection limit reached: "
                  << connectionLimitForHostReached << endl;
    if ( !(*it)->checkingMail() && !connectionLimitForHostReached ) {
      curAccount = (*it);
      mAcctTodo.remove( curAccount );
      break;
    }
  }
  if ( !curAccount ) return; // no account or all of them are already checking

  if (curAccount->type() != "imap" && curAccount->type() != "cachedimap" &&
      curAccount->folder() == 0)
  {
    QString tmp = i18n("Account %1 has no mailbox defined:\n"
        "mail checking aborted;\n"
        "check your account settings.")
      .arg(curAccount->name());
    KMessageBox::information(0,tmp);
    emit checkedMail( false, interactive, mTotalNewInFolder );
    mTotalNewMailsArrived = 0;
    mTotalNewInFolder.clear();
    return;
  }

  connect( curAccount, SIGNAL( finishedCheck( bool, CheckStatus ) ),
	   this, SLOT( processNextCheck( bool ) ) );

  BroadcastStatus::instance()->setStatusMsg(
      i18n("Checking account %1 for new mail").arg(curAccount->name()));

  kdDebug(5006) << "processing next mail check for " << curAccount->name() << endl;

  curAccount->setCheckingMail(true);
  mAcctChecking.append(curAccount);
  kmkernel->filterMgr()->ref();
  curAccount->processNewMail(interactive);

  if ( !accountHostName.isEmpty() ) {
    if ( mServerConnections.find( accountHostName ) != mServerConnections.end() )
      mServerConnections[accountHostName] += 1;
    else
      mServerConnections[accountHostName] = 1;
    kdDebug(5006) << "check mail started - connections for host "
                  << accountHostName << " now is "
                  << mServerConnections[accountHostName] << endl;
  }
}

//-----------------------------------------------------------------------------
KMAccount* KMAcctMgr::create(const QString &aType, const QString &aName, uint id)
{
  KMAccount* act = 0;
  if (id == 0)
    id = createId();

  if (aType == "local")
    act = new KMAcctLocal(this, aName.isEmpty() ? i18n("Local Account") : aName, id);

  if (aType == "maildir")
    act = new KMAcctMaildir(this, aName.isEmpty() ? i18n("Local Account") : aName, id);

  else if (aType == "pop")
    act = new KMAcctExpPop(this, aName.isEmpty() ? i18n("POP Account") : aName, id);

  else if (aType == "imap")
    act = new KMAcctImap(this, aName.isEmpty() ? i18n("IMAP Account") : aName, id);

  else if (aType == "cachedimap")
    act = new KMAcctCachedImap(this, aName.isEmpty() ? i18n("Disconnected IMAP") : aName, id);

  if (act)
  {
    if (aType != "imap" && aType != "cachedimap")
      act->setFolder(kmkernel->inboxFolder());
    connect( act, SIGNAL( newMailsProcessed( const QMap<QString, int> & ) ),
             this, SLOT( addToTotalNewMailCount( const QMap<QString, int> & ) ) );
  }

  return act;
}

//-----------------------------------------------------------------------------
void KMAcctMgr::add(KMAccount *account)
{
  if (account) {
    mAcctList.append( account );
    emit accountAdded( account );
  }
}

//-----------------------------------------------------------------------------
KMAccount* KMAcctMgr::findByName(const QString &aName)
{
  if (aName.isEmpty()) return 0;

  for ( QPtrListIterator<KMAccount> it(mAcctList) ; it.current() ; ++it )
  {
    if ((*it)->name() == aName) return (*it);
  }

  return 0;
}

//-----------------------------------------------------------------------------
KMAccount* KMAcctMgr::find(const uint id)
{
  if (id == 0) return 0;

  for ( QPtrListIterator<KMAccount> it(mAcctList) ; it.current() ; ++it )
  {
    if ((*it)->id() == id) return (*it);
  }

  return 0;
}

//-----------------------------------------------------------------------------
KMAccount* KMAcctMgr::first(void)
{
  return mAcctList.first();
}

//-----------------------------------------------------------------------------
KMAccount* KMAcctMgr::next(void)
{
  return mAcctList.next();
}

//-----------------------------------------------------------------------------
bool KMAcctMgr::remove( KMAccount* acct )
{
  if( !acct )
    return false;
  mAcctList.removeRef( acct );
  emit accountRemoved( acct );
  return true;
}

//-----------------------------------------------------------------------------
void KMAcctMgr::checkMail(bool _interactive)
{
  newMailArrived = false;

  if (mAcctList.isEmpty())
  {
    KMessageBox::information(0,i18n("You need to add an account in the network "
				    "section of the settings in order to "
				    "receive mail."));
    return;
  }
  mDisplaySummary = true;

  mTotalNewMailsArrived=0;
  mTotalNewInFolder.clear();

  for ( QPtrListIterator<KMAccount> it(mAcctList) ;
        it.current() ; ++it )
  {
    if (!it.current()->checkExclude())
      singleCheckMail(it.current(), _interactive);
  }
}

//-----------------------------------------------------------------------------
void KMAcctMgr::singleInvalidateIMAPFolders(KMAccount *account) {
  account->invalidateIMAPFolders();
}

void KMAcctMgr::invalidateIMAPFolders()
{
  if (mAcctList.isEmpty()) {
    KMessageBox::information(0,i18n("You need to add an account in the network "
                                   "section of the settings in order to "
                                   "receive mail."));
    return;
  }

  for ( QPtrListIterator<KMAccount> it(mAcctList) ; it.current() ; ++it )
    singleInvalidateIMAPFolders(it.current());
}

//-----------------------------------------------------------------------------
QStringList  KMAcctMgr::getAccounts(bool noImap) {

  KMAccount *cur;
  QStringList strList;
  for (cur=mAcctList.first(); cur; cur=mAcctList.next()) {
    if (!noImap || cur->type() != "imap") strList.append(cur->name());
  }

  return strList;

}

//-----------------------------------------------------------------------------
void KMAcctMgr::intCheckMail(int item, bool _interactive)
{
  KMAccount* cur;
  newMailArrived = false;

  mTotalNewMailsArrived = 0;
  mTotalNewInFolder.clear();
  int x = 0;
  cur = mAcctList.first();
  while (cur)
  {
    x++;
    if (x > item) break;
    cur=mAcctList.next();
  }
  mDisplaySummary = false;

  singleCheckMail(cur, _interactive);
}

//-----------------------------------------------------------------------------
void KMAcctMgr::addToTotalNewMailCount( const QMap<QString, int> & newInFolder )
{
  for ( QMap<QString, int>::const_iterator it = newInFolder.begin();
        it != newInFolder.end();
        ++it )
  {
    mTotalNewMailsArrived += it.data();
    if ( mTotalNewInFolder.find( it.key() ) == mTotalNewInFolder.end() )
      mTotalNewInFolder[it.key()] = it.data();
    else
      mTotalNewInFolder[it.key()] += it.data();
  }
}

//-----------------------------------------------------------------------------
uint KMAcctMgr::createId()
{
  QValueList<uint> usedIds;
  for ( QPtrListIterator<KMAccount> it(mAcctList) ; it.current() ; ++it )
    usedIds << it.current()->id();

  usedIds << 0; // 0 is default for unknown
  int newId;
  do
  {
    newId = kapp->random();
  } while ( usedIds.find(newId) != usedIds.end() );

  return newId;
}

//-----------------------------------------------------------------------------
void KMAcctMgr::cancelMailCheck()
{
  for ( QPtrListIterator<KMAccount> it(mAcctList) ;
	it.current() ; ++it ) {
    it.current()->cancelMailCheck();
  }
}

//-----------------------------------------------------------------------------
QString KMAcctMgr::hostForAccount( const KMAccount *acct ) const
{
  const NetworkAccount *net_acct = dynamic_cast<const NetworkAccount*>( acct );
  return net_acct ? net_acct->host() : QString::null;
}

#include "kmacctmgr.moc"
<commit_msg>Also use 'IMAP Account' as default name for disc. IMAP.<commit_after>// KMail Account Manager

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "kmacctmgr.h"

#include "kmacctmaildir.h"
#include "kmacctlocal.h"
#include "kmacctexppop.h"
#include "kmacctimap.h"
#include "networkaccount.h"
using KMail::NetworkAccount;
#include "kmacctcachedimap.h"
#include "broadcaststatus.h"
#include "kmfiltermgr.h"
#include "globalsettings.h"

#include <klocale.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <kconfig.h>
#include <kapplication.h>

#include <qregexp.h>
#include <qvaluelist.h>

using KPIM::BroadcastStatus;

//-----------------------------------------------------------------------------
KMAcctMgr::KMAcctMgr(): QObject()
{
  mAcctList.setAutoDelete(TRUE);
  mAcctChecking.clear();
  mAcctTodo.clear();
  mTotalNewMailsArrived=0;
  mDisplaySummary = false;
}

//-----------------------------------------------------------------------------
KMAcctMgr::~KMAcctMgr()
{
  writeConfig(FALSE);
}

//-----------------------------------------------------------------------------
void KMAcctMgr::writeConfig(bool withSync)
{
  KConfig* config = KMKernel::config();
  QString groupName;

  KConfigGroupSaver saver(config, "General");
  config->writeEntry("accounts", mAcctList.count());

  // first delete all account groups in the config file:
  QStringList accountGroups =
    config->groupList().grep( QRegExp( "Account \\d+" ) );
  for ( QStringList::Iterator it = accountGroups.begin() ;
	it != accountGroups.end() ; ++it )
    config->deleteGroup( *it );

  // now write new account groups:
  int i = 1;
  for ( QPtrListIterator<KMAccount> it(mAcctList) ;
	it.current() ; ++it, ++i ) {
    groupName.sprintf("Account %d", i);
    KConfigGroupSaver saver(config, groupName);
    (*it)->writeConfig(*config);
  }
  if (withSync) config->sync();
}

//-----------------------------------------------------------------------------
void KMAcctMgr::readConfig(void)
{
  KConfig* config = KMKernel::config();
  KMAccount* acct;
  QString acctType, acctName;
  QCString groupName;
  int i, num;
  uint id;

  mAcctList.clear();

  KConfigGroup general(config, "General");
  num = general.readNumEntry("accounts", 0);

  for (i=1; i<=num; i++)
  {
    groupName.sprintf("Account %d", i);
    KConfigGroupSaver saver(config, groupName);
    acctType = config->readEntry("Type");
    // Provide backwards compatibility
    if (acctType == "advanced pop" || acctType == "experimental pop")
      acctType = "pop";
    acctName = config->readEntry("Name");
    id = config->readUnsignedNumEntry("Id", 0);
    if (acctName.isEmpty()) acctName = i18n("Account %1").arg(i);
    acct = create(acctType, acctName, id);
    if (!acct) continue;
    add(acct);
    acct->readConfig(*config);
  }
}

//-----------------------------------------------------------------------------
void KMAcctMgr::singleCheckMail(KMAccount *account, bool _interactive)
{
  newMailArrived = false;
  interactive = _interactive;

  // queue the account
  mAcctTodo.append(account);

  if (account->checkingMail())
  {
    kdDebug(5006) << "account " << account->name() << " busy, queuing" << endl;
    return;
  }

  processNextCheck(false);
}

//-----------------------------------------------------------------------------
void KMAcctMgr::processNextCheck(bool _newMail)
{
  kdDebug(5006) << "processNextCheck, remaining " << mAcctTodo.count() << endl;
  KMAccount *curAccount = 0;
  newMailArrived |= _newMail;

  KMAccount* acct;
  for ( acct = mAcctChecking.first(); acct; acct = mAcctChecking.next() )
  {
    if ( !acct->checkingMail() )
    {
      // check done
      kdDebug(5006) << "account " << acct->name() << " finished check" << endl;
      mAcctChecking.removeRef( acct );
      kmkernel->filterMgr()->deref();
      disconnect( acct, SIGNAL( finishedCheck( bool, CheckStatus ) ),
                  this, SLOT( processNextCheck( bool ) ) );
      QString hostname = hostForAccount( acct );
      if ( !hostname.isEmpty() ) {
        if ( mServerConnections.find( hostname ) != mServerConnections.end() ) {
          mServerConnections[hostname] -= 1;
          kdDebug(5006) << "connections to server " << hostname
                        << " now " << mServerConnections[hostname] << endl;
        }
      }
    }
  }
  if (mAcctChecking.isEmpty())
  {
    // all checks finished, display summary
    if ( mDisplaySummary )
      BroadcastStatus::instance()->setStatusMsgTransmissionCompleted(
          mTotalNewMailsArrived );
    emit checkedMail( newMailArrived, interactive, mTotalNewInFolder );
    mTotalNewMailsArrived = 0;
    mTotalNewInFolder.clear();
    mDisplaySummary = false;
  }
  if (mAcctTodo.isEmpty()) return;

  QString accountHostName;

  curAccount = 0;
  KMAcctList::Iterator it ( mAcctTodo.begin() );
  KMAcctList::Iterator last ( mAcctTodo.end() );
  for ( ; it != last; it++ )
  {
    accountHostName = hostForAccount(*it);
    kdDebug(5006) << "for host " << accountHostName
                  << " current connections="
                  << (mServerConnections.find(accountHostName)==mServerConnections.end() ? 0 : mServerConnections[accountHostName])
                  << " and limit is " << GlobalSettings::maxConnectionsPerHost()
                  << endl;
    bool connectionLimitForHostReached =
      !accountHostName.isNull() &&
      GlobalSettings::maxConnectionsPerHost() > 0 &&
      mServerConnections.find( accountHostName ) != mServerConnections.end() &&
      mServerConnections[accountHostName] >= GlobalSettings::maxConnectionsPerHost();
    kdDebug(5006) << "connection limit reached: "
                  << connectionLimitForHostReached << endl;
    if ( !(*it)->checkingMail() && !connectionLimitForHostReached ) {
      curAccount = (*it);
      mAcctTodo.remove( curAccount );
      break;
    }
  }
  if ( !curAccount ) return; // no account or all of them are already checking

  if (curAccount->type() != "imap" && curAccount->type() != "cachedimap" &&
      curAccount->folder() == 0)
  {
    QString tmp = i18n("Account %1 has no mailbox defined:\n"
        "mail checking aborted;\n"
        "check your account settings.")
      .arg(curAccount->name());
    KMessageBox::information(0,tmp);
    emit checkedMail( false, interactive, mTotalNewInFolder );
    mTotalNewMailsArrived = 0;
    mTotalNewInFolder.clear();
    return;
  }

  connect( curAccount, SIGNAL( finishedCheck( bool, CheckStatus ) ),
	   this, SLOT( processNextCheck( bool ) ) );

  BroadcastStatus::instance()->setStatusMsg(
      i18n("Checking account %1 for new mail").arg(curAccount->name()));

  kdDebug(5006) << "processing next mail check for " << curAccount->name() << endl;

  curAccount->setCheckingMail(true);
  mAcctChecking.append(curAccount);
  kmkernel->filterMgr()->ref();
  curAccount->processNewMail(interactive);

  if ( !accountHostName.isEmpty() ) {
    if ( mServerConnections.find( accountHostName ) != mServerConnections.end() )
      mServerConnections[accountHostName] += 1;
    else
      mServerConnections[accountHostName] = 1;
    kdDebug(5006) << "check mail started - connections for host "
                  << accountHostName << " now is "
                  << mServerConnections[accountHostName] << endl;
  }
}

//-----------------------------------------------------------------------------
KMAccount* KMAcctMgr::create(const QString &aType, const QString &aName, uint id)
{
  KMAccount* act = 0;
  if (id == 0)
    id = createId();

  if (aType == "local")
    act = new KMAcctLocal(this, aName.isEmpty() ? i18n("Local Account") : aName, id);

  if (aType == "maildir")
    act = new KMAcctMaildir(this, aName.isEmpty() ? i18n("Local Account") : aName, id);

  else if (aType == "pop")
    act = new KMAcctExpPop(this, aName.isEmpty() ? i18n("POP Account") : aName, id);

  else if (aType == "imap")
    act = new KMAcctImap(this, aName.isEmpty() ? i18n("IMAP Account") : aName, id);

  else if (aType == "cachedimap")
    act = new KMAcctCachedImap(this, aName.isEmpty() ? i18n("IMAP Account") : aName, id);

  if (act)
  {
    if (aType != "imap" && aType != "cachedimap")
      act->setFolder(kmkernel->inboxFolder());
    connect( act, SIGNAL( newMailsProcessed( const QMap<QString, int> & ) ),
             this, SLOT( addToTotalNewMailCount( const QMap<QString, int> & ) ) );
  }

  return act;
}

//-----------------------------------------------------------------------------
void KMAcctMgr::add(KMAccount *account)
{
  if (account) {
    mAcctList.append( account );
    emit accountAdded( account );
  }
}

//-----------------------------------------------------------------------------
KMAccount* KMAcctMgr::findByName(const QString &aName)
{
  if (aName.isEmpty()) return 0;

  for ( QPtrListIterator<KMAccount> it(mAcctList) ; it.current() ; ++it )
  {
    if ((*it)->name() == aName) return (*it);
  }

  return 0;
}

//-----------------------------------------------------------------------------
KMAccount* KMAcctMgr::find(const uint id)
{
  if (id == 0) return 0;

  for ( QPtrListIterator<KMAccount> it(mAcctList) ; it.current() ; ++it )
  {
    if ((*it)->id() == id) return (*it);
  }

  return 0;
}

//-----------------------------------------------------------------------------
KMAccount* KMAcctMgr::first(void)
{
  return mAcctList.first();
}

//-----------------------------------------------------------------------------
KMAccount* KMAcctMgr::next(void)
{
  return mAcctList.next();
}

//-----------------------------------------------------------------------------
bool KMAcctMgr::remove( KMAccount* acct )
{
  if( !acct )
    return false;
  mAcctList.removeRef( acct );
  emit accountRemoved( acct );
  return true;
}

//-----------------------------------------------------------------------------
void KMAcctMgr::checkMail(bool _interactive)
{
  newMailArrived = false;

  if (mAcctList.isEmpty())
  {
    KMessageBox::information(0,i18n("You need to add an account in the network "
				    "section of the settings in order to "
				    "receive mail."));
    return;
  }
  mDisplaySummary = true;

  mTotalNewMailsArrived=0;
  mTotalNewInFolder.clear();

  for ( QPtrListIterator<KMAccount> it(mAcctList) ;
        it.current() ; ++it )
  {
    if (!it.current()->checkExclude())
      singleCheckMail(it.current(), _interactive);
  }
}

//-----------------------------------------------------------------------------
void KMAcctMgr::singleInvalidateIMAPFolders(KMAccount *account) {
  account->invalidateIMAPFolders();
}

void KMAcctMgr::invalidateIMAPFolders()
{
  if (mAcctList.isEmpty()) {
    KMessageBox::information(0,i18n("You need to add an account in the network "
                                   "section of the settings in order to "
                                   "receive mail."));
    return;
  }

  for ( QPtrListIterator<KMAccount> it(mAcctList) ; it.current() ; ++it )
    singleInvalidateIMAPFolders(it.current());
}

//-----------------------------------------------------------------------------
QStringList  KMAcctMgr::getAccounts(bool noImap) {

  KMAccount *cur;
  QStringList strList;
  for (cur=mAcctList.first(); cur; cur=mAcctList.next()) {
    if (!noImap || cur->type() != "imap") strList.append(cur->name());
  }

  return strList;

}

//-----------------------------------------------------------------------------
void KMAcctMgr::intCheckMail(int item, bool _interactive)
{
  KMAccount* cur;
  newMailArrived = false;

  mTotalNewMailsArrived = 0;
  mTotalNewInFolder.clear();
  int x = 0;
  cur = mAcctList.first();
  while (cur)
  {
    x++;
    if (x > item) break;
    cur=mAcctList.next();
  }
  mDisplaySummary = false;

  singleCheckMail(cur, _interactive);
}

//-----------------------------------------------------------------------------
void KMAcctMgr::addToTotalNewMailCount( const QMap<QString, int> & newInFolder )
{
  for ( QMap<QString, int>::const_iterator it = newInFolder.begin();
        it != newInFolder.end();
        ++it )
  {
    mTotalNewMailsArrived += it.data();
    if ( mTotalNewInFolder.find( it.key() ) == mTotalNewInFolder.end() )
      mTotalNewInFolder[it.key()] = it.data();
    else
      mTotalNewInFolder[it.key()] += it.data();
  }
}

//-----------------------------------------------------------------------------
uint KMAcctMgr::createId()
{
  QValueList<uint> usedIds;
  for ( QPtrListIterator<KMAccount> it(mAcctList) ; it.current() ; ++it )
    usedIds << it.current()->id();

  usedIds << 0; // 0 is default for unknown
  int newId;
  do
  {
    newId = kapp->random();
  } while ( usedIds.find(newId) != usedIds.end() );

  return newId;
}

//-----------------------------------------------------------------------------
void KMAcctMgr::cancelMailCheck()
{
  for ( QPtrListIterator<KMAccount> it(mAcctList) ;
	it.current() ; ++it ) {
    it.current()->cancelMailCheck();
  }
}

//-----------------------------------------------------------------------------
QString KMAcctMgr::hostForAccount( const KMAccount *acct ) const
{
  const NetworkAccount *net_acct = dynamic_cast<const NetworkAccount*>( acct );
  return net_acct ? net_acct->host() : QString::null;
}

#include "kmacctmgr.moc"
<|endoftext|>


<commit_before>#include <libmemcached/memcached.h>

#include <string>
#include <vector>

class Memcached
{
public:

  Memcached()
    :
      memc(),
      result()
  {
    memcached_create(&memc);
  }

  Memcached(memcached_st *clone)
    :
      memc(),
      result()
  {
    memcached_clone(&memc, clone);
  }

  ~Memcached()
  {
    memcached_free(&memc);
  }

  bool fetch(std::string &key,
             std::string &ret_val,
             size_t *key_length,
             size_t *value_length,
             uint32_t *flags,
             memcached_return *rc)
  {
    char ret_key[MEMCACHED_MAX_KEY];
    char *value= memcached_fetch(&memc, ret_key, key_length,
                                 value_length, flags, rc);
    if (value)
    {
      ret_val.assign(value);
      key.assign(ret_key);
      return true;
    }
    return false;
  }

  std::string get(const std::string &key, size_t *value_length)
  {
    uint32_t flags;
    memcached_return rc;
    std::string ret_val;

    char *value= memcached_get(&memc, key.c_str(), key.length(),
                               value_length, &flags, &rc);
    if (value)
    {
      ret_val.assign(value);
    }
    return ret_val;
  }

  std::string get_by_key(const std::string &master_key,
                         const std::string &key,
                         size_t *value_length)
  {
    uint32_t flags;
    memcached_return rc;
    std::string ret_val;

    char *value= memcached_get_by_key(&memc, master_key.c_str(), master_key.length(),
                                      key.c_str(), key.length(),
                                      value_length, &flags, &rc);
    if (value)
    {
      ret_val.assign(value);
    }
    return ret_val;
  }

  bool mget(std::vector<std::string> &keys)
  {
    std::vector<const char *> real_keys;
    std::vector<size_t> key_len;
    /*
     * Construct an array which will contain the length
     * of each of the strings in the input vector. Also, to
     * interface with the memcached C API, we need to convert
     * the vector of std::string's to a vector of char *.
     */
    real_keys.reserve(keys.size());
    key_len.reserve(keys.size());

    std::vector<std::string>::iterator it= keys.begin();

    while (it != keys.end())
    {
      real_keys.push_back(const_cast<char *>((*it).c_str()));
      key_len.push_back((*it).length());
      ++it;
    }

    /*
     * If the std::vector of keys is empty then we cannot
     * call memcached_mget as we will get undefined behavior.
     */
    if (!real_keys.empty())
    {
      memcached_return rc= memcached_mget(&memc, &real_keys[0], &key_len[0],
                                          real_keys.size());
      return (rc == MEMCACHED_SUCCESS);
    }

    return false;
  }

  bool set(const std::string &key,
           const std::string &value,
           time_t expiration,
           uint32_t flags)
  {
    memcached_return rc= memcached_set(&memc,
                                       key.c_str(), key.length(),
                                       value.c_str(), value.length(),
                                       expiration, flags);
    return (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
  }

  bool set_all(std::vector<std::string> &keys,
               std::vector<std::string> &values,
               time_t expiration,
               uint32_t flags)
  {
    if (keys.size() != values.size())
    {
      return false;
    }
    bool retval= true;
    std::vector<std::string>::iterator key_it= keys.begin();
    std::vector<std::string>::iterator val_it= values.begin();
    while (key_it != keys.end())
    {
      retval= set((*key_it), (*val_it), expiration, flags);
      if (retval == false)
      {
        return retval;
      }
      ++key_it;
      ++val_it;
    }
    return retval;
  }

  bool set_by_key(const std::string &master_key,
                  const std::string &key,
                  const std::string &value,
                  time_t expiration,
                  uint32_t flags)
  {
    memcached_return rc= memcached_set_by_key(&memc, master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(), key.length(),
                                              value.c_str(), value.length(),
                                              expiration,
                                              flags);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool increment(const std::string &key, unsigned int offset, uint64_t *value)
  {
    memcached_return rc= memcached_increment(&memc, key.c_str(), key.length(),
                                             offset, value);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool decrement(const std::string &key, unsigned int offset, uint64_t *value)
  {
    memcached_return rc= memcached_decrement(&memc, key.c_str(),
                                             key.length(),
                                             offset, value);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool add(const std::string &key, const std::string &value)
  {
    memcached_return rc= memcached_add(&memc, key.c_str(), key.length(),
                                       value.c_str(), value.length(), 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool add_by_key(const std::string &master_key,
                  const std::string &key,
                  const std::string &value)
  {
    memcached_return rc= memcached_add_by_key(&memc,
                                              master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(),
                                              key.length(),
                                              value.c_str(),
                                              value.length(),
                                              0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool replace(const std::string &key, const std::string &value)
  {
    memcached_return rc= memcached_replace(&memc, key.c_str(), key.length(),
                                           value.c_str(), value.length(),
                                           0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool replace_by_key(const std::string &master_key,
                      const std::string &key,
                      const std::string &value)
  {
    memcached_return rc= memcached_replace_by_key(&memc,
                                                  master_key.c_str(),
                                                  master_key.length(),
                                                  key.c_str(),
                                                  key.length(),
                                                  value.c_str(),
                                                  value.length(),
                                                  0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool prepend(const std::string &key, const std::string &value)
  {
    memcached_return rc= memcached_prepend(&memc, key.c_str(), key.length(),
                                           value.c_str(), value.length(), 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool prepend_by_key(const std::string &master_key,
                      const std::string &key,
                      const std::string &value)
  {
    memcached_return rc= memcached_prepend_by_key(&memc,
                                                  master_key.c_str(),
                                                  master_key.length(),
                                                  key.c_str(),
                                                  key.length(),
                                                  value.c_str(),
                                                  value.length(),
                                                  0,
                                                  0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool append(const std::string &key, const std::string &value)
  {
    memcached_return rc= memcached_append(&memc,
                                          key.c_str(),
                                          key.length(),
                                          value.c_str(),
                                          value.length(),
                                          0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool append_by_key(const std::string &master_key,
                     const std::string &key,
                     const std::string &value)
  {
    memcached_return rc= memcached_append_by_key(&memc,
                                                 master_key.c_str(),
                                                 master_key.length(),
                                                 key.c_str(),
                                                 key.length(),
                                                 value.c_str(),
                                                 value.length(),
                                                 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool cas(const std::string &key,
           const std::string &value,
           uint64_t cas_arg)
  {
    memcached_return rc= memcached_cas(&memc, key.c_str(), key.length(),
                                       value.c_str(), value.length(),
                                       0, 0, cas_arg);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool cas_by_key(const std::string &master_key,
                  const std::string &key,
                  const std::string &value,
                  uint64_t cas_arg)
  {
    memcached_return rc= memcached_cas_by_key(&memc,
                                              master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(),
                                              key.length(),
                                              value.c_str(),
                                              value.length(),
                                              0, 0, cas_arg);
    return (rc == MEMCACHED_SUCCESS);
  }

  // using 'remove' vs. 'delete' since 'delete' is a keyword
  bool remove(const std::string &key)
  {
    memcached_return rc= memcached_delete(&memc, key.c_str(), key.length(), 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool delete_by_key(const std::string &master_key,
                     const std::string &key)
  {
    memcached_return rc= memcached_delete_by_key(&memc,
                                                 master_key.c_str(),
                                                 master_key.length(),
                                                 key.c_str(),
                                                 key.length(),
                                                 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool flush(time_t expiration)
  {
    memcached_return rc= memcached_flush(&memc, expiration);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool fetch_execute(memcached_execute_function *callback,
                     void *context,
                     unsigned int num_of_callbacks)
  {
    memcached_return rc= memcached_fetch_execute(&memc,
                                                 callback,
                                                 context,
                                                 num_of_callbacks);
    return (rc == MEMCACHED_SUCCESS);
  }

  const std::string lib_version() const
  {
    const char *ver= memcached_lib_version();
    const std::string version(ver);
    return version;
  }

private:
  memcached_st memc;
  memcached_result_st result;
};
<commit_msg>Updated C++ interface to have include guards. Also modified the naming convention for the functions in the C++ interface. We should use camel case for the C++ interface.<commit_after>/*
 * Summary: C++ interface for memcached server
 *
 * Copy: See Copyright for the status of this software.
 *
 * Authors: Padraig O'Sullivan, Patrick Galbraith
 */

#ifndef LIBMEMCACHEDPP_H
#define LIBMEMCACHEDPP_H

#include <libmemcached/memcached.h>

#include <string>
#include <vector>

class Memcached
{
public:

  Memcached()
    :
      memc(),
      result()
  {
    memcached_create(&memc);
  }

  Memcached(memcached_st *clone)
    :
      memc(),
      result()
  {
    memcached_clone(&memc, clone);
  }

  ~Memcached()
  {
    memcached_free(&memc);
  }

  bool fetch(std::string &key,
             std::string &ret_val,
             size_t *key_length,
             size_t *value_length,
             uint32_t *flags,
             memcached_return *rc)
  {
    char ret_key[MEMCACHED_MAX_KEY];
    char *value= memcached_fetch(&memc, ret_key, key_length,
                                 value_length, flags, rc);
    if (value)
    {
      ret_val.assign(value);
      key.assign(ret_key);
      return true;
    }
    return false;
  }

  std::string get(const std::string &key, size_t *value_length)
  {
    uint32_t flags;
    memcached_return rc;
    std::string ret_val;

    char *value= memcached_get(&memc, key.c_str(), key.length(),
                               value_length, &flags, &rc);
    if (value)
    {
      ret_val.assign(value);
    }
    return ret_val;
  }

  std::string getByKey(const std::string &master_key,
                       const std::string &key,
                       size_t *value_length)
  {
    uint32_t flags;
    memcached_return rc;
    std::string ret_val;

    char *value= memcached_get_by_key(&memc,
                                      master_key.c_str(), master_key.length(),
                                      key.c_str(), key.length(),
                                      value_length, &flags, &rc);
    if (value)
    {
      ret_val.assign(value);
    }
    return ret_val;
  }

  bool mget(std::vector<std::string> &keys)
  {
    std::vector<const char *> real_keys;
    std::vector<size_t> key_len;
    /*
     * Construct an array which will contain the length
     * of each of the strings in the input vector. Also, to
     * interface with the memcached C API, we need to convert
     * the vector of std::string's to a vector of char *.
     */
    real_keys.reserve(keys.size());
    key_len.reserve(keys.size());

    std::vector<std::string>::iterator it= keys.begin();

    while (it != keys.end())
    {
      real_keys.push_back(const_cast<char *>((*it).c_str()));
      key_len.push_back((*it).length());
      ++it;
    }

    /*
     * If the std::vector of keys is empty then we cannot
     * call memcached_mget as we will get undefined behavior.
     */
    if (!real_keys.empty())
    {
      memcached_return rc= memcached_mget(&memc, &real_keys[0], &key_len[0],
                                          real_keys.size());
      return (rc == MEMCACHED_SUCCESS);
    }

    return false;
  }

  bool set(const std::string &key,
           const std::string &value,
           time_t expiration,
           uint32_t flags)
  {
    memcached_return rc= memcached_set(&memc,
                                       key.c_str(), key.length(),
                                       value.c_str(), value.length(),
                                       expiration, flags);
    return (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
  }

  bool setAll(std::vector<std::string> &keys,
              std::vector<std::string> &values,
              time_t expiration,
              uint32_t flags)
  {
    if (keys.size() != values.size())
    {
      return false;
    }
    bool retval= true;
    std::vector<std::string>::iterator key_it= keys.begin();
    std::vector<std::string>::iterator val_it= values.begin();
    while (key_it != keys.end())
    {
      retval= set((*key_it), (*val_it), expiration, flags);
      if (retval == false)
      {
        return retval;
      }
      ++key_it;
      ++val_it;
    }
    return retval;
  }

  bool setByKey(const std::string &master_key,
                const std::string &key,
                const std::string &value,
                time_t expiration,
                uint32_t flags)
  {
    memcached_return rc= memcached_set_by_key(&memc, master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(), key.length(),
                                              value.c_str(), value.length(),
                                              expiration,
                                              flags);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool increment(const std::string &key, unsigned int offset, uint64_t *value)
  {
    memcached_return rc= memcached_increment(&memc, key.c_str(), key.length(),
                                             offset, value);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool decrement(const std::string &key, unsigned int offset, uint64_t *value)
  {
    memcached_return rc= memcached_decrement(&memc, key.c_str(),
                                             key.length(),
                                             offset, value);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool add(const std::string &key, const std::string &value)
  {
    memcached_return rc= memcached_add(&memc, key.c_str(), key.length(),
                                       value.c_str(), value.length(), 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool addByKey(const std::string &master_key,
                const std::string &key,
                const std::string &value)
  {
    memcached_return rc= memcached_add_by_key(&memc,
                                              master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(),
                                              key.length(),
                                              value.c_str(),
                                              value.length(),
                                              0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool replace(const std::string &key, const std::string &value)
  {
    memcached_return rc= memcached_replace(&memc, key.c_str(), key.length(),
                                           value.c_str(), value.length(),
                                           0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool replaceByKey(const std::string &master_key,
                    const std::string &key,
                    const std::string &value)
  {
    memcached_return rc= memcached_replace_by_key(&memc,
                                                  master_key.c_str(),
                                                  master_key.length(),
                                                  key.c_str(),
                                                  key.length(),
                                                  value.c_str(),
                                                  value.length(),
                                                  0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool prepend(const std::string &key, const std::string &value)
  {
    memcached_return rc= memcached_prepend(&memc, key.c_str(), key.length(),
                                           value.c_str(), value.length(), 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool prependByKey(const std::string &master_key,
                    const std::string &key,
                    const std::string &value)
  {
    memcached_return rc= memcached_prepend_by_key(&memc,
                                                  master_key.c_str(),
                                                  master_key.length(),
                                                  key.c_str(),
                                                  key.length(),
                                                  value.c_str(),
                                                  value.length(),
                                                  0,
                                                  0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool append(const std::string &key, const std::string &value)
  {
    memcached_return rc= memcached_append(&memc,
                                          key.c_str(),
                                          key.length(),
                                          value.c_str(),
                                          value.length(),
                                          0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool appendByKey(const std::string &master_key,
                   const std::string &key,
                   const std::string &value)
  {
    memcached_return rc= memcached_append_by_key(&memc,
                                                 master_key.c_str(),
                                                 master_key.length(),
                                                 key.c_str(),
                                                 key.length(),
                                                 value.c_str(),
                                                 value.length(),
                                                 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool cas(const std::string &key,
           const std::string &value,
           uint64_t cas_arg)
  {
    memcached_return rc= memcached_cas(&memc, key.c_str(), key.length(),
                                       value.c_str(), value.length(),
                                       0, 0, cas_arg);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool casByKey(const std::string &master_key,
                const std::string &key,
                const std::string &value,
                uint64_t cas_arg)
  {
    memcached_return rc= memcached_cas_by_key(&memc,
                                              master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(),
                                              key.length(),
                                              value.c_str(),
                                              value.length(),
                                              0, 0, cas_arg);
    return (rc == MEMCACHED_SUCCESS);
  }

  // using 'remove' vs. 'delete' since 'delete' is a keyword
  bool remove(const std::string &key)
  {
    memcached_return rc= memcached_delete(&memc, key.c_str(), key.length(), 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool removeByKey(const std::string &master_key,
                   const std::string &key)
  {
    memcached_return rc= memcached_delete_by_key(&memc,
                                                 master_key.c_str(),
                                                 master_key.length(),
                                                 key.c_str(),
                                                 key.length(),
                                                 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool flush(time_t expiration)
  {
    memcached_return rc= memcached_flush(&memc, expiration);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool fetchExecute(memcached_execute_function *callback,
                    void *context,
                    unsigned int num_of_callbacks)
  {
    memcached_return rc= memcached_fetch_execute(&memc,
                                                 callback,
                                                 context,
                                                 num_of_callbacks);
    return (rc == MEMCACHED_SUCCESS);
  }

  const std::string libVersion() const
  {
    const char *ver= memcached_lib_version();
    const std::string version(ver);
    return version;
  }

private:
  memcached_st memc;
  memcached_result_st result;
};

#endif /* LIBMEMCACHEDPP_H */
<|endoftext|>


<commit_before>#include "ExecutionEngine.h"

#include <chrono>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/ADT/Triple.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/ExecutionEngine/GenericValue.h>
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Signals.h>
#include <llvm/Support/PrettyStackTrace.h>
#include <llvm/Support/Host.h>

#pragma GCC diagnostic pop

#include "Runtime.h"
#include "Memory.h"
#include "Stack.h"
#include "Type.h"
#include "Compiler.h"
#include "Cache.h"

namespace dev
{
namespace eth
{
namespace jit
{

ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env)
{
	std::string key{reinterpret_cast<char const*>(_code.data()), _code.size()};
	/*if (auto cachedExec = Cache::findExec(key))
	{
		return run(*cachedExec, _data, _env);
	}*/

	auto module = Compiler({}).compile(_code);
	//module->dump();
	return run(std::move(module), _data, _env, _code);
}

namespace
{

typedef ReturnCode(*EntryFuncPtr)(Runtime*);

ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime)
{
	// That function uses long jumps to handle "execeptions".
	// Do not create any non-POD objects here

	ReturnCode returnCode{};
	auto sj = setjmp(_runtime->getJmpBuf());
	if (sj == 0)
		returnCode = _mainFunc(_runtime);
	else
		returnCode = static_cast<ReturnCode>(sj);

	return returnCode;
}

}

ReturnCode ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, RuntimeData* _data, Env* _env, bytes const& _code)
{
	// TODO: Use it in evmcc
	//llvm::sys::PrintStackTraceOnErrorSignal();
	//static const auto program = "EVM JIT";
	//llvm::PrettyStackTraceProgram X(1, &program);

	static std::unique_ptr<llvm::ExecutionEngine> ee;  // TODO: Use Managed Objects from LLVM?

	typedef ReturnCode(*EntryFuncPtr)(Runtime*);
	EntryFuncPtr entryFuncPtr{};

	auto&& mainFuncName = _module->getModuleIdentifier();

	if (!ee)
	{
		llvm::InitializeNativeTarget();
		llvm::InitializeNativeTargetAsmPrinter();

		llvm::EngineBuilder builder(_module.get());
		builder.setEngineKind(llvm::EngineKind::JIT);
		builder.setUseMCJIT(true);
		std::unique_ptr<llvm::SectionMemoryManager> memoryManager(new llvm::SectionMemoryManager);
		builder.setMCJITMemoryManager(memoryManager.get());
		builder.setOptLevel(llvm::CodeGenOpt::None);

		auto triple = llvm::Triple(llvm::sys::getProcessTriple());
		if (triple.getOS() == llvm::Triple::OSType::Win32)
			triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF);  // MCJIT does not support COFF format
		_module->setTargetTriple(triple.str());

		ee.reset(builder.create());
		if (!ee)
			return ReturnCode::LLVMConfigError;

		_module.release();        // Successfully created llvm::ExecutionEngine takes ownership of the module
		memoryManager.release();  // and memory manager

		//ee->setObjectCache(Cache::getObjectCache());
	}
	else
	{
		if (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(_module->getModuleIdentifier()))
		{
			entryFuncPtr = nullptr;
		}
		else
		{
			ee->addModule(_module.get());
			//std::cerr << _module->getModuleIdentifier() << "\n";
			_module.release();
		}
	}

	assert(ee);

	//ExecBundle exec;
	//exec.engine.reset(builder.create());
	//if (!exec.engine)
	//	return ReturnCode::LLVMConfigError;

	// TODO: Finalization not needed when llvm::ExecutionEngine::getFunctionAddress used
	//auto finalizationStartTime = std::chrono::high_resolution_clock::now();
	//exec.engine->finalizeObject();
	//auto finalizationEndTime = std::chrono::high_resolution_clock::now();
	//clog(JIT) << " + " << std::chrono::duration_cast<std::chrono::milliseconds>(finalizationEndTime - finalizationStartTime).count();

	auto executionStartTime = std::chrono::high_resolution_clock::now();

	std::string key{reinterpret_cast<char const*>(_code.data()), _code.size()};
	//auto& cachedExec = Cache::registerExec(key, std::move(exec));
	Runtime runtime(_data, _env);
	auto mainFunc = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
	auto returnCode = runEntryFunc(mainFunc, &runtime);
	if (returnCode == ReturnCode::Return)
		this->returnData = runtime.getReturnData();

	auto executionEndTime = std::chrono::high_resolution_clock::now();
	clog(JIT) << " + " << std::chrono::duration_cast<std::chrono::milliseconds>(executionEndTime - executionStartTime).count() << " ms ";
	//clog(JIT) << "Max stack size: " << Stack::maxStackSize;

	clog(JIT) << "\n";

	return returnCode;
}

}
}
}
<commit_msg>Clean up ExecutionEngine<commit_after>#include "ExecutionEngine.h"

#include <chrono>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/ADT/Triple.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/ExecutionEngine/GenericValue.h>
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Signals.h>
#include <llvm/Support/PrettyStackTrace.h>
#include <llvm/Support/Host.h>

#pragma GCC diagnostic pop

#include "Runtime.h"
#include "Memory.h"
#include "Stack.h"
#include "Type.h"
#include "Compiler.h"
#include "Cache.h"

namespace dev
{
namespace eth
{
namespace jit
{

ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env)
{
	auto module = Compiler({}).compile(_code);
	//module->dump();
	return run(std::move(module), _data, _env, _code);
}

namespace
{

typedef ReturnCode(*EntryFuncPtr)(Runtime*);

ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime)
{
	// That function uses long jumps to handle "execeptions".
	// Do not create any non-POD objects here

	ReturnCode returnCode{};
	auto sj = setjmp(_runtime->getJmpBuf());
	if (sj == 0)
		returnCode = _mainFunc(_runtime);
	else
		returnCode = static_cast<ReturnCode>(sj);

	return returnCode;
}

}

ReturnCode ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, RuntimeData* _data, Env* _env, bytes const& _code)
{
	// TODO: Use it in evmcc
	//llvm::sys::PrintStackTraceOnErrorSignal();
	//static const auto program = "EVM JIT";
	//llvm::PrettyStackTraceProgram X(1, &program);

	static std::unique_ptr<llvm::ExecutionEngine> ee;  // TODO: Use Managed Objects from LLVM?

	EntryFuncPtr entryFuncPtr{};

	Runtime runtime(_data, _env);

	auto&& mainFuncName = _module->getModuleIdentifier();

	if (!ee)
	{
		llvm::InitializeNativeTarget();
		llvm::InitializeNativeTargetAsmPrinter();

		llvm::EngineBuilder builder(_module.get());
		builder.setEngineKind(llvm::EngineKind::JIT);
		builder.setUseMCJIT(true);
		std::unique_ptr<llvm::SectionMemoryManager> memoryManager(new llvm::SectionMemoryManager);
		builder.setMCJITMemoryManager(memoryManager.get());
		builder.setOptLevel(llvm::CodeGenOpt::None);

		auto triple = llvm::Triple(llvm::sys::getProcessTriple());
		if (triple.getOS() == llvm::Triple::OSType::Win32)
			triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF);  // MCJIT does not support COFF format
		_module->setTargetTriple(triple.str());

		ee.reset(builder.create());
		if (!ee)
			return ReturnCode::LLVMConfigError;

		_module.release();        // Successfully created llvm::ExecutionEngine takes ownership of the module
		memoryManager.release();  // and memory manager

		//ee->setObjectCache(Cache::getObjectCache());
		entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
	}
	else
	{
		entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
		if (!entryFuncPtr)
		{
			ee->addModule(_module.get());
			_module.release();
			entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
		}
	}
	assert(entryFuncPtr);

	auto executionStartTime = std::chrono::high_resolution_clock::now();
	//auto mainFunc = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
	auto returnCode = runEntryFunc(entryFuncPtr, &runtime);
	if (returnCode == ReturnCode::Return)
		this->returnData = runtime.getReturnData();

	auto executionEndTime = std::chrono::high_resolution_clock::now();
	clog(JIT) << " + " << std::chrono::duration_cast<std::chrono::milliseconds>(executionEndTime - executionStartTime).count() << " ms ";

	clog(JIT) << "\n";

	return returnCode;
}

}
}
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
#include <functional>
#include <unordered_map>

// Compare two lists to see if they're the same group; in most
// circumstances we should check for the equality of their sizes
// and early out with a false return if they weren't equal;
// however, this function is only called if the lists
// to be compared are equal to the prerequisite size anyway.
// It's provided for completeness and flexibility for other use-cases

/*
 * as it turns out, this function isn't necessary because the nature of the combinations algorithm
   prevents this via sequentially chopping off every member
   from the given numbers list
 * it's here for documentation purposes.
 *
static bool isSameUnordered(const std::vector<int>& a, const std::vector<int>& b) {
	std::unordered_map<int, int> m;

	if (a.size() != b.size())
		return false;

	// if m[x] does not exist yet,
	// the increment will first initialize it to 0
	// and then add 1 accordingly;
	// i.e., if m[x] does not exist,
	// even simply reading its value
	// will cause it to be zero-initialized
	// (on GCC)
	for (int x: a)
		m[x]++;

	for (int x: b) {
		if (m[x] == 0)
			return false;
		m[x]++;
	}

	return true;
}
*/

// This is a recursive function designed to find
// all possible sum combinations for a given list of numbers.

// For a particular size of numbers of k, and a tuple of
// distinct integers t (which is always required and given size k),
// if the sum of t is equivalent to the target sum s,
// we have a winning value. Correspondingly, we print this winning value
// ( in addition to its sequence ) into an output file corresponding
// to the input file the sum value stems from.

// The running time of this function n and k is the following combination formula (where order doesn't matter):
// O(n! / k!(n - k)!) or O(nCk)

// The implementation of this function was originally in Python,
// and can be found here: http://stackoverflow.com/a/4633515
static void sum(std::ofstream& stream,
				const int targetSum,
				const int targetAmount,
				const std::vector<int>& numbers,
				const std::vector<int>& partial = std::vector<int>()) {

	// Potentially skip iteration over winningTuples
	if (partial.size() == (uint32_t) targetAmount)
	{
		// Compute the sum for this current group
		int s = 0;
		std::for_each(partial.begin(), partial.cend(), [&s](const int& x) -> void {
			s += x;
		});

		// If we're valid, provide an output which shows the expression
		if (s == targetSum) {
			std::stringstream ss;

			size_t c = 0;

			for (int i: partial) {
				ss << i;

				if (++c != partial.size())
					ss << " + ";
			}
			ss << " = " << targetSum << "\n";
			stream << ss.str();

			winningTuples.push_back(partial);
		}

		// There is no point in continuing if either of these are true,
		// since we'll only be increasing the value/partial size if
		// recurse down the tree further.
		if (s >= targetSum)
			return;
	}

	// Same principle with the sum check in the above block^^^
	if (partial.size() >= (size_t)targetAmount)
		return;

	// For us to evaluate all possible combinations (up to the desired target amount)
	// we develop a chain of values for every single value
	// which individually inspects it self with every other possible
	// sum in every list

	// Each iteration successively creates a new variant of the given partial list,
	// by taking the value in numbers corresponding to the current iteration,
	// chopping off every value up to (inclusive) that iteration from the numbers list
	// and creating a copy of that list with which we can use to evaluate within the next depth.

	// So, if I have abcdefg numbers, all of the partial combinations for first level will be:
	// ab, ac, ad, ae, af, ag

	// And in the next level:
	// abc, abd, abe, abf, abg;
	// acd, ace, acf, acg;
	// ade, adf, adg;
	// aef, aeg;
	// afg

	// (and so on and so forth)
	for (auto i = numbers.begin(); i != numbers.end(); ++i) {
		int x = *i;

		std::vector<int> remaining;
		int index = std::distance(numbers.begin(), i);
		remaining.reserve(numbers.size() - index);

		for (auto j = i + 1; j != numbers.end(); ++j)
			remaining.push_back(*j);

		std::vector<int> newPartial(partial.begin(), partial.end());
		newPartial.push_back(x);

		sum(stream, targetSum, targetAmount, remaining, newPartial);
	}
}

static bool parseInput(const std::string& inputPath, const std::string& outputPath) {
	std::ifstream f;
	f.open(inputPath);

	std::ofstream output;
	output.open(outputPath);

	int targetSum = 0;
	int targetAmount = 0;

	std::vector<int> numbers;

	if (f.is_open()) {
		// Get the current line,
		// evaluate its function accordingly,
		// depending on the current line number
		std::string line;
		int lineNum = 0;

		while (std::getline(f, line)) {
			std::istringstream toInteger(line);
			switch (lineNum) {
				case 1: toInteger >> targetSum; break;
				case 0: toInteger >> targetAmount; break;
				default:  {
					int value;
					toInteger >> value;
					numbers.push_back(value);
				} break;
			}

			lineNum++;
		}

		// Compute the sum.
		output << "BEGIN " << inputPath << "\n\n";
		output << "number count: " << numbers.size() << "\n";
		output << "target amount: " << targetAmount << "\n";
		output << "target sum: " << targetSum << "\n";

		sum(output, targetSum, targetAmount, numbers);

		output << "END input\n\n";

		output.close();

		winningTuples.clear();

	} else {
		std::cout << "Failure" << std::endl;
		return false;
	}

	return true;
}

int main()
{
	// Must <= the amount of test files generated via input_gen.py
	int numTests = 3;

	for (int i = 0; i < numTests; ++i) {
		std::string inpath("input" + std::to_string(i) + ".txt");
		if (!parseInput(inpath, "result_input" + std::to_string(i) + ".txt")) {
			std::cout << "Could not read file \"" << inpath << '\"' << std::endl;
		}
	}

	return 0;
}

<commit_msg>Update main.cpp<commit_after>#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
#include <functional>
#include <unordered_map>

// Compare two lists to see if they're the same group; in most
// circumstances we should check for the equality of their sizes
// and early out with a false return if they weren't equal;
// however, this function is only called if the lists
// to be compared are equal to the prerequisite size anyway.
// It's provided for completeness and flexibility for other use-cases

/*
 * as it turns out, this function isn't necessary because the nature of the combinations algorithm
   prevents this via sequentially chopping off every member
   from the given numbers list
 * it's here for documentation purposes.
 *
static bool isSameUnordered(const std::vector<int>& a, const std::vector<int>& b) {
	std::unordered_map<int, int> m;

	if (a.size() != b.size())
		return false;

	// if m[x] does not exist yet,
	// the increment will first initialize it to 0
	// and then add 1 accordingly;
	// i.e., if m[x] does not exist,
	// even simply reading its value
	// will cause it to be zero-initialized
	// (on GCC)
	for (int x: a)
		m[x]++;

	for (int x: b) {
		if (m[x] == 0)
			return false;
		m[x]++;
	}

	return true;
}
*/

// This is a recursive function designed to find
// all possible sum combinations for a given list of numbers.

// For a particular size of numbers of k, and a tuple of
// distinct integers t (which is always required and given size k),
// if the sum of t is equivalent to the target sum s,
// we have a winning value. Correspondingly, we print this winning value
// ( in addition to its sequence ) into an output file corresponding
// to the input file the sum value stems from.

// The running time of this function n and k is the following combination formula (where order doesn't matter):
// O(n! / k!(n - k)!) or O(nCk)

// The implementation of this function was originally in Python,
// and can be found here: http://stackoverflow.com/a/4633515
static void sum(std::ofstream& stream,
				const int targetSum,
				const int targetAmount,
				const std::vector<int>& numbers,
				const std::vector<int>& partial = std::vector<int>()) {

	if (partial.size() == (uint32_t) targetAmount)
	{
		// Compute the sum for this current group
		int s = 0;
		std::for_each(partial.begin(), partial.cend(), [&s](const int& x) -> void {
			s += x;
		});

		// If we're valid, provide an output which shows the expression
		if (s == targetSum) {
			std::stringstream ss;

			size_t c = 0;

			for (int i: partial) {
				ss << i;

				if (++c != partial.size())
					ss << " + ";
			}
			ss << " = " << targetSum << "\n";
			stream << ss.str();

			winningTuples.push_back(partial);
		}

		// There is no point in continuing if either of these are true,
		// since we'll only be increasing the value/partial size if
		// recurse down the tree further.
		if (s >= targetSum)
			return;
	}

	// Same principle with the sum check in the above block^^^
	if (partial.size() >= (size_t)targetAmount)
		return;

	// For us to evaluate all possible combinations (up to the desired target amount)
	// we develop a chain of values for every single value
	// which individually inspects it self with every other possible
	// sum in every list

	// Each iteration successively creates a new variant of the given partial list,
	// by taking the value in numbers corresponding to the current iteration,
	// chopping off every value up to (inclusive) that iteration from the numbers list
	// and creating a copy of that list with which we can use to evaluate within the next depth.

	// So, if I have abcdefg numbers, all of the partial combinations for first level will be:
	// ab, ac, ad, ae, af, ag

	// And in the next level:
	// abc, abd, abe, abf, abg;
	// acd, ace, acf, acg;
	// ade, adf, adg;
	// aef, aeg;
	// afg

	// (and so on and so forth)
	for (auto i = numbers.begin(); i != numbers.end(); ++i) {
		int x = *i;

		std::vector<int> remaining;
		int index = std::distance(numbers.begin(), i);
		remaining.reserve(numbers.size() - index);

		for (auto j = i + 1; j != numbers.end(); ++j)
			remaining.push_back(*j);

		std::vector<int> newPartial(partial.begin(), partial.end());
		newPartial.push_back(x);

		sum(stream, targetSum, targetAmount, remaining, newPartial);
	}
}

static bool parseInput(const std::string& inputPath, const std::string& outputPath) {
	std::ifstream f;
	f.open(inputPath);

	std::ofstream output;
	output.open(outputPath);

	int targetSum = 0;
	int targetAmount = 0;

	std::vector<int> numbers;

	if (f.is_open()) {
		// Get the current line,
		// evaluate its function accordingly,
		// depending on the current line number
		std::string line;
		int lineNum = 0;

		while (std::getline(f, line)) {
			std::istringstream toInteger(line);
			switch (lineNum) {
				case 1: toInteger >> targetSum; break;
				case 0: toInteger >> targetAmount; break;
				default:  {
					int value;
					toInteger >> value;
					numbers.push_back(value);
				} break;
			}

			lineNum++;
		}

		// Compute the sum.
		output << "BEGIN " << inputPath << "\n\n";
		output << "number count: " << numbers.size() << "\n";
		output << "target amount: " << targetAmount << "\n";
		output << "target sum: " << targetSum << "\n";

		sum(output, targetSum, targetAmount, numbers);

		output << "END input\n\n";

		output.close();

		winningTuples.clear();

	} else {
		return false;
	}

	return true;
}

int main()
{
	// Must be <= the amount of test files generated via input_gen.py
	int numTests = 3;

	for (int i = 0; i < numTests; ++i) {
		std::string inpath("input" + std::to_string(i) + ".txt");
		if (!parseInput(inpath, "result_input" + std::to_string(i) + ".txt")) {
			std::cout << "Could not read file \"" << inpath << '\"' << std::endl;
		}
	}

	return 0;
}

<|endoftext|>


<commit_before>//===--- JSONRPCDispatcher.cpp - Main JSON parser entry point -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "JSONRPCDispatcher.h"
#include "ProtocolHandlers.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"
#include <istream>

using namespace clang;
using namespace clangd;

void JSONOutput::writeMessage(const Twine &Message) {
  llvm::SmallString<128> Storage;
  StringRef M = Message.toStringRef(Storage);

  std::lock_guard<std::mutex> Guard(StreamMutex);
  // Log without headers.
  Logs << "--> " << M << '\n';
  Logs.flush();

  // Emit message with header.
  Outs << "Content-Length: " << M.size() << "\r\n\r\n" << M;
  Outs.flush();
}

void JSONOutput::log(const Twine &Message) {
  std::lock_guard<std::mutex> Guard(StreamMutex);
  Logs << Message;
  Logs.flush();
}

void JSONOutput::mirrorInput(const Twine &Message) {
  if (!InputMirror)
    return;

  *InputMirror << Message;
  InputMirror->flush();
}

void RequestContext::reply(const llvm::Twine &Result) {
  if (ID.empty()) {
    Out.log("Attempted to reply to a notification!\n");
    return;
  }
  Out.writeMessage(llvm::Twine(R"({"jsonrpc":"2.0","id":)") + ID +
                   R"(,"result":)" + Result + "}");
}

void RequestContext::replyError(int code, const llvm::StringRef &Message) {
  Out.log("Error " + llvm::Twine(code) + ": " + Message + "\n");
  if (!ID.empty()) {
    Out.writeMessage(llvm::Twine(R"({"jsonrpc":"2.0","id":)") + ID +
                     R"(,"error":{"code":)" + llvm::Twine(code) +
                     R"(,"message":")" + llvm::yaml::escape(Message) +
                     R"("}})");
  }
}

void JSONRPCDispatcher::registerHandler(StringRef Method, Handler H) {
  assert(!Handlers.count(Method) && "Handler already registered!");
  Handlers[Method] = std::move(H);
}

static void
callHandler(const llvm::StringMap<JSONRPCDispatcher::Handler> &Handlers,
            llvm::yaml::ScalarNode *Method, llvm::yaml::ScalarNode *Id,
            llvm::yaml::MappingNode *Params,
            const JSONRPCDispatcher::Handler &UnknownHandler, JSONOutput &Out) {
  llvm::SmallString<64> MethodStorage;
  auto I = Handlers.find(Method->getValue(MethodStorage));
  auto &Handler = I != Handlers.end() ? I->second : UnknownHandler;
  Handler(RequestContext(Out, Id ? Id->getRawValue() : ""), Params);
}

bool JSONRPCDispatcher::call(StringRef Content, JSONOutput &Out) const {
  llvm::SourceMgr SM;
  llvm::yaml::Stream YAMLStream(Content, SM);

  auto Doc = YAMLStream.begin();
  if (Doc == YAMLStream.end())
    return false;

  auto *Root = Doc->getRoot();
  if (!Root)
    return false;

  auto *Object = dyn_cast<llvm::yaml::MappingNode>(Root);
  if (!Object)
    return false;

  llvm::yaml::ScalarNode *Version = nullptr;
  llvm::yaml::ScalarNode *Method = nullptr;
  llvm::yaml::MappingNode *Params = nullptr;
  llvm::yaml::ScalarNode *Id = nullptr;
  for (auto &NextKeyValue : *Object) {
    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
    if (!KeyString)
      return false;

    llvm::SmallString<10> KeyStorage;
    StringRef KeyValue = KeyString->getValue(KeyStorage);
    llvm::yaml::Node *Value = NextKeyValue.getValue();
    if (!Value)
      return false;

    if (KeyValue == "jsonrpc") {
      // This should be "2.0". Always.
      Version = dyn_cast<llvm::yaml::ScalarNode>(Value);
      if (!Version || Version->getRawValue() != "\"2.0\"")
        return false;
    } else if (KeyValue == "method") {
      Method = dyn_cast<llvm::yaml::ScalarNode>(Value);
    } else if (KeyValue == "id") {
      Id = dyn_cast<llvm::yaml::ScalarNode>(Value);
    } else if (KeyValue == "params") {
      if (!Method)
        return false;
      // We have to interleave the call of the function here, otherwise the
      // YAMLParser will die because it can't go backwards. This is unfortunate
      // because it will break clients that put the id after params. A possible
      // fix would be to split the parsing and execution phases.
      Params = dyn_cast<llvm::yaml::MappingNode>(Value);
      callHandler(Handlers, Method, Id, Params, UnknownHandler, Out);
      return true;
    } else {
      return false;
    }
  }

  // In case there was a request with no params, call the handler on the
  // leftovers.
  if (!Method)
    return false;
  callHandler(Handlers, Method, Id, nullptr, UnknownHandler, Out);

  return true;
}

void clangd::runLanguageServerLoop(std::istream &In, JSONOutput &Out,
                                   JSONRPCDispatcher &Dispatcher,
                                   bool &IsDone) {
  while (In.good()) {
    // A Language Server Protocol message starts with a set of HTTP headers,
    // delimited  by \r\n, and terminated by an empty line (\r\n).
    unsigned long long ContentLength = 0;
    while (In.good()) {
      std::string Line;
      std::getline(In, Line);
      if (!In.good() && errno == EINTR) {
        In.clear();
        continue;
      }

      Out.mirrorInput(Line);
      // Mirror '\n' that gets consumed by std::getline, but is not included in
      // the resulting Line.
      // Note that '\r' is part of Line, so we don't need to mirror it
      // separately.
      if (!In.eof())
        Out.mirrorInput("\n");

      llvm::StringRef LineRef(Line);

      // We allow YAML-style comments in headers. Technically this isn't part
      // of the LSP specification, but makes writing tests easier.
      if (LineRef.startswith("#"))
        continue;

      // Content-Type is a specified header, but does nothing.
      // Content-Length is a mandatory header. It specifies the length of the
      // following JSON.
      // It is unspecified what sequence headers must be supplied in, so we
      // allow any sequence.
      // The end of headers is signified by an empty line.
      if (LineRef.consume_front("Content-Length: ")) {
        if (ContentLength != 0) {
          Out.log("Warning: Duplicate Content-Length header received. "
                  "The previous value for this message (" +
                  std::to_string(ContentLength) + ") was ignored.\n");
        }

        llvm::getAsUnsignedInteger(LineRef.trim(), 0, ContentLength);
        continue;
      } else if (!LineRef.trim().empty()) {
        // It's another header, ignore it.
        continue;
      } else {
        // An empty line indicates the end of headers.
        // Go ahead and read the JSON.
        break;
      }
    }

    if (ContentLength > 0) {
      // Now read the JSON. Insert a trailing null byte as required by the YAML
      // parser.
      std::vector<char> JSON(ContentLength + 1, '\0');
      In.read(JSON.data(), ContentLength);
      Out.mirrorInput(StringRef(JSON.data(), In.gcount()));

      // If the stream is aborted before we read ContentLength bytes, In
      // will have eofbit and failbit set.
      if (!In) {
        Out.log("Input was aborted. Read only " + std::to_string(In.gcount()) +
                " bytes of expected " + std::to_string(ContentLength) + ".\n");
        break;
      }

      llvm::StringRef JSONRef(JSON.data(), ContentLength);
      // Log the message.
      Out.log("<-- " + JSONRef + "\n");

      // Finally, execute the action for this JSON message.
      if (!Dispatcher.call(JSONRef, Out))
        Out.log("JSON dispatch failed!\n");

      // If we're done, exit the loop.
      if (IsDone)
        break;
    } else {
      Out.log("Warning: Missing Content-Length header, or message has zero "
              "length.\n");
    }
  }
}
<commit_msg>[clangd] Harden clangd a bit against garbage input.<commit_after>//===--- JSONRPCDispatcher.cpp - Main JSON parser entry point -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "JSONRPCDispatcher.h"
#include "ProtocolHandlers.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"
#include <istream>

using namespace clang;
using namespace clangd;

void JSONOutput::writeMessage(const Twine &Message) {
  llvm::SmallString<128> Storage;
  StringRef M = Message.toStringRef(Storage);

  std::lock_guard<std::mutex> Guard(StreamMutex);
  // Log without headers.
  Logs << "--> " << M << '\n';
  Logs.flush();

  // Emit message with header.
  Outs << "Content-Length: " << M.size() << "\r\n\r\n" << M;
  Outs.flush();
}

void JSONOutput::log(const Twine &Message) {
  std::lock_guard<std::mutex> Guard(StreamMutex);
  Logs << Message;
  Logs.flush();
}

void JSONOutput::mirrorInput(const Twine &Message) {
  if (!InputMirror)
    return;

  *InputMirror << Message;
  InputMirror->flush();
}

void RequestContext::reply(const llvm::Twine &Result) {
  if (ID.empty()) {
    Out.log("Attempted to reply to a notification!\n");
    return;
  }
  Out.writeMessage(llvm::Twine(R"({"jsonrpc":"2.0","id":)") + ID +
                   R"(,"result":)" + Result + "}");
}

void RequestContext::replyError(int code, const llvm::StringRef &Message) {
  Out.log("Error " + llvm::Twine(code) + ": " + Message + "\n");
  if (!ID.empty()) {
    Out.writeMessage(llvm::Twine(R"({"jsonrpc":"2.0","id":)") + ID +
                     R"(,"error":{"code":)" + llvm::Twine(code) +
                     R"(,"message":")" + llvm::yaml::escape(Message) +
                     R"("}})");
  }
}

void JSONRPCDispatcher::registerHandler(StringRef Method, Handler H) {
  assert(!Handlers.count(Method) && "Handler already registered!");
  Handlers[Method] = std::move(H);
}

static void
callHandler(const llvm::StringMap<JSONRPCDispatcher::Handler> &Handlers,
            llvm::yaml::ScalarNode *Method, llvm::yaml::ScalarNode *Id,
            llvm::yaml::MappingNode *Params,
            const JSONRPCDispatcher::Handler &UnknownHandler, JSONOutput &Out) {
  llvm::SmallString<64> MethodStorage;
  auto I = Handlers.find(Method->getValue(MethodStorage));
  auto &Handler = I != Handlers.end() ? I->second : UnknownHandler;
  Handler(RequestContext(Out, Id ? Id->getRawValue() : ""), Params);
}

bool JSONRPCDispatcher::call(StringRef Content, JSONOutput &Out) const {
  llvm::SourceMgr SM;
  llvm::yaml::Stream YAMLStream(Content, SM);

  auto Doc = YAMLStream.begin();
  if (Doc == YAMLStream.end())
    return false;

  auto *Object = dyn_cast_or_null<llvm::yaml::MappingNode>(Doc->getRoot());
  if (!Object)
    return false;

  llvm::yaml::ScalarNode *Version = nullptr;
  llvm::yaml::ScalarNode *Method = nullptr;
  llvm::yaml::MappingNode *Params = nullptr;
  llvm::yaml::ScalarNode *Id = nullptr;
  for (auto &NextKeyValue : *Object) {
    auto *KeyString =
        dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
    if (!KeyString)
      return false;

    llvm::SmallString<10> KeyStorage;
    StringRef KeyValue = KeyString->getValue(KeyStorage);
    llvm::yaml::Node *Value = NextKeyValue.getValue();
    if (!Value)
      return false;

    if (KeyValue == "jsonrpc") {
      // This should be "2.0". Always.
      Version = dyn_cast<llvm::yaml::ScalarNode>(Value);
      if (!Version || Version->getRawValue() != "\"2.0\"")
        return false;
    } else if (KeyValue == "method") {
      Method = dyn_cast<llvm::yaml::ScalarNode>(Value);
    } else if (KeyValue == "id") {
      Id = dyn_cast<llvm::yaml::ScalarNode>(Value);
    } else if (KeyValue == "params") {
      if (!Method)
        return false;
      // We have to interleave the call of the function here, otherwise the
      // YAMLParser will die because it can't go backwards. This is unfortunate
      // because it will break clients that put the id after params. A possible
      // fix would be to split the parsing and execution phases.
      Params = dyn_cast<llvm::yaml::MappingNode>(Value);
      callHandler(Handlers, Method, Id, Params, UnknownHandler, Out);
      return true;
    } else {
      return false;
    }
  }

  // In case there was a request with no params, call the handler on the
  // leftovers.
  if (!Method)
    return false;
  callHandler(Handlers, Method, Id, nullptr, UnknownHandler, Out);

  return true;
}

void clangd::runLanguageServerLoop(std::istream &In, JSONOutput &Out,
                                   JSONRPCDispatcher &Dispatcher,
                                   bool &IsDone) {
  while (In.good()) {
    // A Language Server Protocol message starts with a set of HTTP headers,
    // delimited  by \r\n, and terminated by an empty line (\r\n).
    unsigned long long ContentLength = 0;
    while (In.good()) {
      std::string Line;
      std::getline(In, Line);
      if (!In.good() && errno == EINTR) {
        In.clear();
        continue;
      }

      Out.mirrorInput(Line);
      // Mirror '\n' that gets consumed by std::getline, but is not included in
      // the resulting Line.
      // Note that '\r' is part of Line, so we don't need to mirror it
      // separately.
      if (!In.eof())
        Out.mirrorInput("\n");

      llvm::StringRef LineRef(Line);

      // We allow YAML-style comments in headers. Technically this isn't part
      // of the LSP specification, but makes writing tests easier.
      if (LineRef.startswith("#"))
        continue;

      // Content-Type is a specified header, but does nothing.
      // Content-Length is a mandatory header. It specifies the length of the
      // following JSON.
      // It is unspecified what sequence headers must be supplied in, so we
      // allow any sequence.
      // The end of headers is signified by an empty line.
      if (LineRef.consume_front("Content-Length: ")) {
        if (ContentLength != 0) {
          Out.log("Warning: Duplicate Content-Length header received. "
                  "The previous value for this message (" +
                  std::to_string(ContentLength) + ") was ignored.\n");
        }

        llvm::getAsUnsignedInteger(LineRef.trim(), 0, ContentLength);
        continue;
      } else if (!LineRef.trim().empty()) {
        // It's another header, ignore it.
        continue;
      } else {
        // An empty line indicates the end of headers.
        // Go ahead and read the JSON.
        break;
      }
    }

    if (ContentLength > 0) {
      // Now read the JSON. Insert a trailing null byte as required by the YAML
      // parser.
      std::vector<char> JSON(ContentLength + 1, '\0');
      In.read(JSON.data(), ContentLength);
      Out.mirrorInput(StringRef(JSON.data(), In.gcount()));

      // If the stream is aborted before we read ContentLength bytes, In
      // will have eofbit and failbit set.
      if (!In) {
        Out.log("Input was aborted. Read only " + std::to_string(In.gcount()) +
                " bytes of expected " + std::to_string(ContentLength) + ".\n");
        break;
      }

      llvm::StringRef JSONRef(JSON.data(), ContentLength);
      // Log the message.
      Out.log("<-- " + JSONRef + "\n");

      // Finally, execute the action for this JSON message.
      if (!Dispatcher.call(JSONRef, Out))
        Out.log("JSON dispatch failed!\n");

      // If we're done, exit the loop.
      if (IsDone)
        break;
    } else {
      Out.log("Warning: Missing Content-Length header, or message has zero "
              "length.\n");
    }
  }
}
<|endoftext|>


<commit_before>/*
Copyright 2013-present Barefoot Networks, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "bitvec.h"
#include "hex.h"

std::ostream &operator<<(std::ostream &os, const bitvec &bv) {
    if (bv.size == 1) {
        os << hex(bv.data);
    } else {
        bool first = true;
        for (int i = bv.size-1; i >= 0; i--) {
            if (first) {
                if (!bv.ptr[i]) continue;
                os << hex(bv.ptr[i]);
                first = false;
            } else {
                os << hex(bv.ptr[i], sizeof(bv.data)*2, '0'); } }
        if (first)
            os << '0';
    }
    return os;
}

bitvec &bitvec::operator>>=(size_t count) {
    if (size == 1) {
        if (count >= bits_per_unit)
            data = 0;
        else
            data >>= count;
        return *this; }
    int off = count / bits_per_unit;
    count %= bits_per_unit;
    for (size_t i = 0; i < size; i++)
        if (i + off < size) {
            ptr[i] = ptr[i+off] >> count;
            if (count && i + off + 1 < size)
                ptr[i] |= ptr[i+off+1] << (bits_per_unit - count);
        } else {
            ptr[i] = 0; }
    while (size > 1 && !ptr[size-1]) size--;
    if (size == 1) {
        auto tmp = ptr[0];
        delete [] ptr;
        data = tmp; }
    return *this;
}

bitvec &bitvec::operator<<=(size_t count) {
    size_t needsize = (max().index() + count + bits_per_unit - 1)/bits_per_unit;
    if (needsize > size) expand(needsize);
    if (size == 1) {
        data <<= count;
        return *this; }
    int off = count / bits_per_unit;
    count %= bits_per_unit;
    for (int i = size-1; i >= 0; i--)
        if (i >= off) {
            ptr[i] = ptr[i-off] << count;
            if (count && i > off)
                ptr[i] |= ptr[i-off-1] >> (bits_per_unit - count);
        } else {
            ptr[i] = 0; }
    return *this;
}

bitvec bitvec::getslice(size_t idx, size_t sz) const {
    if (idx >= size * bits_per_unit) return bitvec();
    if (idx + sz > size * bits_per_unit)
        sz = size * bits_per_unit - idx;
    if (size > 1) {
        bitvec rv;
        unsigned shift = idx % bits_per_unit;
        idx /= bits_per_unit;
        if (sz > bits_per_unit) {
            rv.expand((sz-1)/bits_per_unit + 1);
            for (size_t i = 0; i < rv.size; i++) {
                if (shift != 0 && i != 0)
                    rv.ptr[i-1] |= ptr[idx + 1] << (bits_per_unit - shift);
                rv.ptr[i] = ptr[idx] >> shift; }
            if ((sz %= bits_per_unit))
                rv.ptr[rv.size-1] &= ~(~(uintptr_t)1 << (sz-1));
        } else {
            rv.data = ptr[idx] >> shift;
            if (shift != 0 && idx + 1 < size)
                rv.data |= ptr[idx + 1] << (bits_per_unit - shift);
            rv.data &= ~(~(uintptr_t)1 << (sz-1)); }
        return rv;
    } else {
        return bitvec((data >> idx) & ~(~(uintptr_t)1 << (sz-1))); }
}

int bitvec::ffs(unsigned start) const {
    uintptr_t val = ~0ULL;
    unsigned idx = start / bits_per_unit;
    val <<= (start % bits_per_unit);
    while (idx < size && !(val &= word(idx))) {
        ++idx;
        val = ~0ULL; }
    if (idx >= size) return -1;
    unsigned rv = idx * bits_per_unit;
#if defined(__GNUC__) || defined(__clang__)
    rv += builtin_ctz(val);
#else
    while ((val & 0xff) == 0) { rv += 8; val >>= 8; }
    while ((val & 1) == 0) { rv++; val >>= 1; }
#endif
    return rv;
}

unsigned bitvec::ffz(unsigned start) const {
    uintptr_t val = 0;
    unsigned idx = start / bits_per_unit;
    val = ~(~val << (start % bits_per_unit));
    while (!~(val |= word(idx))) {
        ++idx;
        val = 0; }
    unsigned rv = idx * bits_per_unit;
#if defined(__GNUC__) || defined(__clang__)
    rv += builtin_ctz(~val);
#else
    while ((val & 0xff) == 0xff) { rv += 8; val >>= 8; }
    while (val & 1) { rv++; val >>= 1; }
#endif
    return rv;
}

bool bitvec::is_contiguous() const {
    // Empty bitvec is not contiguous
    if (empty())
        return false;
    return max().index() - min().index() + 1 == popcount();
}
<commit_msg>Adjusted getslice function of bitvec to return empty bitvec when the size requested is 0. (#744)<commit_after>/*
Copyright 2013-present Barefoot Networks, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "bitvec.h"
#include "hex.h"

std::ostream &operator<<(std::ostream &os, const bitvec &bv) {
    if (bv.size == 1) {
        os << hex(bv.data);
    } else {
        bool first = true;
        for (int i = bv.size-1; i >= 0; i--) {
            if (first) {
                if (!bv.ptr[i]) continue;
                os << hex(bv.ptr[i]);
                first = false;
            } else {
                os << hex(bv.ptr[i], sizeof(bv.data)*2, '0'); } }
        if (first)
            os << '0';
    }
    return os;
}

bitvec &bitvec::operator>>=(size_t count) {
    if (size == 1) {
        if (count >= bits_per_unit)
            data = 0;
        else
            data >>= count;
        return *this; }
    int off = count / bits_per_unit;
    count %= bits_per_unit;
    for (size_t i = 0; i < size; i++)
        if (i + off < size) {
            ptr[i] = ptr[i+off] >> count;
            if (count && i + off + 1 < size)
                ptr[i] |= ptr[i+off+1] << (bits_per_unit - count);
        } else {
            ptr[i] = 0; }
    while (size > 1 && !ptr[size-1]) size--;
    if (size == 1) {
        auto tmp = ptr[0];
        delete [] ptr;
        data = tmp; }
    return *this;
}

bitvec &bitvec::operator<<=(size_t count) {
    size_t needsize = (max().index() + count + bits_per_unit - 1)/bits_per_unit;
    if (needsize > size) expand(needsize);
    if (size == 1) {
        data <<= count;
        return *this; }
    int off = count / bits_per_unit;
    count %= bits_per_unit;
    for (int i = size-1; i >= 0; i--)
        if (i >= off) {
            ptr[i] = ptr[i-off] << count;
            if (count && i > off)
                ptr[i] |= ptr[i-off-1] >> (bits_per_unit - count);
        } else {
            ptr[i] = 0; }
    return *this;
}

bitvec bitvec::getslice(size_t idx, size_t sz) const {
    if (sz == 0) return bitvec();
    if (idx >= size * bits_per_unit) return bitvec();
    if (idx + sz > size * bits_per_unit)
        sz = size * bits_per_unit - idx;
    if (size > 1) {
        bitvec rv;
        unsigned shift = idx % bits_per_unit;
        idx /= bits_per_unit;
        if (sz > bits_per_unit) {
            rv.expand((sz-1)/bits_per_unit + 1);
            for (size_t i = 0; i < rv.size; i++) {
                if (shift != 0 && i != 0)
                    rv.ptr[i-1] |= ptr[idx + 1] << (bits_per_unit - shift);
                rv.ptr[i] = ptr[idx] >> shift; }
            if ((sz %= bits_per_unit))
                rv.ptr[rv.size-1] &= ~(~(uintptr_t)1 << (sz-1));
        } else {
            rv.data = ptr[idx] >> shift;
            if (shift != 0 && idx + 1 < size)
                rv.data |= ptr[idx + 1] << (bits_per_unit - shift);
            rv.data &= ~(~(uintptr_t)1 << (sz-1)); }
        return rv;
    } else {
        return bitvec((data >> idx) & ~(~(uintptr_t)1 << (sz-1))); }
}

int bitvec::ffs(unsigned start) const {
    uintptr_t val = ~0ULL;
    unsigned idx = start / bits_per_unit;
    val <<= (start % bits_per_unit);
    while (idx < size && !(val &= word(idx))) {
        ++idx;
        val = ~0ULL; }
    if (idx >= size) return -1;
    unsigned rv = idx * bits_per_unit;
#if defined(__GNUC__) || defined(__clang__)
    rv += builtin_ctz(val);
#else
    while ((val & 0xff) == 0) { rv += 8; val >>= 8; }
    while ((val & 1) == 0) { rv++; val >>= 1; }
#endif
    return rv;
}

unsigned bitvec::ffz(unsigned start) const {
    uintptr_t val = 0;
    unsigned idx = start / bits_per_unit;
    val = ~(~val << (start % bits_per_unit));
    while (!~(val |= word(idx))) {
        ++idx;
        val = 0; }
    unsigned rv = idx * bits_per_unit;
#if defined(__GNUC__) || defined(__clang__)
    rv += builtin_ctz(~val);
#else
    while ((val & 0xff) == 0xff) { rv += 8; val >>= 8; }
    while (val & 1) { rv++; val >>= 1; }
#endif
    return rv;
}

bool bitvec::is_contiguous() const {
    // Empty bitvec is not contiguous
    if (empty())
        return false;
    return max().index() - min().index() + 1 == popcount();
}
<|endoftext|>