<commit_before>/*
    This file is part of kdepim.

    Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "webdavhandler.h"
#include "sloxbase.h"

#include "config.h"

#ifdef HAVE_VALUES_H
#include <values.h>
#else
#ifdef HAVE_SYS_LIMITS_H
#include <sys/limits.h>
#endif
#endif

#include <stdlib.h>

#include <libkcal/incidence.h>

#include <libkdepim/kpimprefs.h>

#include <kdebug.h>
#include <kconfig.h>

#include <qfile.h>
//Added by qt3to4:
#include <Q3ValueList>
#include <Q3CString>

SloxItem::SloxItem()
  : status( Invalid )
{
}

WebdavHandler::WebdavHandler()
  : mLogCount( 0 )
{
  KConfig cfg( "sloxrc" );

  cfg.setGroup( "General" );
  mLogFile = cfg.readEntry( "LogFile" );

  kdDebug() << "LOG FILE: " << mLogFile << endl;
}

void WebdavHandler::setUserId( const QString &id )
{
  mUserId = id;
}

QString WebdavHandler::userId() const
{
  return mUserId;
}

void WebdavHandler::log( const QString &text )
{
  if ( mLogFile.isEmpty() ) return;

  QString filename = mLogFile + "-" + QString::number( mLogCount );
  QFile file( filename );
  if ( !file.open( QIODevice::WriteOnly ) ) {
    kdWarning() << "Unable to open log file '" << filename << "'" << endl;
    return;
  }

  Q3CString textUtf8 = text.utf8();
  file.writeBlock( textUtf8.data(), textUtf8.size() - 1 );

  if ( ++mLogCount > 5 ) mLogCount = 0;
}

Q3ValueList<SloxItem> WebdavHandler::getSloxItems( SloxBase *res, const QDomDocument &doc )
{
  kdDebug() << "getSloxItems" << endl;

  Q3ValueList<SloxItem> items;

  QDomElement docElement = doc.documentElement();

  QDomNode responseNode;
  for( responseNode = docElement.firstChild(); !responseNode.isNull();
       responseNode = responseNode.nextSibling() ) {
    QDomElement responseElement = responseNode.toElement();
    if ( responseElement.tagName() == "response" ) {
      SloxItem item;

      QDomNode propstat = responseElement.namedItem( "propstat" );
      if ( propstat.isNull() ) {
        kdError() << "Unable to find propstat tag." << endl;
        continue;
      }

      QDomNode prop = propstat.namedItem( "prop" );
      if ( prop.isNull() ) {
        kdError() << "Unable to find WebDAV property" << endl;
        continue;
      }
      item.domNode = prop;

      QDomNode sloxIdNode = prop.namedItem( res->fieldName( SloxBase::ObjectId ) );
      if ( sloxIdNode.isNull() ) {
        kdError() << "Unable to find SLOX id." << endl;
        continue;
      }
      QDomElement sloxIdElement = sloxIdNode.toElement();
      item.sloxId = sloxIdElement.text();

      QDomNode clientIdNode = prop.namedItem( res->fieldName( SloxBase::ClientId ) );
      if ( !clientIdNode.isNull() ) {
        QDomElement clientIdElement = clientIdNode.toElement();
        item.clientId = clientIdElement.text();
        if ( item.clientId != item.sloxId )
          item.status = SloxItem::New;
      }

      QDomNode sloxStatus = prop.namedItem( res->fieldName( SloxBase::ObjectStatus ) );
      if ( !sloxStatus.isNull() ) {
        QDomElement sloxStatusElement = sloxStatus.toElement();
        if ( sloxStatusElement.text() == "DELETE" ) {
          item.status = SloxItem::Delete;
        } else if ( sloxStatusElement.text() == "CREATE" ) {
          item.status = SloxItem::Create;
        }
      }

      QDomNode status = propstat.namedItem( "status" );
      if ( status.isNull() ) {
        kdError() << "Unable to find WebDAV status" << endl;
        continue;
      }
      item.response = status.toElement().text();

      QDomNode desc = propstat.namedItem( "responsedescription" );
      if ( desc.isNull() ) {
        kdError() << "Unable to find WebDAV responsedescription" << endl;
        continue;
      }
      item.responseDescription = desc.toElement().text();

      items.append( item );
    }
  }

  return items;
}

QString WebdavHandler::qDateTimeToSlox( const QDateTime &dt )
{
  uint ticks = -dt.secsTo( QDateTime( QDate( 1970, 1, 1 ), QTime( 0, 0 ) ) );

  return QString::number( ticks ) + "000";
}

QString WebdavHandler::qDateTimeToSlox( const QDateTime &dt,
                                        const QString &timeZoneId )
{
  QDateTime utc = KPimPrefs::localTimeToUtc( dt, timeZoneId );

  // secsTo and toTime_t etc also perform a timezone conversion using the system timezone,
  // but we want to use the calendar timezone, so we have to convert ourself and spoof the tz to UTC before
  // converting to ticks to prevent this
  Q3CString origTz = getenv("TZ");
  setenv( "TZ", "UTC", 1 );
  uint ticks = utc.toTime_t();
  if ( origTz.isNull() )
    unsetenv( "TZ" );
  else
    setenv( "TZ", origTz, 1 );

  return QString::number( ticks ) + "000";
}

QDateTime WebdavHandler::sloxToQDateTime( const QString &str )
{
  QString s = str.mid( 0, str.length() - 3 );

  bool preEpoch = s.startsWith("-");
  if (preEpoch)
     s = s.mid(1);

  unsigned long ticks = s.toULong();

  QDateTime dt;

  if (preEpoch) {
    dt.setTime_t( 0, Qt::UTC );
    if (ticks > INT_MAX) {
      dt = dt.addSecs(-INT_MAX);
      ticks -= INT_MAX;
    }
    dt = dt.addSecs(-((long) ticks));
  }
  else
  {
    dt.setTime_t( ticks, Qt::UTC );
  }

  return dt;
}

QDateTime WebdavHandler::sloxToQDateTime( const QString &str,
                                          const QString &timeZoneId )
{
  return KPimPrefs::utcToLocalTime( sloxToQDateTime(str), timeZoneId );
}

QDomElement WebdavHandler::addElement( QDomDocument &doc, QDomNode &node,
                                       const QString &tag )
{
  QDomElement el = doc.createElement( tag );
  node.appendChild( el );
  return el;
}

QDomElement WebdavHandler::addDavElement( QDomDocument &doc, QDomNode &node,
                                          const QString &tag )
{
  QDomElement el = doc.createElementNS( "DAV:", "D:" + tag );
  node.appendChild( el );
  return el;
}

QDomElement WebdavHandler::addSloxElement( SloxBase *res,
                                           QDomDocument &doc, QDomNode &node,
                                           const QString &tag,
                                           const QString &text )
{
  QDomElement el;
  if ( res->resType() == "ox" )
    el = doc.createElementNS( "http://www.open-xchange.org", "ox:" + tag );
  else
    el = doc.createElementNS( "SLOX", "S:" + tag );
  if ( !text.isEmpty() ) {
    QDomText textnode = doc.createTextNode( text );
    el.appendChild( textnode );
  }
  node.appendChild( el );
  return el;
}

void WebdavHandler::parseSloxAttribute( const QDomElement &e )
{
//  kdDebug() << "parseSloxAttribute" << endl;

  QString tag = e.tagName();
  QString text = QString::fromUtf8( e.text().latin1() );
  if ( text.isEmpty() ) return;

  if ( tag == "owner" ) {
    if ( text == mUserId ) mWritable = true;
  } else if ( tag == "writerights" ) {
    QDomNode n;
    for( n = e.firstChild(); !n.isNull(); n = n.nextSibling() ) {
      QDomElement e2 = n.toElement();
      if ( e2.tagName() == "member" ) {
        if ( e2.text() == mUserId ) mWritable = true;
      }
      // TODO: Process group write rights
    }
  }
}

void WebdavHandler::clearSloxAttributeStatus()
{
  if ( mRes->resType() == "ox" )
    mWritable = true; // parseSloxAttribute() won't work for OX
  else
    mWritable = false;
}

void WebdavHandler::setSloxAttributes( KCal::Incidence *i )
{
  i->setReadOnly( !mWritable );
}

void WebdavHandler::setSloxAttributes( KABC::Addressee & )
{
  // FIXME: libkabc doesn't allow to set an individual addressee to read-only
}
<commit_msg>Forward port from 3.5 branch to trunk: Compile fix for Solaris, submitted by Jens Hatlak <jh at junetz dot de>.<commit_after>/*
    This file is part of kdepim.

    Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "webdavhandler.h"
#include "sloxbase.h"

#include "config.h"

#ifdef HAVE_VALUES_H
#include <values.h>
#else
#ifdef HAVE_SYS_LIMITS_H
#include <sys/limits.h>
#endif
#endif

#include <config.h>
#include <stdlib.h>

#include <libkcal/incidence.h>

#include <libkdepim/kpimprefs.h>

#include <kdebug.h>
#include <kconfig.h>

#include <qfile.h>
//Added by qt3to4:
#include <Q3ValueList>
#include <Q3CString>

SloxItem::SloxItem()
  : status( Invalid )
{
}

WebdavHandler::WebdavHandler()
  : mLogCount( 0 )
{
  KConfig cfg( "sloxrc" );

  cfg.setGroup( "General" );
  mLogFile = cfg.readEntry( "LogFile" );

  kdDebug() << "LOG FILE: " << mLogFile << endl;
}

void WebdavHandler::setUserId( const QString &id )
{
  mUserId = id;
}

QString WebdavHandler::userId() const
{
  return mUserId;
}

void WebdavHandler::log( const QString &text )
{
  if ( mLogFile.isEmpty() ) return;

  QString filename = mLogFile + "-" + QString::number( mLogCount );
  QFile file( filename );
  if ( !file.open( QIODevice::WriteOnly ) ) {
    kdWarning() << "Unable to open log file '" << filename << "'" << endl;
    return;
  }

  Q3CString textUtf8 = text.utf8();
  file.writeBlock( textUtf8.data(), textUtf8.size() - 1 );

  if ( ++mLogCount > 5 ) mLogCount = 0;
}

Q3ValueList<SloxItem> WebdavHandler::getSloxItems( SloxBase *res, const QDomDocument &doc )
{
  kdDebug() << "getSloxItems" << endl;

  Q3ValueList<SloxItem> items;

  QDomElement docElement = doc.documentElement();

  QDomNode responseNode;
  for( responseNode = docElement.firstChild(); !responseNode.isNull();
       responseNode = responseNode.nextSibling() ) {
    QDomElement responseElement = responseNode.toElement();
    if ( responseElement.tagName() == "response" ) {
      SloxItem item;

      QDomNode propstat = responseElement.namedItem( "propstat" );
      if ( propstat.isNull() ) {
        kdError() << "Unable to find propstat tag." << endl;
        continue;
      }

      QDomNode prop = propstat.namedItem( "prop" );
      if ( prop.isNull() ) {
        kdError() << "Unable to find WebDAV property" << endl;
        continue;
      }
      item.domNode = prop;

      QDomNode sloxIdNode = prop.namedItem( res->fieldName( SloxBase::ObjectId ) );
      if ( sloxIdNode.isNull() ) {
        kdError() << "Unable to find SLOX id." << endl;
        continue;
      }
      QDomElement sloxIdElement = sloxIdNode.toElement();
      item.sloxId = sloxIdElement.text();

      QDomNode clientIdNode = prop.namedItem( res->fieldName( SloxBase::ClientId ) );
      if ( !clientIdNode.isNull() ) {
        QDomElement clientIdElement = clientIdNode.toElement();
        item.clientId = clientIdElement.text();
        if ( item.clientId != item.sloxId )
          item.status = SloxItem::New;
      }

      QDomNode sloxStatus = prop.namedItem( res->fieldName( SloxBase::ObjectStatus ) );
      if ( !sloxStatus.isNull() ) {
        QDomElement sloxStatusElement = sloxStatus.toElement();
        if ( sloxStatusElement.text() == "DELETE" ) {
          item.status = SloxItem::Delete;
        } else if ( sloxStatusElement.text() == "CREATE" ) {
          item.status = SloxItem::Create;
        }
      }

      QDomNode status = propstat.namedItem( "status" );
      if ( status.isNull() ) {
        kdError() << "Unable to find WebDAV status" << endl;
        continue;
      }
      item.response = status.toElement().text();

      QDomNode desc = propstat.namedItem( "responsedescription" );
      if ( desc.isNull() ) {
        kdError() << "Unable to find WebDAV responsedescription" << endl;
        continue;
      }
      item.responseDescription = desc.toElement().text();

      items.append( item );
    }
  }

  return items;
}

QString WebdavHandler::qDateTimeToSlox( const QDateTime &dt )
{
  uint ticks = -dt.secsTo( QDateTime( QDate( 1970, 1, 1 ), QTime( 0, 0 ) ) );

  return QString::number( ticks ) + "000";
}

QString WebdavHandler::qDateTimeToSlox( const QDateTime &dt,
                                        const QString &timeZoneId )
{
  QDateTime utc = KPimPrefs::localTimeToUtc( dt, timeZoneId );

  // secsTo and toTime_t etc also perform a timezone conversion using the system timezone,
  // but we want to use the calendar timezone, so we have to convert ourself and spoof the tz to UTC before
  // converting to ticks to prevent this
  Q3CString origTz = getenv("TZ");
  setenv( "TZ", "UTC", 1 );
  uint ticks = utc.toTime_t();
  if ( origTz.isNull() )
    unsetenv( "TZ" );
  else
    setenv( "TZ", origTz, 1 );

  return QString::number( ticks ) + "000";
}

QDateTime WebdavHandler::sloxToQDateTime( const QString &str )
{
  QString s = str.mid( 0, str.length() - 3 );

  bool preEpoch = s.startsWith("-");
  if (preEpoch)
     s = s.mid(1);

  unsigned long ticks = s.toULong();

  QDateTime dt;

  if (preEpoch) {
    dt.setTime_t( 0, Qt::UTC );
    if (ticks > INT_MAX) {
      dt = dt.addSecs(-INT_MAX);
      ticks -= INT_MAX;
    }
    dt = dt.addSecs(-((long) ticks));
  }
  else
  {
    dt.setTime_t( ticks, Qt::UTC );
  }

  return dt;
}

QDateTime WebdavHandler::sloxToQDateTime( const QString &str,
                                          const QString &timeZoneId )
{
  return KPimPrefs::utcToLocalTime( sloxToQDateTime(str), timeZoneId );
}

QDomElement WebdavHandler::addElement( QDomDocument &doc, QDomNode &node,
                                       const QString &tag )
{
  QDomElement el = doc.createElement( tag );
  node.appendChild( el );
  return el;
}

QDomElement WebdavHandler::addDavElement( QDomDocument &doc, QDomNode &node,
                                          const QString &tag )
{
  QDomElement el = doc.createElementNS( "DAV:", "D:" + tag );
  node.appendChild( el );
  return el;
}

QDomElement WebdavHandler::addSloxElement( SloxBase *res,
                                           QDomDocument &doc, QDomNode &node,
                                           const QString &tag,
                                           const QString &text )
{
  QDomElement el;
  if ( res->resType() == "ox" )
    el = doc.createElementNS( "http://www.open-xchange.org", "ox:" + tag );
  else
    el = doc.createElementNS( "SLOX", "S:" + tag );
  if ( !text.isEmpty() ) {
    QDomText textnode = doc.createTextNode( text );
    el.appendChild( textnode );
  }
  node.appendChild( el );
  return el;
}

void WebdavHandler::parseSloxAttribute( const QDomElement &e )
{
//  kdDebug() << "parseSloxAttribute" << endl;

  QString tag = e.tagName();
  QString text = QString::fromUtf8( e.text().latin1() );
  if ( text.isEmpty() ) return;

  if ( tag == "owner" ) {
    if ( text == mUserId ) mWritable = true;
  } else if ( tag == "writerights" ) {
    QDomNode n;
    for( n = e.firstChild(); !n.isNull(); n = n.nextSibling() ) {
      QDomElement e2 = n.toElement();
      if ( e2.tagName() == "member" ) {
        if ( e2.text() == mUserId ) mWritable = true;
      }
      // TODO: Process group write rights
    }
  }
}

void WebdavHandler::clearSloxAttributeStatus()
{
  if ( mRes->resType() == "ox" )
    mWritable = true; // parseSloxAttribute() won't work for OX
  else
    mWritable = false;
}

void WebdavHandler::setSloxAttributes( KCal::Incidence *i )
{
  i->setReadOnly( !mWritable );
}

void WebdavHandler::setSloxAttributes( KABC::Addressee & )
{
  // FIXME: libkabc doesn't allow to set an individual addressee to read-only
}
<|endoftext|>


<commit_before><commit_msg>fdo#57950: remove consecutive append in basctl with StringBuffer<commit_after><|endoftext|>


<commit_before>/* File Name: server.c */
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
using namespace std;
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <univ/log.h>
#include <univ/univ.h>
#include <univ/threadpool.h>
using namespace Sloong;
using namespace Sloong::Universal;

#include "epollex.h"
#include "msgproc.h"
#include "serverconfig.h"

#include "userv.h"

SloongWallUS::SloongWallUS()
{
	m_pLog = new CLog();
    m_pEpoll = new CEpollEx();
    m_pMsgProc = new CMsgProc();
	m_pThreadPool = new CThreadPool();
}

SloongWallUS::~SloongWallUS()
{
	SAFE_DELETE(m_pEpoll);
	SAFE_DELETE(m_pMsgProc);
	m_pThreadPool->End();
	SAFE_DELETE(m_pThreadPool);
	SAFE_DELETE(m_pLog);
}

void SloongWallUS::Initialize(CServerConfig* config)
{
	m_nPriorityLevel = config->m_nPriorityLevel;
	m_pLog->Initialize(config->m_strLogPath, config->m_bDebug);
    m_pEpoll->Initialize(m_pLog,config->m_nPort,config->m_nThreadNum,config->m_nPriorityLevel);
    m_pMsgProc->Initialize(m_pLog,config->m_strScriptFolder);
	m_pThreadPool->Initialize(config->m_nThreadNum);
}

void SloongWallUS::Run()
{
	m_pThreadPool->AddTask(SloongWallUS::HandleEventWorkLoop, this, true);
	m_pThreadPool->Start();
	while (true)
	{
        SLEEP(1000);
	}
}

void* SloongWallUS::HandleEventWorkLoop(void* pParam)
{
	SloongWallUS* pThis = (SloongWallUS*)pParam;

	if (!pThis->m_pEpoll->m_EventSockList.empty())
	{
		unique_lock<mutex> eventLoc(pThis->m_pEpoll->m_oEventListMutex);
		if (pThis->m_pEpoll->m_EventSockList.empty())
			return NULL;

		// process read list.
		int sock = pThis->m_pEpoll->m_EventSockList.front();
		pThis->m_pEpoll->m_EventSockList.pop();
		eventLoc.unlock();

		CSockInfo* info = pThis->m_pEpoll->m_SockList[sock];
		if (!info) return NULL;

        for (int i = 0; i < pThis->m_nPriorityLevel || i == 0; i++ )
		{
			// if not empty
			while (!info->m_pReadList[i].empty())
			{
                if( info->m_oReadMutex.try_lock() == false )
                {
                    continue;
                }
                unique_lock<mutex> readLoc(info->m_oReadMutex,std::adopt_lock);
				// recheck is not empty when lock done.
				if (info->m_pReadList[i].empty())
				{
					readLoc.unlock();
					continue;
				}

				string msg = info->m_pReadList[i].front();
				info->m_pReadList[i].pop();
				readLoc.unlock();
				auto md5index = msg.find("|");
				auto swiftindex = msg.find("|", md5index + 1);
				string md5 = msg.substr(0, md5index);
				//int swift = boost::lexical_cast<int>(msg.substr(md5index, swiftindex - md5index));
				string swift = (msg.substr(md5index + 1, swiftindex - (md5index + 1)));
				string tmsg = msg.substr(swiftindex + 1);
				string rmd5 = CUniversal::MD5_Encoding(tmsg);
				CUniversal::touper(md5);
				CUniversal::touper(rmd5);
				if (md5 != rmd5)
				{
					// handle error.
					pThis->m_pEpoll->SendMessage(sock, i, swift, "-1|package check error");
					continue;
				}

				string strRes;
				char* pBuf = NULL;
				int nSize = pThis->m_pMsgProc->MsgProcess(info->m_pUserInfo, tmsg, strRes, pBuf);
				pThis->m_pEpoll->SendMessage(sock, i, swift, strRes, pBuf, nSize);
			}
		}

	}
	else
	{
		SLEEP(500);
	}
	return NULL;
}

<commit_msg>add exit cmd.<commit_after>/* File Name: server.c */
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
using namespace std;
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <univ/log.h>
#include <univ/univ.h>
#include <univ/threadpool.h>
using namespace Sloong;
using namespace Sloong::Universal;

#include "epollex.h"
#include "msgproc.h"
#include "serverconfig.h"

#include "userv.h"

SloongWallUS::SloongWallUS()
{
	m_pLog = new CLog();
    m_pEpoll = new CEpollEx();
    m_pMsgProc = new CMsgProc();
	m_pThreadPool = new CThreadPool();
}

SloongWallUS::~SloongWallUS()
{
	m_pThreadPool->End();
	SAFE_DELETE(m_pEpoll);
	SAFE_DELETE(m_pMsgProc);
	SAFE_DELETE(m_pThreadPool);
	SAFE_DELETE(m_pLog);
}

void SloongWallUS::Initialize(CServerConfig* config)
{
	m_nPriorityLevel = config->m_nPriorityLevel;
	m_pLog->Initialize(config->m_strLogPath, config->m_bDebug);
    m_pEpoll->Initialize(m_pLog,config->m_nPort,config->m_nThreadNum,config->m_nPriorityLevel);
    m_pMsgProc->Initialize(m_pLog,config->m_strScriptFolder);
	m_pThreadPool->Initialize(config->m_nThreadNum);
}

void SloongWallUS::Run()
{
	m_pThreadPool->AddTask(SloongWallUS::HandleEventWorkLoop, this, true);
	m_pThreadPool->Start();
	string cmd;
	while (true)
	{
		cmd.clear();
		cin >> cmd;
		if (cmd == "exit")
			return;
		else
			SLEEP(1000);
	}
}

void* SloongWallUS::HandleEventWorkLoop(void* pParam)
{
	SloongWallUS* pThis = (SloongWallUS*)pParam;

	if (!pThis->m_pEpoll->m_EventSockList.empty())
	{
		unique_lock<mutex> eventLoc(pThis->m_pEpoll->m_oEventListMutex);
		if (pThis->m_pEpoll->m_EventSockList.empty())
			return NULL;

		// process read list.
		int sock = pThis->m_pEpoll->m_EventSockList.front();
		pThis->m_pEpoll->m_EventSockList.pop();
		eventLoc.unlock();

		CSockInfo* info = pThis->m_pEpoll->m_SockList[sock];
		if (!info) return NULL;

        for (int i = 0; i < pThis->m_nPriorityLevel || i == 0; i++ )
		{
			// if not empty
			while (!info->m_pReadList[i].empty())
			{
                if( info->m_oReadMutex.try_lock() == false )
                {
                    continue;
                }
                unique_lock<mutex> readLoc(info->m_oReadMutex,std::adopt_lock);
				// recheck is not empty when lock done.
				if (info->m_pReadList[i].empty())
				{
					readLoc.unlock();
					continue;
				}

				string msg = info->m_pReadList[i].front();
				info->m_pReadList[i].pop();
				readLoc.unlock();
				auto md5index = msg.find("|");
				auto swiftindex = msg.find("|", md5index + 1);
				string md5 = msg.substr(0, md5index);
				//int swift = boost::lexical_cast<int>(msg.substr(md5index, swiftindex - md5index));
				string swift = (msg.substr(md5index + 1, swiftindex - (md5index + 1)));
				string tmsg = msg.substr(swiftindex + 1);
				string rmd5 = CUniversal::MD5_Encoding(tmsg);
				CUniversal::touper(md5);
				CUniversal::touper(rmd5);
				if (md5 != rmd5)
				{
					// handle error.
					pThis->m_pEpoll->SendMessage(sock, i, swift, "-1|package check error");
					continue;
				}

				string strRes;
				char* pBuf = NULL;
				int nSize = pThis->m_pMsgProc->MsgProcess(info->m_pUserInfo, tmsg, strRes, pBuf);
				pThis->m_pEpoll->SendMessage(sock, i, swift, strRes, pBuf, nSize);
			}
		}

	}
	else
	{
		SLEEP(500);
	}
	return NULL;
}

<|endoftext|>


<commit_before>// Copyright (c) 2015-2021 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include <tao/pegtl/file_input.hpp>

#if defined( _POSIX_MAPPED_FILES ) || defined( _WIN32 )

#include "test.hpp"

namespace TAO_PEGTL_NAMESPACE
{
   void unit_test()
   {
#if defined( __cpp_exceptions )
      const internal::file_opener fo( "Makefile" );
      ::close( fo.m_fd );  // Provoke exception, nobody would normally do this.
      try {
         (void)fo.size();  // expected to throw

         // LCOV_EXCL_START
         std::cerr << "pegtl: unit test failed for [ internal::file_opener ] " << std::endl;
         ++failed;
         // LCOV_EXCL_END
      }
      catch( const std::exception& ) {
      }
#endif
   }

}  // namespace TAO_PEGTL_NAMESPACE

#include "main.hpp"

#else

int main()
{
   return 0;
}

#endif
<commit_msg>Portable test<commit_after>// Copyright (c) 2015-2021 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include <tao/pegtl/file_input.hpp>

#if defined( _POSIX_MAPPED_FILES ) || defined( _WIN32 )

#include "test.hpp"

namespace TAO_PEGTL_NAMESPACE
{
   void unit_test()
   {
#if defined( __cpp_exceptions )
      const internal::file_opener fo( "Makefile" );
      fo.internal::~file_opener();  // Provoke exception, nobody would normally do this.
      try {
         (void)fo.size();  // expected to throw

         // LCOV_EXCL_START
         std::cerr << "pegtl: unit test failed for [ internal::file_opener ] " << std::endl;
         ++failed;
         // LCOV_EXCL_END
      }
      catch( const std::exception& ) {
      }
#endif
   }

}  // namespace TAO_PEGTL_NAMESPACE

#include "main.hpp"

#else

int main()
{
   return 0;
}

#endif
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <fstream>

struct Field {
  std::string name;
  std::string value;
};

using Fields = std::vector<Field>;

struct Entry {
  std::string type;
  std::string key;
  Fields fields;
  std::string comment;
};

using Entries = std::vector<Entry>;

enum ParserState {
  LIMBO,
  ENTRY_TYPE,
  ENTRY_KEY,
  FIELD_LIMBO,
  FIELD_NAME,
  FIELD_POST_EQUAL,
  FIELD_VALUE_TEXT,
  FIELD_VALUE_SPACE,
  COMMENT
};

enum FieldValueLimit {
  FVL_NONE,
  FVL_CURLY,
  FVL_QUOTE
};

static void make_lowercase(std::string& s) {
  std::transform(s.begin(), s.end(), s.begin(), ::tolower);
}

static std::string as_lowercase(std::string const& s) {
  std::string s2 = s;
  make_lowercase(s2);
  return s2;
}

static void print_entries(std::ostream& stream, Entries const& entries);

class Parser {
  ParserState state;
  int line;
  int column;
  int curly_depth;
  FieldValueLimit value_limit;
  Entries entries;

  bool is_curly(char c) {
    return c == '{' || c == '}';
  }

  void handle_curly(char c) {
    if (c == '{') ++curly_depth;
    if (c == '}') --curly_depth;
    if (curly_depth < 0) fail();
  }

  void fail() __attribute__((noreturn));

  bool field_value_ended(char c) {
    if (curly_depth != 0) return false;
    switch (value_limit) {
      case FVL_NONE: return c == ',';
      case FVL_CURLY: return c == '}';
      case FVL_QUOTE: return c == '"';
    }
  }

public:

  void run(std::istream& stream) {
    entries.clear();
    state = LIMBO;
    line = 1;
    column = 0;
    curly_depth = 0;
    char c;
    while (stream.get(c)) {
      if (c == '\n') {
        ++line;
        column = 0;
      } else {
        ++column;
      }
      switch (state) {
        case LIMBO:
          if (std::isspace(c)) break;
          else if (c == '@') {
            state = ENTRY_TYPE;
            entries.push_back(Entry());
          } else {
            entries.push_back(Entry());
            entries.back().type = "comment";
            entries.back().comment.push_back(c);
            state = COMMENT;
          }
        break;
        case ENTRY_TYPE:
          if (std::isspace(c)) {
            if (as_lowercase(entries.back().type) == "comment") {
              make_lowercase(entries.back().type);
              state = COMMENT;
            } else break;
          }
          else if (c == '{') {
            make_lowercase(entries.back().type);
            if (entries.back().type == "string") state = FIELD_LIMBO;
            else state = ENTRY_KEY;
          }
          else if (std::isalpha(c)) {
            entries.back().type.push_back(c);
          }
          else fail();
        break;
        case ENTRY_KEY:
          if (std::isspace(c)) break;
          else if (c == ',') {
            make_lowercase(entries.back().key);
            state = FIELD_LIMBO;
          }
          else if (std::isalnum(c)) {
            entries.back().key.push_back(c);
          }
          else fail();
        break;
        case FIELD_LIMBO:
          if (std::isspace(c)) break;
          else if (std::isalpha(c)) {
            entries.back().fields.push_back(Field());
            entries.back().fields.back().name.push_back(c);
            state = FIELD_NAME;
          } else if (c == '}') state = LIMBO;
          else if (c == ',') break;
          else fail();
        break;
        case FIELD_NAME:
          if (std::isspace(c)) break;
          else if (std::isalpha(c)) {
            entries.back().fields.back().name.push_back(c);
          } else if (c == '=') {
            make_lowercase(entries.back().fields.back().name);
            state = FIELD_POST_EQUAL;
          } else fail();
        break;
        case FIELD_POST_EQUAL:
          if (std::isspace(c)) break;
          else if (c == '{') {
            state = FIELD_VALUE_TEXT;
            value_limit = FVL_CURLY;
          } else if (c == '"') {
            state = FIELD_VALUE_TEXT;
            value_limit = FVL_QUOTE;
          } else if (std::isprint(c)) {
            value_limit = FVL_NONE;
            if (is_curly(c)) handle_curly(c);
            entries.back().fields.back().value.push_back(c);
            state = FIELD_VALUE_TEXT;
          } else fail();
        break;
        case FIELD_VALUE_TEXT:
          if (std::isspace(c)) state = FIELD_VALUE_SPACE;
          else if (field_value_ended(c)) {
            state = FIELD_LIMBO;
          } else if (std::isprint(c)) {
            if (is_curly(c)) handle_curly(c);
            entries.back().fields.back().value.push_back(c);
          } else fail();
        break;
        case FIELD_VALUE_SPACE:
          if (std::isspace(c)) break;
          else if (field_value_ended(c)) {
            state = FIELD_LIMBO;
          } else if (std::isprint(c)) {
            if (is_curly(c)) handle_curly(c);
            entries.back().fields.back().value.push_back(' ');
            entries.back().fields.back().value.push_back(c);
            state = FIELD_VALUE_TEXT;
          } else fail();
        break;
        case COMMENT:
          if (c == '\n') state = LIMBO;
          else entries.back().comment.push_back(c);
        break;
      }
    }
    if (state != LIMBO) {
      std::cout << "File ended early\n";
      exit(-1);
    }
  }

};

void Parser::fail() {
  std::cout << "Parse error at line " << line << " column " << column;
  std::cout << " state \"";
  switch (state) {
    case LIMBO: std::cout << "limbo"; break;
    case ENTRY_TYPE: std::cout << "entry type"; break;
    case ENTRY_KEY: std::cout << "entry key"; break;
    case FIELD_LIMBO: std::cout << "field limbo"; break;
    case FIELD_NAME: std::cout << "field name"; break;
    case FIELD_POST_EQUAL: std::cout << "field post equal"; break;
    case FIELD_VALUE_TEXT: std::cout << "field value text"; break;
    case FIELD_VALUE_SPACE: std::cout << "field value space"; break;
    case COMMENT: std::cout << "comment"; break;
  }
  std::cout << "\"\n";
  print_entries(std::cout, entries);
  exit(-1);
}

static void print_field(std::ostream& stream, Field const& field, bool last) {
  stream << "  " << field.name << "={" << field.value << "}";
  if (!last) stream << ",";
  stream << '\n';
}

static void print_fields(std::ostream& stream, Fields const& fields) {
  if (fields.empty()) return;
  for (size_t i = 0; i < fields.size() - 1; ++i)
    print_field(stream, fields[i], false);
  print_field(stream, fields.back(), true);
}

static void print_entry(std::ostream& stream, Entry const& entry) {
  if (entry.type == "comment") {
    stream << entry.comment << '\n';
    return;
  }
  stream << "@" << entry.type << "{";
  if (entry.type != "string") stream << entry.key << ",";
  stream << "\n";
  print_fields(stream, entry.fields);
  stream << "}\n\n";
}

static void print_entries(std::ostream& stream, Entries const& entries) {
  for (auto entry : entries) print_entry(stream, entry);
}

int main(int argc, char** argv) {
  if (argc != 2) {
    std::cout << "usage: " << argv[0] << " input.bib\n";
    return -1;
  }
  std::ifstream file(argv[1]);
  Parser parser;
  parser.run(file);
}
<commit_msg>allow other weird chars in entry key<commit_after>#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <fstream>

struct Field {
  std::string name;
  std::string value;
};

using Fields = std::vector<Field>;

struct Entry {
  std::string type;
  std::string key;
  Fields fields;
  std::string comment;
};

using Entries = std::vector<Entry>;

enum ParserState {
  LIMBO,
  ENTRY_TYPE,
  ENTRY_KEY,
  FIELD_LIMBO,
  FIELD_NAME,
  FIELD_POST_EQUAL,
  FIELD_VALUE_TEXT,
  FIELD_VALUE_SPACE,
  COMMENT
};

enum FieldValueLimit {
  FVL_NONE,
  FVL_CURLY,
  FVL_QUOTE
};

static void make_lowercase(std::string& s) {
  std::transform(s.begin(), s.end(), s.begin(), ::tolower);
}

static std::string as_lowercase(std::string const& s) {
  std::string s2 = s;
  make_lowercase(s2);
  return s2;
}

static void print_entries(std::ostream& stream, Entries const& entries);

class Parser {
  ParserState state;
  int line;
  int column;
  int curly_depth;
  FieldValueLimit value_limit;
  Entries entries;

  bool is_curly(char c) {
    return c == '{' || c == '}';
  }

  void handle_curly(char c) {
    if (c == '{') ++curly_depth;
    if (c == '}') --curly_depth;
    if (curly_depth < 0) fail();
  }

  void fail() __attribute__((noreturn));

  bool field_value_ended(char c) {
    if (curly_depth != 0) return false;
    switch (value_limit) {
      case FVL_NONE: return c == ',';
      case FVL_CURLY: return c == '}';
      case FVL_QUOTE: return c == '"';
    }
  }

  bool iskey(char c) {
    return std::isalnum(c) || c == '-' || c == '_' ||
      c == '.' || c == ':';
  }

public:

  void run(std::istream& stream) {
    entries.clear();
    state = LIMBO;
    line = 1;
    column = 0;
    curly_depth = 0;
    char c;
    while (stream.get(c)) {
      if (c == '\n') {
        ++line;
        column = 0;
      } else {
        ++column;
      }
      switch (state) {
        case LIMBO:
          if (std::isspace(c)) break;
          else if (c == '@') {
            state = ENTRY_TYPE;
            entries.push_back(Entry());
          } else {
            entries.push_back(Entry());
            entries.back().type = "comment";
            entries.back().comment.push_back(c);
            state = COMMENT;
          }
        break;
        case ENTRY_TYPE:
          if (std::isspace(c)) {
            if (as_lowercase(entries.back().type) == "comment") {
              make_lowercase(entries.back().type);
              state = COMMENT;
            } else break;
          }
          else if (c == '{') {
            make_lowercase(entries.back().type);
            if (entries.back().type == "string") state = FIELD_LIMBO;
            else state = ENTRY_KEY;
          }
          else if (std::isalpha(c)) {
            entries.back().type.push_back(c);
          }
          else fail();
        break;
        case ENTRY_KEY:
          if (std::isspace(c)) break;
          else if (c == ',') {
            make_lowercase(entries.back().key);
            state = FIELD_LIMBO;
          }
          else if (iskey(c)) {
            entries.back().key.push_back(c);
          }
          else fail();
        break;
        case FIELD_LIMBO:
          if (std::isspace(c)) break;
          else if (std::isalpha(c)) {
            entries.back().fields.push_back(Field());
            entries.back().fields.back().name.push_back(c);
            state = FIELD_NAME;
          } else if (c == '}') state = LIMBO;
          else if (c == ',') break;
          else fail();
        break;
        case FIELD_NAME:
          if (std::isspace(c)) break;
          else if (std::isalpha(c)) {
            entries.back().fields.back().name.push_back(c);
          } else if (c == '=') {
            make_lowercase(entries.back().fields.back().name);
            state = FIELD_POST_EQUAL;
          } else fail();
        break;
        case FIELD_POST_EQUAL:
          if (std::isspace(c)) break;
          else if (c == '{') {
            state = FIELD_VALUE_TEXT;
            value_limit = FVL_CURLY;
          } else if (c == '"') {
            state = FIELD_VALUE_TEXT;
            value_limit = FVL_QUOTE;
          } else if (std::isprint(c)) {
            value_limit = FVL_NONE;
            if (is_curly(c)) handle_curly(c);
            entries.back().fields.back().value.push_back(c);
            state = FIELD_VALUE_TEXT;
          } else fail();
        break;
        case FIELD_VALUE_TEXT:
          if (std::isspace(c)) state = FIELD_VALUE_SPACE;
          else if (field_value_ended(c)) {
            state = FIELD_LIMBO;
          } else if (std::isprint(c)) {
            if (is_curly(c)) handle_curly(c);
            entries.back().fields.back().value.push_back(c);
          } else fail();
        break;
        case FIELD_VALUE_SPACE:
          if (std::isspace(c)) break;
          else if (field_value_ended(c)) {
            state = FIELD_LIMBO;
          } else if (std::isprint(c)) {
            if (is_curly(c)) handle_curly(c);
            entries.back().fields.back().value.push_back(' ');
            entries.back().fields.back().value.push_back(c);
            state = FIELD_VALUE_TEXT;
          } else fail();
        break;
        case COMMENT:
          if (c == '\n') state = LIMBO;
          else entries.back().comment.push_back(c);
        break;
      }
    }
    if (state != LIMBO) {
      std::cout << "File ended early\n";
      exit(-1);
    }
  }

};

void Parser::fail() {
  std::cout << "Parse error at line " << line << " column " << column;
  std::cout << " state \"";
  switch (state) {
    case LIMBO: std::cout << "limbo"; break;
    case ENTRY_TYPE: std::cout << "entry type"; break;
    case ENTRY_KEY: std::cout << "entry key"; break;
    case FIELD_LIMBO: std::cout << "field limbo"; break;
    case FIELD_NAME: std::cout << "field name"; break;
    case FIELD_POST_EQUAL: std::cout << "field post equal"; break;
    case FIELD_VALUE_TEXT: std::cout << "field value text"; break;
    case FIELD_VALUE_SPACE: std::cout << "field value space"; break;
    case COMMENT: std::cout << "comment"; break;
  }
  std::cout << "\"\n";
  print_entries(std::cout, entries);
  exit(-1);
}

static void print_field(std::ostream& stream, Field const& field, bool last) {
  stream << "  " << field.name << "={" << field.value << "}";
  if (!last) stream << ",";
  stream << '\n';
}

static void print_fields(std::ostream& stream, Fields const& fields) {
  if (fields.empty()) return;
  for (size_t i = 0; i < fields.size() - 1; ++i)
    print_field(stream, fields[i], false);
  print_field(stream, fields.back(), true);
}

static void print_entry(std::ostream& stream, Entry const& entry) {
  if (entry.type == "comment") {
    stream << entry.comment << '\n';
    return;
  }
  stream << "@" << entry.type << "{";
  if (entry.type != "string") stream << entry.key << ",";
  stream << "\n";
  print_fields(stream, entry.fields);
  stream << "}\n\n";
}

static void print_entries(std::ostream& stream, Entries const& entries) {
  for (auto entry : entries) print_entry(stream, entry);
}

int main(int argc, char** argv) {
  if (argc != 2) {
    std::cout << "usage: " << argv[0] << " input.bib\n";
    return -1;
  }
  std::ifstream file(argv[1]);
  Parser parser;
  parser.run(file);
}
<|endoftext|>


<commit_before>#include "quiz.h"

#define TITLE "SOME GREAT AWESOME TITLE HERE"

extern question questions[3][3][3];

int height, width;

void init_ui()
{
	textcolor(LIGHTGRAY);
	textbackground(BLACK);

	struct text_info info;
	gettextinfo(&info);

	width = (int) info.screenwidth;
	height = (int) info.screenheight;
}

void frame(coord up_left, int f_height, int f_width, int f_sides)
{
	char l_up = (char) 201;
	char l_down = (char) 200;
	char r_up = (char) 187;
	char r_down = (char) 188;
	char bet_ver = (char) 186;
	char bet_hor = (char) 205;

	if(up_left.x == -1)
	{
		coord b(1,1);
		up_left = b;
		f_width = width;
		f_height = height - 1;
	}

	gotoxy(up_left.x, up_left.y);

	cout << l_up;
	for(int i = 0; i < f_width - 2; i++)
	{
		cout << bet_hor;
	}
	cout << r_up;

	if(f_sides)
	{
		for(i = 2; i <= f_height - 1; i++)
		{
			gotoxy(up_left.x, i); cout << bet_ver;
			gotoxy(up_left.x + f_width - 1, i); cout << bet_ver;
		}
	}

	gotoxy(up_left.x, up_left.y + f_height + 1);
	cout << l_down;
	for(i = 0; i < f_width - 2; i++)
	{
		cout << bet_hor;
	}
	cout << r_down;

	gotoxy(up_left.x + 2, up_left.y + 2);
}

void printc(char str[], int ws, int t_color, int b_color)
{
	if(ws == -1)
	{
		gotoxy((width - strlen(str))/2 ,wherey());
	}
	else
	{
		gotoxy(ws + 1, wherey());
	}

	textcolor(t_color);
	textbackground(b_color);
	cprintf("%s", str);
}

/*
 Generates user interface
 Screen_num:
	1: difficulty level
	2: Subject
*/
int generate_ui(int screen_num)
{
	clrscr();
	frame();

	char title[] = TITLE;
	char head[100], op1[100], op2[100], op3[100];
	if(screen_num == 1)
	{
		strcpy(head, "Select difficulty level: ");
		strcpy(op1, "Easy");
		strcpy(op2, "Intermediate");
		strcpy(op3, "Hard");
	}
	else if(screen_num == 2)
	{
		strcpy(head, "Select subject: ");
		strcpy(op1, "Computer Science (C++)");
		strcpy(op2, "General Knowledge");
		strcpy(op3, "English");
	}

	gotoxy(1, (height - 6) / 2);

	printc(title);
	cout << "\n\n";

	int lengths[] = {
					  strlen(head),
					  strlen(op1),
					  strlen(op2),
					  strlen(op3),
					};

	//Determining max length
	int max_len = lengths[0];
	for(int i = 0; i < 4; i++)
	{
		for(int j = i + 1; j < 4; j++)
		{
			if(lengths[j] > max_len)
			{
				max_len = lengths[j];
			}
		}
	}

	int a = (width - max_len) / 2;
	coord b(a - 4,wherey());
	frame(b, 6, max_len + 8, 0);

	printc(head, a);
	cout << '\n';

	coord bullet1(b.x + 2, wherey());

	gotoxy(bullet1.x + 2, bullet1.y); printc(op1, a); cout << '\n';
	gotoxy(bullet1.x + 2, bullet1.y + 1); printc(op2, a); cout << '\n';
	gotoxy(bullet1.x + 2, bullet1.y + 2); printc(op3, a); cout << '\n';

	return select(bullet1, 3);
}

int generate_ui(int lvl, int sub, int q_num)
{
	clrscr();
	frame();

	gotoxy(2,2); cout << "Difficulty: ";
	switch(lvl)
	{
		case 0:
			cout << "Easy";
			break;
		case 1:
			cout << "Intermediate";
			break;
		case 2:
			cout << "Hard";
			break;
	}

	char print[100] = "Subject: ";
	switch(sub)
	{
		case 0:
			strcat(print, "C++");
			break;
		case 1:
			strcat(print, "G.K.");
			break;
		case 2:
			strcat(print, "English");
			break;
	}
	gotoxy(width - strlen(print), 2);
	cout << print;

	char ques[200], options[4][200];

	strcpy(ques, questions[lvl][sub][q_num].q);
	strcpy(options[0], questions[lvl][sub][q_num].options[0]);
	strcpy(options[1], questions[lvl][sub][q_num].options[1]);
	strcpy(options[2], questions[lvl][sub][q_num].options[2]);
	strcpy(options[3], questions[lvl][sub][q_num].options[3]);

	int f_width = (8 * width) / 10;
	int ws = (width - f_width) / 2;

	int lengths[] = {
					 strlen(ques),
					 strlen(options[0]),
					 strlen(options[1]),
					 strlen(options[2]),
					 strlen(options[3])
					};

	int f_height = 2 + lengths[0] / f_width + 1;
	int f_ws = 3;  //Whitespace inside frame for options
	for(int i = 1; i < 5; i++)
	{
		f_height += lengths[i] / (f_width - f_ws) + 1;
	}

	coord u_left(ws + 1, (height - f_height) / 2 + 1);
	frame(u_left, f_height, f_width, 0);

	char printq[] = "Question ";
	gotoxy((width - strlen(printq) - 1) / 2 + 1, 2);
	cout << printq << q_num + 1;

	gotoxy(1, (height - f_height) / 2 - 3);
	printc(TITLE);

	char fstring[200] = "";

	int height_ops[4] = {0,0,0,0};
	int height_ques = wrap(ques, fstring, f_width - f_ws);

	int line_num = 1;
	char line[200];
	int read;
	int chars_read = 0;
	coord ques_coord(u_left.x + 1, u_left.y + 2);

	for(i = 0; i < height_ques; i++)
	{
		sscanf(fstring + chars_read, "%[^\n]%*c%n", line, &read);
		gotoxy(ques_coord.x + 2, ques_coord.y + line_num - 1);
		cout << line;
		line_num++;
		chars_read += read;
	}

	strcpy(fstring, "");

	coord bullet1(ques_coord.x, ques_coord.y + height_ques);

	for(i = 0; i < 4; i++)
	{
		height_ops[i] = wrap(options[i], fstring, f_width - f_ws - 3 - 2);
		read = 0, chars_read = 0;

		int len = strlen(fstring);
		fstring[len] = '\n'; fstring[len+1] = '\0';

		coord op_start(bullet1.x + 2 + 3, bullet1.y); // x: +2 space for bullet, +3 space for option letter

		for(int j = 0; j < i; j++)
		{
			op_start.y += height_ops[j];
		}

		gotoxy(bullet1.x + 2, op_start.y);
		cout << (char) ('A' + i) << ". ";

		for(j = 0; j < height_ops[i]; j++)
		{
			sscanf(fstring + chars_read, "%[^\n]%*c%n", line, &read);
			gotoxy(op_start.x, op_start.y + j);
			line_num++;
			cout << line;
			chars_read += read;
		}

		strcpy(fstring, "");
	}

	int selected_ans = select(bullet1, 4, height_ops) + 1;
	gotoxy(1, (height - f_height) / 2 - 1);
	if(selected_ans == questions[lvl][sub][q_num].correct)
	{
		printc("Correct Answer!!");
		return 1;
	}
	else
	{
		char pr[] = "Incorrect Answer!! Correct answer was ";
		char a[2] = {(char) ('A' + questions[lvl][sub][q_num].correct - 1),'\0'};
		strcat(pr,a);
		printc(pr);
		return 0;
	}

}

int select(coord line1, int num_ops, char bullet)
{
	int height_ops[] = {1,1,1,1,1};
	return select(line1, num_ops, height_ops, bullet);
}

int select(coord line1, int num_ops, int height_ops[], char bullet)
{
	int curr_line = 0;
	gotoxy(line1.x, line1.y); cout << bullet;
	while(1)
	{
		char c = getch();

		if(c == 0)
		{
			c = getch();
			switch(c)
			{
				case 'H':
					curr_line == 0 ? curr_line = num_ops - 1 : curr_line--;
					break;
				case 'P':
					curr_line == num_ops - 1 ? curr_line = 0 : curr_line++;
					break;
			}
		}
		else if(c == 13)
		{
			return curr_line;
		}

		for(int i = 0; i < num_ops; i++)
		{
			coord bullet_pos;

			bullet_pos.x = line1.x;
			bullet_pos.y = line1.y;
			for(int j = 0; j < i; j++)
			{
				bullet_pos.y += height_ops[j];
			}

			gotoxy(bullet_pos.x, bullet_pos.y);

			if(i == curr_line)
			{
				cout << bullet;
			}
			else
			{
				cout << ' ';
			}
		}
	}
}
<commit_msg>Added title<commit_after>#include "quiz.h"

#define TITLE "TEST YOUR KNOWLEDGE!"

extern question questions[3][3][3];

int height, width;

void init_ui()
{
	textcolor(LIGHTGRAY);
	textbackground(BLACK);

	struct text_info info;
	gettextinfo(&info);

	width = (int) info.screenwidth;
	height = (int) info.screenheight;
}

void frame(coord up_left, int f_height, int f_width, int f_sides)
{
	char l_up = (char) 201;
	char l_down = (char) 200;
	char r_up = (char) 187;
	char r_down = (char) 188;
	char bet_ver = (char) 186;
	char bet_hor = (char) 205;

	if(up_left.x == -1)
	{
		coord b(1,1);
		up_left = b;
		f_width = width;
		f_height = height - 1;
	}

	gotoxy(up_left.x, up_left.y);

	cout << l_up;
	for(int i = 0; i < f_width - 2; i++)
	{
		cout << bet_hor;
	}
	cout << r_up;

	if(f_sides)
	{
		for(i = 2; i <= f_height - 1; i++)
		{
			gotoxy(up_left.x, i); cout << bet_ver;
			gotoxy(up_left.x + f_width - 1, i); cout << bet_ver;
		}
	}

	gotoxy(up_left.x, up_left.y + f_height + 1);
	cout << l_down;
	for(i = 0; i < f_width - 2; i++)
	{
		cout << bet_hor;
	}
	cout << r_down;

	gotoxy(up_left.x + 2, up_left.y + 2);
}

void printc(char str[], int ws, int t_color, int b_color)
{
	if(ws == -1)
	{
		gotoxy((width - strlen(str))/2 ,wherey());
	}
	else
	{
		gotoxy(ws + 1, wherey());
	}

	textcolor(t_color);
	textbackground(b_color);
	cprintf("%s", str);
}

/*
 Generates user interface
 Screen_num:
	1: difficulty level
	2: Subject
*/
int generate_ui(int screen_num)
{
	clrscr();
	frame();

	char title[] = TITLE;
	char head[100], op1[100], op2[100], op3[100];
	if(screen_num == 1)
	{
		strcpy(head, "Select difficulty level: ");
		strcpy(op1, "Easy");
		strcpy(op2, "Intermediate");
		strcpy(op3, "Hard");
	}
	else if(screen_num == 2)
	{
		strcpy(head, "Select subject: ");
		strcpy(op1, "Computer Science (C++)");
		strcpy(op2, "General Knowledge");
		strcpy(op3, "English");
	}

	gotoxy(1, (height - 6) / 2);

	printc(title);
	cout << "\n\n";

	int lengths[] = {
					  strlen(head),
					  strlen(op1),
					  strlen(op2),
					  strlen(op3),
					};

	//Determining max length
	int max_len = lengths[0];
	for(int i = 0; i < 4; i++)
	{
		for(int j = i + 1; j < 4; j++)
		{
			if(lengths[j] > max_len)
			{
				max_len = lengths[j];
			}
		}
	}

	int a = (width - max_len) / 2;
	coord b(a - 4,wherey());
	frame(b, 6, max_len + 8, 0);

	printc(head, a);
	cout << '\n';

	coord bullet1(b.x + 2, wherey());

	gotoxy(bullet1.x + 2, bullet1.y); printc(op1, a); cout << '\n';
	gotoxy(bullet1.x + 2, bullet1.y + 1); printc(op2, a); cout << '\n';
	gotoxy(bullet1.x + 2, bullet1.y + 2); printc(op3, a); cout << '\n';

	return select(bullet1, 3);
}

int generate_ui(int lvl, int sub, int q_num)
{
	clrscr();
	frame();

	gotoxy(2,2); cout << "Difficulty: ";
	switch(lvl)
	{
		case 0:
			cout << "Easy";
			break;
		case 1:
			cout << "Intermediate";
			break;
		case 2:
			cout << "Hard";
			break;
	}

	char print[100] = "Subject: ";
	switch(sub)
	{
		case 0:
			strcat(print, "C++");
			break;
		case 1:
			strcat(print, "G.K.");
			break;
		case 2:
			strcat(print, "English");
			break;
	}
	gotoxy(width - strlen(print), 2);
	cout << print;

	char ques[200], options[4][200];

	strcpy(ques, questions[lvl][sub][q_num].q);
	strcpy(options[0], questions[lvl][sub][q_num].options[0]);
	strcpy(options[1], questions[lvl][sub][q_num].options[1]);
	strcpy(options[2], questions[lvl][sub][q_num].options[2]);
	strcpy(options[3], questions[lvl][sub][q_num].options[3]);

	int f_width = (8 * width) / 10;
	int ws = (width - f_width) / 2;

	int lengths[] = {
					 strlen(ques),
					 strlen(options[0]),
					 strlen(options[1]),
					 strlen(options[2]),
					 strlen(options[3])
					};

	int f_height = 2 + lengths[0] / f_width + 1;
	int f_ws = 3;  //Whitespace inside frame for options
	for(int i = 1; i < 5; i++)
	{
		f_height += lengths[i] / (f_width - f_ws) + 1;
	}

	coord u_left(ws + 1, (height - f_height) / 2 + 1);
	frame(u_left, f_height, f_width, 0);

	char printq[] = "Question ";
	gotoxy((width - strlen(printq) - 1) / 2 + 1, 2);
	cout << printq << q_num + 1;

	gotoxy(1, (height - f_height) / 2 - 3);
	printc(TITLE);

	char fstring[200] = "";

	int height_ops[4] = {0,0,0,0};
	int height_ques = wrap(ques, fstring, f_width - f_ws);

	int line_num = 1;
	char line[200];
	int read;
	int chars_read = 0;
	coord ques_coord(u_left.x + 1, u_left.y + 2);

	for(i = 0; i < height_ques; i++)
	{
		sscanf(fstring + chars_read, "%[^\n]%*c%n", line, &read);
		gotoxy(ques_coord.x + 2, ques_coord.y + line_num - 1);
		cout << line;
		line_num++;
		chars_read += read;
	}

	strcpy(fstring, "");

	coord bullet1(ques_coord.x, ques_coord.y + height_ques);

	for(i = 0; i < 4; i++)
	{
		height_ops[i] = wrap(options[i], fstring, f_width - f_ws - 3 - 2);
		read = 0, chars_read = 0;

		int len = strlen(fstring);
		fstring[len] = '\n'; fstring[len+1] = '\0';

		coord op_start(bullet1.x + 2 + 3, bullet1.y); // x: +2 space for bullet, +3 space for option letter

		for(int j = 0; j < i; j++)
		{
			op_start.y += height_ops[j];
		}

		gotoxy(bullet1.x + 2, op_start.y);
		cout << (char) ('A' + i) << ". ";

		for(j = 0; j < height_ops[i]; j++)
		{
			sscanf(fstring + chars_read, "%[^\n]%*c%n", line, &read);
			gotoxy(op_start.x, op_start.y + j);
			line_num++;
			cout << line;
			chars_read += read;
		}

		strcpy(fstring, "");
	}

	int selected_ans = select(bullet1, 4, height_ops) + 1;
	gotoxy(1, (height - f_height) / 2 - 1);
	if(selected_ans == questions[lvl][sub][q_num].correct)
	{
		printc("Correct Answer!!");
		return 1;
	}
	else
	{
		char pr[] = "Incorrect Answer!! Correct answer was ";
		char a[2] = {(char) ('A' + questions[lvl][sub][q_num].correct - 1),'\0'};
		strcat(pr,a);
		printc(pr);
		return 0;
	}

}

int select(coord line1, int num_ops, char bullet)
{
	int height_ops[] = {1,1,1,1,1};
	return select(line1, num_ops, height_ops, bullet);
}

int select(coord line1, int num_ops, int height_ops[], char bullet)
{
	int curr_line = 0;
	gotoxy(line1.x, line1.y); cout << bullet;
	while(1)
	{
		char c = getch();

		if(c == 0)
		{
			c = getch();
			switch(c)
			{
				case 'H':
					curr_line == 0 ? curr_line = num_ops - 1 : curr_line--;
					break;
				case 'P':
					curr_line == num_ops - 1 ? curr_line = 0 : curr_line++;
					break;
			}
		}
		else if(c == 13)
		{
			return curr_line;
		}

		for(int i = 0; i < num_ops; i++)
		{
			coord bullet_pos;

			bullet_pos.x = line1.x;
			bullet_pos.y = line1.y;
			for(int j = 0; j < i; j++)
			{
				bullet_pos.y += height_ops[j];
			}

			gotoxy(bullet_pos.x, bullet_pos.y);

			if(i == curr_line)
			{
				cout << bullet;
			}
			else
			{
				cout << ' ';
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * 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 <fcntl.h>
#include <getopt.h>
#include <sys/stat.h>
#include <unistd.h>

#include <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>

#include "perfetto/base/logging.h"
#include "perfetto/base/scoped_file.h"
#include "perfetto/base/unix_task_runner.h"
#include "perfetto/base/utils.h"
#include "perfetto/protozero/proto_utils.h"
#include "perfetto/traced/traced.h"
#include "perfetto/tracing/core/consumer.h"
#include "perfetto/tracing/core/data_source_config.h"
#include "perfetto/tracing/core/data_source_descriptor.h"
#include "perfetto/tracing/core/trace_config.h"
#include "perfetto/tracing/core/trace_packet.h"
#include "perfetto/tracing/ipc/consumer_ipc_client.h"

#include "perfetto/config/trace_config.pb.h"

#if defined(PERFETTO_BUILD_WITH_ANDROID)
#include "perfetto/base/android_task_runner.h"

#include <android/os/DropBoxManager.h>
#include <utils/Looper.h>
#include <utils/StrongPointer.h>
#endif  // defined(PERFETTO_BUILD_WITH_ANDROID)

// TODO(primiano): add the ability to pass the file descriptor directly to the
// traced service instead of receiving a copy of the chunks and writing them
// from this process.
namespace perfetto {
namespace {
const char kTempTraceDir[] = "/data/misc/perfetto-traces";
const char kDefaultDropBoxTag[] = "perfetto";
}  // namespace

using protozero::proto_utils::WriteVarInt;
using protozero::proto_utils::MakeTagLengthDelimited;

#if defined(PERFETTO_BUILD_WITH_ANDROID)
using PlatformTaskRunner = base::AndroidTaskRunner;
#else
using PlatformTaskRunner = base::UnixTaskRunner;
#endif

class PerfettoCmd : public Consumer {
 public:
  int Main(int argc, char** argv);
  int PrintUsage(const char* argv0);
  void OnStopTraceTimer();
  void OnTimeout();

  // perfetto::Consumer implementation.
  void OnConnect() override;
  void OnDisconnect() override;
  void OnTraceData(std::vector<TracePacket>, bool has_more) override;

 private:
  base::ScopedFile CreateTemporaryFile(std::string* out_path);
  void SaveTraceFileAs(const std::string& name);

  PlatformTaskRunner task_runner_;
  std::unique_ptr<perfetto::Service::ConsumerEndpoint> consumer_endpoint_;
  std::unique_ptr<TraceConfig> trace_config_;
  base::ScopedFstream trace_out_stream_;
  std::string trace_out_path_;

  // Only used if linkat(AT_FDCWD) isn't available.
  std::string tmp_trace_out_path_;

  std::string dropbox_tag_;
  bool did_process_full_trace_ = false;
};

int PerfettoCmd::PrintUsage(const char* argv0) {
  PERFETTO_ELOG(R"(
Usage: %s
  --background  -b     : Exits immediately and continues tracing in background
  --config      -c     : /path/to/trace/config/file or - for stdin
  --out         -o     : /path/to/out/trace/file
  --dropbox     -d TAG : Upload trace into DropBox using tag TAG (default: %s)
  --help        -h
)",
                argv0, kDefaultDropBoxTag);
  return 1;
}

int PerfettoCmd::Main(int argc, char** argv) {
  static const struct option long_options[] = {
      // |option_index| relies on the order of options, don't reshuffle them.
      {"help", required_argument, 0, 'h'},
      {"config", required_argument, 0, 'c'},
      {"out", required_argument, 0, 'o'},
      {"background", no_argument, 0, 'b'},
      {"dropbox", optional_argument, 0, 'd'},
      {nullptr, 0, nullptr, 0}};

  int option_index = 0;
  std::string trace_config_raw;
  bool background = false;
  for (;;) {
    int option =
        getopt_long(argc, argv, "c:o:bd::", long_options, &option_index);

    if (option == -1)
      break;  // EOF.

    if (option == 'c') {
      if (strcmp(optarg, "-") == 0) {
        std::istreambuf_iterator<char> begin(std::cin), end;
        trace_config_raw.assign(begin, end);
      } else if (strcmp(optarg, ":test") == 0) {
        // TODO(primiano): temporary for testing only.
        perfetto::protos::TraceConfig test_config;
        test_config.add_buffers()->set_size_kb(4096);
        test_config.set_duration_ms(10000);
        auto* ds_config = test_config.add_data_sources()->mutable_config();
        ds_config->set_name("com.google.perfetto.ftrace");
        ds_config->mutable_ftrace_config()->add_event_names("sched_switch");
        ds_config->mutable_ftrace_config()->add_event_names("cpu_idle");
        ds_config->mutable_ftrace_config()->add_event_names("cpu_frequency");
        ds_config->set_target_buffer(0);
        test_config.SerializeToString(&trace_config_raw);
      } else {
        std::ifstream file_stream;
        file_stream.open(optarg, std::ios_base::in | std::ios_base::binary);
        if (!file_stream.is_open()) {
          PERFETTO_ELOG("Could not open %s", optarg);
          return 1;
        }
        std::istreambuf_iterator<char> begin(file_stream), end;
        trace_config_raw.assign(begin, end);
      }
      continue;
    }

    if (option == 'o') {
      trace_out_path_ = optarg;
      continue;
    }

    if (option == 'd') {
#if defined(PERFETTO_BUILD_WITH_ANDROID)
      dropbox_tag_ = optarg ? optarg : kDefaultDropBoxTag;
      continue;
#else
      PERFETTO_ELOG("DropBox is only supported with Android tree builds");
      return 1;
#endif
    }

    if (option == 'b') {
      background = true;
      continue;
    }
    return PrintUsage(argv[0]);
  }

  if (!trace_out_path_.empty() && !dropbox_tag_.empty()) {
    PERFETTO_ELOG(
        "Can't log to a file (--out) and DropBox (--dropbox) at the same "
        "time");
    return 1;
  }

  if (trace_config_raw.empty() ||
      (trace_out_path_.empty() && dropbox_tag_.empty())) {
    return PrintUsage(argv[0]);
  }

  if (access(kTempTraceDir, F_OK) == -1 && mkdir(kTempTraceDir, 0770) == -1) {
    PERFETTO_ELOG("Could not create temporary trace directory: %s",
                  kTempTraceDir);
    return 1;
  }

  base::ScopedFile fd;
  fd = CreateTemporaryFile(&tmp_trace_out_path_);
  trace_out_stream_.reset(fdopen(fd.release(), "wb"));
  PERFETTO_CHECK(trace_out_stream_);

  perfetto::protos::TraceConfig trace_config_proto;
  PERFETTO_DLOG("Parsing TraceConfig, %zu bytes", trace_config_raw.size());
  bool parsed = trace_config_proto.ParseFromString(trace_config_raw);
  if (!parsed) {
    PERFETTO_ELOG("Could not parse TraceConfig proto from stdin");
    return 1;
  }
  trace_config_.reset(new TraceConfig());
  trace_config_->FromProto(trace_config_proto);
  trace_config_raw.clear();

  if (background) {
    PERFETTO_CHECK(daemon(0 /*nochdir*/, 0 /*noclose*/) == 0);
    PERFETTO_DLOG("Continuing in background");
  }

  consumer_endpoint_ = ConsumerIPCClient::Connect(PERFETTO_CONSUMER_SOCK_NAME,
                                                  this, &task_runner_);
  task_runner_.Run();
  return did_process_full_trace_ ? 0 : 1;
}  // namespace perfetto

void PerfettoCmd::OnConnect() {
  PERFETTO_LOG(
      "Connected to the Perfetto traced service, starting tracing for %d ms",
      trace_config_->duration_ms());
  PERFETTO_DCHECK(trace_config_);
  consumer_endpoint_->EnableTracing(*trace_config_);
  task_runner_.PostDelayedTask(std::bind(&PerfettoCmd::OnStopTraceTimer, this),
                               trace_config_->duration_ms());

  // Failsafe mechanism to avoid waiting indefinitely if the service hangs.
  task_runner_.PostDelayedTask(std::bind(&PerfettoCmd::OnTimeout, this),
                               trace_config_->duration_ms() * 2);
}

void PerfettoCmd::OnDisconnect() {
  PERFETTO_LOG("Disconnected from the Perfetto traced service");
  task_runner_.Quit();
}

void PerfettoCmd::OnStopTraceTimer() {
  PERFETTO_LOG("Timer expired, disabling tracing and collecting results");
  consumer_endpoint_->DisableTracing();
  consumer_endpoint_->ReadBuffers();
}

void PerfettoCmd::OnTimeout() {
  PERFETTO_ELOG("Timed out while waiting for trace from the service, aborting");
  task_runner_.Quit();
}

void PerfettoCmd::OnTraceData(std::vector<TracePacket> packets, bool has_more) {
  PERFETTO_DLOG("Received trace packet, has_more=%d", has_more);
  for (TracePacket& packet : packets) {
    for (const Chunk& chunk : packet) {
      uint8_t preamble[16];
      uint8_t* pos = preamble;
      pos = WriteVarInt(MakeTagLengthDelimited(1 /* field_id */), pos);
      pos = WriteVarInt(static_cast<uint32_t>(chunk.size), pos);
      fwrite(reinterpret_cast<const char*>(preamble), pos - preamble, 1,
             trace_out_stream_.get());
      fwrite(reinterpret_cast<const char*>(chunk.start), chunk.size, 1,
             trace_out_stream_.get());
    }
  }
  if (has_more)
    return;

  // Reached end of trace.
  consumer_endpoint_->FreeBuffers();
  task_runner_.Quit();

  long bytes_written = ftell(trace_out_stream_.get());
  if (!dropbox_tag_.empty()) {
#if defined(PERFETTO_BUILD_WITH_ANDROID)
    // DropBox needs a path to the uploaded file, so make a temporarily visible
    // file.
    // TODO(skyostil): Modify DropBox to take an fd directly.
    std::string tmp_path;
    CreateTemporaryFile(&tmp_path);
    SaveTraceFileAs(tmp_path);

    android::sp<android::os::DropBoxManager> dropbox =
        new android::os::DropBoxManager();
    android::binder::Status status = dropbox->addFile(
        android::String16(dropbox_tag_.c_str()), tmp_path, 0 /* flags */);
    unlink(tmp_path.c_str());
    if (!status.isOk()) {
      PERFETTO_ELOG("DropBox upload failed: %s", status.toString8().c_str());
      return;
    }
    PERFETTO_ILOG("Uploaded %ld bytes into DropBox with tag %s", bytes_written,
                  dropbox_tag_.c_str());
#endif  // defined(PERFETTO_BUILD_WITH_ANDROID)
  } else {
    SaveTraceFileAs(trace_out_path_);
    PERFETTO_ILOG("Wrote %ld bytes into %s", bytes_written,
                  trace_out_path_.c_str());
  }
  did_process_full_trace_ = true;
}

base::ScopedFile PerfettoCmd::CreateTemporaryFile(std::string* out_path) {
  *out_path = std::string(kTempTraceDir) + "/perfetto-traceXXXXXX";
  return base::ScopedFile(mkstemp(&(*out_path)[0]));
}

void PerfettoCmd::SaveTraceFileAs(const std::string& name) {
  PERFETTO_DCHECK(trace_out_stream_);
  PERFETTO_CHECK(rename(tmp_trace_out_path_.c_str(), name.c_str()) == 0);
  trace_out_stream_.reset();
}

int __attribute__((visibility("default")))
PerfettoCmdMain(int argc, char** argv) {
  perfetto::PerfettoCmd consumer_cmd;
  return consumer_cmd.Main(argc, argv);
}

}  // namespace perfetto
<commit_msg>Pass trace fd directly to DropBox am: 0b99a3bbd5<commit_after>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * 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 <fcntl.h>
#include <getopt.h>
#include <sys/stat.h>
#include <unistd.h>

#include <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>

#include "perfetto/base/logging.h"
#include "perfetto/base/scoped_file.h"
#include "perfetto/base/unix_task_runner.h"
#include "perfetto/base/utils.h"
#include "perfetto/protozero/proto_utils.h"
#include "perfetto/traced/traced.h"
#include "perfetto/tracing/core/consumer.h"
#include "perfetto/tracing/core/data_source_config.h"
#include "perfetto/tracing/core/data_source_descriptor.h"
#include "perfetto/tracing/core/trace_config.h"
#include "perfetto/tracing/core/trace_packet.h"
#include "perfetto/tracing/ipc/consumer_ipc_client.h"

#include "perfetto/config/trace_config.pb.h"

#if defined(PERFETTO_BUILD_WITH_ANDROID)
#include "perfetto/base/android_task_runner.h"

#include <android/os/DropBoxManager.h>
#include <utils/Looper.h>
#include <utils/StrongPointer.h>
#endif  // defined(PERFETTO_BUILD_WITH_ANDROID)

// TODO(primiano): add the ability to pass the file descriptor directly to the
// traced service instead of receiving a copy of the chunks and writing them
// from this process.
namespace perfetto {
namespace {

// Temporary directory for DropBox traces. Note that this is automatically
// created by the system by setting setprop persist.traced.enable=1.
const char kTempDropBoxTraceDir[] = "/data/misc/perfetto-traces";
const char kDefaultDropBoxTag[] = "perfetto";

std::string GetDirName(const std::string& path) {
  size_t sep = path.find_last_of('/');
  if (sep == std::string::npos)
    return ".";
  return path.substr(0, sep);
}

}  // namespace

using protozero::proto_utils::WriteVarInt;
using protozero::proto_utils::MakeTagLengthDelimited;

#if defined(PERFETTO_BUILD_WITH_ANDROID)
using PlatformTaskRunner = base::AndroidTaskRunner;
#else
using PlatformTaskRunner = base::UnixTaskRunner;
#endif

class PerfettoCmd : public Consumer {
 public:
  int Main(int argc, char** argv);
  int PrintUsage(const char* argv0);
  void OnStopTraceTimer();
  void OnTimeout();

  // perfetto::Consumer implementation.
  void OnConnect() override;
  void OnDisconnect() override;
  void OnTraceData(std::vector<TracePacket>, bool has_more) override;

 private:
  bool OpenOutputFile();

  PlatformTaskRunner task_runner_;
  std::unique_ptr<perfetto::Service::ConsumerEndpoint> consumer_endpoint_;
  std::unique_ptr<TraceConfig> trace_config_;
  base::ScopedFstream trace_out_stream_;
  std::string trace_out_path_;

  // Only used if linkat(AT_FDCWD) isn't available.
  std::string tmp_trace_out_path_;

  std::string dropbox_tag_;
  bool did_process_full_trace_ = false;
};

int PerfettoCmd::PrintUsage(const char* argv0) {
  PERFETTO_ELOG(R"(
Usage: %s
  --background  -b     : Exits immediately and continues tracing in background
  --config      -c     : /path/to/trace/config/file or - for stdin
  --out         -o     : /path/to/out/trace/file
  --dropbox     -d TAG : Upload trace into DropBox using tag TAG (default: %s)
  --help        -h
)",
                argv0, kDefaultDropBoxTag);
  return 1;
}

int PerfettoCmd::Main(int argc, char** argv) {
  static const struct option long_options[] = {
      // |option_index| relies on the order of options, don't reshuffle them.
      {"help", required_argument, 0, 'h'},
      {"config", required_argument, 0, 'c'},
      {"out", required_argument, 0, 'o'},
      {"background", no_argument, 0, 'b'},
      {"dropbox", optional_argument, 0, 'd'},
      {nullptr, 0, nullptr, 0}};

  int option_index = 0;
  std::string trace_config_raw;
  bool background = false;
  for (;;) {
    int option =
        getopt_long(argc, argv, "c:o:bd::", long_options, &option_index);

    if (option == -1)
      break;  // EOF.

    if (option == 'c') {
      if (strcmp(optarg, "-") == 0) {
        std::istreambuf_iterator<char> begin(std::cin), end;
        trace_config_raw.assign(begin, end);
      } else if (strcmp(optarg, ":test") == 0) {
        // TODO(primiano): temporary for testing only.
        perfetto::protos::TraceConfig test_config;
        test_config.add_buffers()->set_size_kb(4096);
        test_config.set_duration_ms(10000);
        auto* ds_config = test_config.add_data_sources()->mutable_config();
        ds_config->set_name("com.google.perfetto.ftrace");
        ds_config->mutable_ftrace_config()->add_event_names("sched_switch");
        ds_config->mutable_ftrace_config()->add_event_names("cpu_idle");
        ds_config->mutable_ftrace_config()->add_event_names("cpu_frequency");
        ds_config->set_target_buffer(0);
        test_config.SerializeToString(&trace_config_raw);
      } else {
        std::ifstream file_stream;
        file_stream.open(optarg, std::ios_base::in | std::ios_base::binary);
        if (!file_stream.is_open()) {
          PERFETTO_ELOG("Could not open %s", optarg);
          return 1;
        }
        std::istreambuf_iterator<char> begin(file_stream), end;
        trace_config_raw.assign(begin, end);
      }
      continue;
    }

    if (option == 'o') {
      trace_out_path_ = optarg;
      continue;
    }

    if (option == 'd') {
#if defined(PERFETTO_BUILD_WITH_ANDROID)
      dropbox_tag_ = optarg ? optarg : kDefaultDropBoxTag;
      continue;
#else
      PERFETTO_ELOG("DropBox is only supported with Android tree builds");
      return 1;
#endif
    }

    if (option == 'b') {
      background = true;
      continue;
    }
    return PrintUsage(argv[0]);
  }

  if (!trace_out_path_.empty() && !dropbox_tag_.empty()) {
    PERFETTO_ELOG(
        "Can't log to a file (--out) and DropBox (--dropbox) at the same "
        "time");
    return 1;
  }

  if (trace_config_raw.empty() ||
      (trace_out_path_.empty() && dropbox_tag_.empty())) {
    return PrintUsage(argv[0]);
  }

  perfetto::protos::TraceConfig trace_config_proto;
  PERFETTO_DLOG("Parsing TraceConfig, %zu bytes", trace_config_raw.size());
  bool parsed = trace_config_proto.ParseFromString(trace_config_raw);
  if (!parsed) {
    PERFETTO_ELOG("Could not parse TraceConfig proto from stdin");
    return 1;
  }
  trace_config_.reset(new TraceConfig());
  trace_config_->FromProto(trace_config_proto);
  trace_config_raw.clear();

  if (!OpenOutputFile())
    return 1;

  if (background) {
    PERFETTO_CHECK(daemon(0 /*nochdir*/, 0 /*noclose*/) == 0);
    PERFETTO_DLOG("Continuing in background");
  }

  consumer_endpoint_ = ConsumerIPCClient::Connect(PERFETTO_CONSUMER_SOCK_NAME,
                                                  this, &task_runner_);
  task_runner_.Run();
  return did_process_full_trace_ ? 0 : 1;
}  // namespace perfetto

void PerfettoCmd::OnConnect() {
  PERFETTO_LOG(
      "Connected to the Perfetto traced service, starting tracing for %d ms",
      trace_config_->duration_ms());
  PERFETTO_DCHECK(trace_config_);
  consumer_endpoint_->EnableTracing(*trace_config_);
  task_runner_.PostDelayedTask(std::bind(&PerfettoCmd::OnStopTraceTimer, this),
                               trace_config_->duration_ms());

  // Failsafe mechanism to avoid waiting indefinitely if the service hangs.
  task_runner_.PostDelayedTask(std::bind(&PerfettoCmd::OnTimeout, this),
                               trace_config_->duration_ms() * 2);
}

void PerfettoCmd::OnDisconnect() {
  PERFETTO_LOG("Disconnected from the Perfetto traced service");
  task_runner_.Quit();
}

void PerfettoCmd::OnStopTraceTimer() {
  PERFETTO_LOG("Timer expired, disabling tracing and collecting results");
  consumer_endpoint_->DisableTracing();
  consumer_endpoint_->ReadBuffers();
}

void PerfettoCmd::OnTimeout() {
  PERFETTO_ELOG("Timed out while waiting for trace from the service, aborting");
  task_runner_.Quit();
}

void PerfettoCmd::OnTraceData(std::vector<TracePacket> packets, bool has_more) {
  PERFETTO_DLOG("Received trace packet, has_more=%d", has_more);
  for (TracePacket& packet : packets) {
    for (const Chunk& chunk : packet) {
      uint8_t preamble[16];
      uint8_t* pos = preamble;
      pos = WriteVarInt(MakeTagLengthDelimited(1 /* field_id */), pos);
      pos = WriteVarInt(static_cast<uint32_t>(chunk.size), pos);
      fwrite(reinterpret_cast<const char*>(preamble), pos - preamble, 1,
             trace_out_stream_.get());
      fwrite(reinterpret_cast<const char*>(chunk.start), chunk.size, 1,
             trace_out_stream_.get());
    }
  }
  if (has_more)
    return;

  // Reached end of trace.
  consumer_endpoint_->FreeBuffers();
  task_runner_.Quit();

  fflush(*trace_out_stream_);
  long bytes_written = ftell(*trace_out_stream_);
  if (!dropbox_tag_.empty()) {
#if defined(PERFETTO_BUILD_WITH_ANDROID)
    android::sp<android::os::DropBoxManager> dropbox =
        new android::os::DropBoxManager();
    fseek(*trace_out_stream_, 0, SEEK_SET);
    // DropBox takes ownership of the file descriptor, so give it a duplicate.
    base::ScopedFile fd(dup(fileno(*trace_out_stream_)));
    android::binder::Status status = dropbox->addFile(
        android::String16(dropbox_tag_.c_str()), fd.release(), 0 /* flags */);
    if (!status.isOk()) {
      PERFETTO_ELOG("DropBox upload failed: %s", status.toString8().c_str());
      return;
    }
    PERFETTO_ILOG("Uploaded %ld bytes into DropBox with tag %s", bytes_written,
                  dropbox_tag_.c_str());
#endif  // defined(PERFETTO_BUILD_WITH_ANDROID)
  } else {
    PERFETTO_CHECK(
        rename(tmp_trace_out_path_.c_str(), trace_out_path_.c_str()) == 0);
    PERFETTO_ILOG("Wrote %ld bytes into %s", bytes_written,
                  trace_out_path_.c_str());
  }
  trace_out_stream_.reset();
  did_process_full_trace_ = true;
}

bool PerfettoCmd::OpenOutputFile() {
  base::ScopedFile fd;
  if (!dropbox_tag_.empty()) {
    // If we are tracing to DropBox, there's no need to make a
    // filesystem-visible temporary file.
    // TODO(skyostil): Fall back to mkstemp() + open() + unlink() for older
    // devices.
    fd.reset(open(kTempDropBoxTraceDir, O_TMPFILE | O_RDWR, 0600));
    if (!fd) {
      PERFETTO_ELOG("Could not create a temporary trace file in %s",
                    kTempDropBoxTraceDir);
      return false;
    }
  } else {
    // Otherwise create a temporary file in the directory where the final trace
    // is going to be.
    tmp_trace_out_path_ = GetDirName(trace_out_path_) + "/perfetto-traceXXXXXX";
    fd.reset(mkstemp(&tmp_trace_out_path_[0]));
  }
  trace_out_stream_.reset(fdopen(fd.release(), "wb"));
  PERFETTO_CHECK(trace_out_stream_);
  return true;
}

int __attribute__((visibility("default")))
PerfettoCmdMain(int argc, char** argv) {
  perfetto::PerfettoCmd consumer_cmd;
  return consumer_cmd.Main(argc, argv);
}

}  // namespace perfetto
<|endoftext|>


<commit_before>/*
* Copyright 2009, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
*     * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*     * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "native_client/src/trusted/handle_pass/browser_handle.h"
#include "native_client/src/trusted/plugin/nacl_entry_points.h"
#include "webkit/glue/plugins/plugin_list.h"

// This code inside the ifdef is copied from
// native_client/src/third_party_mod/npapi_plugin/np_entry.cc
// This is required as some function declarations are missing for Mac OSX
// in native_client/src/third_party/npapi/files/include/npupp.h that is included
// above.

extern "C" {
  // Safari under OS X requires the following three entry points to be exported.
  NPError API_CALL NP_Initialize(NPNetscapeFuncs* pFuncs
#if defined(XP_UNIX) && !defined(XP_MACOSX)
                                          , NPPluginFuncs* pluginFuncs
#endif  // XP_UNIX
    );
  NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* pFuncs);
  NPError API_CALL NP_Shutdown(void);
}

NPError API_CALL NaCl_NP_GetEntryPoints(NPPluginFuncs* pFuncs) {
#if NACL_WINDOWS || NACL_OSX
  return NP_GetEntryPoints(pFuncs);
#else
  return 0;
#endif
}

NPError API_CALL NaCl_NP_Initialize(NPNetscapeFuncs* pFuncs
#if defined(XP_UNIX) && !defined(XP_MACOSX)
                                  , NPPluginFuncs* pluginFuncs
#endif  // NACL_LINUX
                                  ) {
                                    return NP_Initialize(pFuncs
#if defined(XP_UNIX) && !defined(XP_MACOSX)
                                      , pluginFuncs
#endif  // NACL_LINUX
                                      );
}

NPError API_CALL NaCl_NP_Shutdown() {
  return NP_Shutdown();
}

static void RegisterCommon() {
  NPAPI::PluginEntryPoints entry_points = {
#if !defined(OS_LINUX)
      NaCl_NP_GetEntryPoints,
#endif
      NaCl_NP_Initialize,
      NaCl_NP_Shutdown
  };

  const NPAPI::PluginVersionInfo nacl_plugin_info = {
      FilePath(FILE_PATH_LITERAL("internal_nacl")),
      L"Google Native Client",
      L"Google Native Client",
      L"1",
      L"application/x-nacl-srpc",
      L"",
      L"",
      entry_points
  };

#if NACL_WINDOWS
  NaClHandlePassBrowserInit();
#endif

  NPAPI::PluginList::Singleton()->RegisterInternalPlugin(nacl_plugin_info);
}

// This gets called in the browser process.
void RegisterInternalNaClPlugin() {
  RegisterCommon();
}

// This gets called in the renderer process.
void RegisterInternalNaClPlugin(const std::map<std::string, uintptr_t>& funcs) {
  RegisterCommon();
  std::map<std::string, uintptr_t>::const_iterator it =
    funcs.find("launch_nacl_process_multi_fd");
  if (it != funcs.end()) {
    launch_nacl_process = reinterpret_cast<LaunchNaClProcessFunc>(it->second);
  }
}
<commit_msg>Update plugin registration to new APIs.<commit_after>/*
* Copyright 2009, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
*     * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*     * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "native_client/src/trusted/handle_pass/browser_handle.h"
#include "native_client/src/trusted/plugin/nacl_entry_points.h"
#include "webkit/glue/plugins/plugin_list.h"

// This code inside the ifdef is copied from
// native_client/src/third_party_mod/npapi_plugin/np_entry.cc
// This is required as some function declarations are missing for Mac OSX
// in native_client/src/third_party/npapi/files/include/npupp.h that is included
// above.

extern "C" {
  // Safari under OS X requires the following three entry points to be exported.
  NPError API_CALL NP_Initialize(NPNetscapeFuncs* pFuncs
#if defined(XP_UNIX) && !defined(XP_MACOSX)
                                          , NPPluginFuncs* pluginFuncs
#endif  // XP_UNIX
    );
  NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* pFuncs);
  NPError API_CALL NP_Shutdown(void);
}

NPError API_CALL NaCl_NP_GetEntryPoints(NPPluginFuncs* pFuncs) {
#if NACL_WINDOWS || NACL_OSX
  return NP_GetEntryPoints(pFuncs);
#else
  return 0;
#endif
}

NPError API_CALL NaCl_NP_Initialize(NPNetscapeFuncs* pFuncs
#if defined(XP_UNIX) && !defined(XP_MACOSX)
                                  , NPPluginFuncs* pluginFuncs
#endif  // NACL_LINUX
                                  ) {
                                    return NP_Initialize(pFuncs
#if defined(XP_UNIX) && !defined(XP_MACOSX)
                                      , pluginFuncs
#endif  // NACL_LINUX
                                      );
}

NPError API_CALL NaCl_NP_Shutdown() {
  return NP_Shutdown();
}

static void RegisterCommon() {
  NPAPI::PluginEntryPoints entry_points = {
#if !defined(OS_LINUX)
    NaCl_NP_GetEntryPoints,
#endif
    NaCl_NP_Initialize,
    NaCl_NP_Shutdown
  };

#if NACL_WINDOWS
  NaClHandlePassBrowserInit();
#endif

  NPAPI::PluginList::Singleton()->RegisterInternalPlugin(
      FilePath(FILE_PATH_LITERAL("internal_nacl")),
      "Google Native Client",
      "Google Native Client",
      "application/x-nacl-srpc",
      entry_points);
}

// This gets called in the browser process.
void RegisterInternalNaClPlugin() {
  RegisterCommon();
}

// This gets called in the renderer process.
void RegisterInternalNaClPlugin(const std::map<std::string, uintptr_t>& funcs) {
  RegisterCommon();
  std::map<std::string, uintptr_t>::const_iterator it =
    funcs.find("launch_nacl_process_multi_fd");
  if (it != funcs.end()) {
    launch_nacl_process = reinterpret_cast<LaunchNaClProcessFunc>(it->second);
  }
}
<|endoftext|>


<commit_before>//===-------------------- Layer.cpp - Layer interfaces --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/ExecutionEngine/Orc/Layer.h"
#include "llvm/Object/ObjectFile.h"

namespace llvm {
namespace orc {

IRLayer::IRLayer(ExecutionSession &ES) : ES(ES) {}
IRLayer::~IRLayer() {}

Error IRLayer::add(JITDylib &JD, VModuleKey K, std::unique_ptr<Module> M) {
  return JD.define(llvm::make_unique<BasicIRLayerMaterializationUnit>(
      *this, std::move(K), std::move(M)));
}

IRMaterializationUnit::IRMaterializationUnit(ExecutionSession &ES,
                                             std::unique_ptr<Module> M)
  : MaterializationUnit(SymbolFlagsMap()), M(std::move(M)) {

  MangleAndInterner Mangle(ES, this->M->getDataLayout());
  for (auto &G : this->M->global_values()) {
    if (G.hasName() && !G.isDeclaration() && !G.hasLocalLinkage() &&
        !G.hasAvailableExternallyLinkage() && !G.hasAppendingLinkage()) {
      auto MangledName = Mangle(G.getName());
      SymbolFlags[MangledName] = JITSymbolFlags::fromGlobalValue(G);
      SymbolToDefinition[MangledName] = &G;
    }
  }
}

IRMaterializationUnit::IRMaterializationUnit(
    std::unique_ptr<Module> M, SymbolFlagsMap SymbolFlags,
    SymbolNameToDefinitionMap SymbolToDefinition)
    : MaterializationUnit(std::move(SymbolFlags)), M(std::move(M)),
      SymbolToDefinition(std::move(SymbolToDefinition)) {}

void IRMaterializationUnit::discard(const JITDylib &JD, SymbolStringPtr Name) {
  auto I = SymbolToDefinition.find(Name);
  assert(I != SymbolToDefinition.end() &&
         "Symbol not provided by this MU, or previously discarded");
  assert(!I->second->isDeclaration() &&
         "Discard should only apply to definitions");
  I->second->setLinkage(GlobalValue::AvailableExternallyLinkage);
  SymbolToDefinition.erase(I);
}

BasicIRLayerMaterializationUnit::BasicIRLayerMaterializationUnit(
    IRLayer &L, VModuleKey K, std::unique_ptr<Module> M)
  : IRMaterializationUnit(L.getExecutionSession(), std::move(M)),
      L(L), K(std::move(K)) {}

void BasicIRLayerMaterializationUnit::materialize(
    MaterializationResponsibility R) {
  L.emit(std::move(R), std::move(K), std::move(M));
}

ObjectLayer::ObjectLayer(ExecutionSession &ES) : ES(ES) {}

ObjectLayer::~ObjectLayer() {}

Error ObjectLayer::add(JITDylib &JD, VModuleKey K,
                       std::unique_ptr<MemoryBuffer> O) {
  auto ObjMU = BasicObjectLayerMaterializationUnit::Create(*this, std::move(K),
                                                           std::move(O));
  if (!ObjMU)
    return ObjMU.takeError();
  return JD.define(std::move(*ObjMU));
}

Expected<std::unique_ptr<BasicObjectLayerMaterializationUnit>>
BasicObjectLayerMaterializationUnit::Create(ObjectLayer &L, VModuleKey K,
                                            std::unique_ptr<MemoryBuffer> O) {
  auto SymbolFlags =
      getObjectSymbolFlags(L.getExecutionSession(), O->getMemBufferRef());

  if (!SymbolFlags)
    return SymbolFlags.takeError();

  return std::unique_ptr<BasicObjectLayerMaterializationUnit>(
      new BasicObjectLayerMaterializationUnit(L, K, std::move(O),
                                              std::move(*SymbolFlags)));
}

BasicObjectLayerMaterializationUnit::BasicObjectLayerMaterializationUnit(
    ObjectLayer &L, VModuleKey K, std::unique_ptr<MemoryBuffer> O,
    SymbolFlagsMap SymbolFlags)
    : MaterializationUnit(std::move(SymbolFlags)), L(L), K(std::move(K)),
      O(std::move(O)) {}

void BasicObjectLayerMaterializationUnit::materialize(
    MaterializationResponsibility R) {
  L.emit(std::move(R), std::move(K), std::move(O));
}

void BasicObjectLayerMaterializationUnit::discard(const JITDylib &JD,
                                                  SymbolStringPtr Name) {
  // FIXME: Support object file level discard. This could be done by building a
  //        filter to pass to the object layer along with the object itself.
}

Expected<SymbolFlagsMap> getObjectSymbolFlags(ExecutionSession &ES,
                                              MemoryBufferRef ObjBuffer) {
  auto Obj = object::ObjectFile::createObjectFile(ObjBuffer);

  if (!Obj)
    return Obj.takeError();

  SymbolFlagsMap SymbolFlags;
  for (auto &Sym : (*Obj)->symbols()) {
    if (!(Sym.getFlags() & object::BasicSymbolRef::SF_Undefined) &&
        (Sym.getFlags() & object::BasicSymbolRef::SF_Exported)) {
      auto Name = Sym.getName();
      if (!Name)
        return Name.takeError();
      auto InternedName = ES.getSymbolStringPool().intern(*Name);
      auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym);
      if (!SymFlags)
        return SymFlags.takeError();
      SymbolFlags[InternedName] = std::move(*SymFlags);
    }
  }

  return SymbolFlags;
}

} // End namespace orc.
} // End namespace llvm.
<commit_msg>[ORC] Do not include non-global symbols in getObjectSymbolFlags.<commit_after>//===-------------------- Layer.cpp - Layer interfaces --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/ExecutionEngine/Orc/Layer.h"
#include "llvm/Object/ObjectFile.h"

namespace llvm {
namespace orc {

IRLayer::IRLayer(ExecutionSession &ES) : ES(ES) {}
IRLayer::~IRLayer() {}

Error IRLayer::add(JITDylib &JD, VModuleKey K, std::unique_ptr<Module> M) {
  return JD.define(llvm::make_unique<BasicIRLayerMaterializationUnit>(
      *this, std::move(K), std::move(M)));
}

IRMaterializationUnit::IRMaterializationUnit(ExecutionSession &ES,
                                             std::unique_ptr<Module> M)
  : MaterializationUnit(SymbolFlagsMap()), M(std::move(M)) {

  MangleAndInterner Mangle(ES, this->M->getDataLayout());
  for (auto &G : this->M->global_values()) {
    if (G.hasName() && !G.isDeclaration() && !G.hasLocalLinkage() &&
        !G.hasAvailableExternallyLinkage() && !G.hasAppendingLinkage()) {
      auto MangledName = Mangle(G.getName());
      SymbolFlags[MangledName] = JITSymbolFlags::fromGlobalValue(G);
      SymbolToDefinition[MangledName] = &G;
    }
  }
}

IRMaterializationUnit::IRMaterializationUnit(
    std::unique_ptr<Module> M, SymbolFlagsMap SymbolFlags,
    SymbolNameToDefinitionMap SymbolToDefinition)
    : MaterializationUnit(std::move(SymbolFlags)), M(std::move(M)),
      SymbolToDefinition(std::move(SymbolToDefinition)) {}

void IRMaterializationUnit::discard(const JITDylib &JD, SymbolStringPtr Name) {
  auto I = SymbolToDefinition.find(Name);
  assert(I != SymbolToDefinition.end() &&
         "Symbol not provided by this MU, or previously discarded");
  assert(!I->second->isDeclaration() &&
         "Discard should only apply to definitions");
  I->second->setLinkage(GlobalValue::AvailableExternallyLinkage);
  SymbolToDefinition.erase(I);
}

BasicIRLayerMaterializationUnit::BasicIRLayerMaterializationUnit(
    IRLayer &L, VModuleKey K, std::unique_ptr<Module> M)
  : IRMaterializationUnit(L.getExecutionSession(), std::move(M)),
      L(L), K(std::move(K)) {}

void BasicIRLayerMaterializationUnit::materialize(
    MaterializationResponsibility R) {
  L.emit(std::move(R), std::move(K), std::move(M));
}

ObjectLayer::ObjectLayer(ExecutionSession &ES) : ES(ES) {}

ObjectLayer::~ObjectLayer() {}

Error ObjectLayer::add(JITDylib &JD, VModuleKey K,
                       std::unique_ptr<MemoryBuffer> O) {
  auto ObjMU = BasicObjectLayerMaterializationUnit::Create(*this, std::move(K),
                                                           std::move(O));
  if (!ObjMU)
    return ObjMU.takeError();
  return JD.define(std::move(*ObjMU));
}

Expected<std::unique_ptr<BasicObjectLayerMaterializationUnit>>
BasicObjectLayerMaterializationUnit::Create(ObjectLayer &L, VModuleKey K,
                                            std::unique_ptr<MemoryBuffer> O) {
  auto SymbolFlags =
      getObjectSymbolFlags(L.getExecutionSession(), O->getMemBufferRef());

  if (!SymbolFlags)
    return SymbolFlags.takeError();

  return std::unique_ptr<BasicObjectLayerMaterializationUnit>(
      new BasicObjectLayerMaterializationUnit(L, K, std::move(O),
                                              std::move(*SymbolFlags)));
}

BasicObjectLayerMaterializationUnit::BasicObjectLayerMaterializationUnit(
    ObjectLayer &L, VModuleKey K, std::unique_ptr<MemoryBuffer> O,
    SymbolFlagsMap SymbolFlags)
    : MaterializationUnit(std::move(SymbolFlags)), L(L), K(std::move(K)),
      O(std::move(O)) {}

void BasicObjectLayerMaterializationUnit::materialize(
    MaterializationResponsibility R) {
  L.emit(std::move(R), std::move(K), std::move(O));
}

void BasicObjectLayerMaterializationUnit::discard(const JITDylib &JD,
                                                  SymbolStringPtr Name) {
  // FIXME: Support object file level discard. This could be done by building a
  //        filter to pass to the object layer along with the object itself.
}

Expected<SymbolFlagsMap> getObjectSymbolFlags(ExecutionSession &ES,
                                              MemoryBufferRef ObjBuffer) {
  auto Obj = object::ObjectFile::createObjectFile(ObjBuffer);

  if (!Obj)
    return Obj.takeError();

  SymbolFlagsMap SymbolFlags;
  for (auto &Sym : (*Obj)->symbols()) {
    // Skip symbols not defined in this object file.
    if (Sym.getFlags() & object::BasicSymbolRef::SF_Undefined)
      continue;

    // Skip symbols that are not global.
    if (!(Sym.getFlags() & object::BasicSymbolRef::SF_Global))
      continue;

    auto Name = Sym.getName();
    if (!Name)
      return Name.takeError();
    auto InternedName = ES.getSymbolStringPool().intern(*Name);
    auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym);
    if (!SymFlags)
      return SymFlags.takeError();
    SymbolFlags[InternedName] = std::move(*SymFlags);
  }

  return SymbolFlags;
}

} // End namespace orc.
} // End namespace llvm.
<|endoftext|>


<commit_before><commit_msg>Re-enable memcmp interceptor for TSan.<commit_after><|endoftext|>