<commit_before>//
//
// MIT License
//
// Copyright (c) 2017 Stellacore Corporation.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//

/*! \file
\brief  This file contains unit test for sys::time
*/

#include "libsys/time.h"

#include "libio/stream.h"

#include <cmath>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>

namespace
{

//! Check for basics
std::string
sys_time_test0
	()
{
	std::ostringstream oss;

	double const absT0(sys::time::now());
	double const relT0(sys::time::relativeNow());

	long const microSleep(123456l);
	std::this_thread::sleep_for(std::chrono::microseconds(microSleep));

	double const absT1(sys::time::now());
	double const relT1(sys::time::relativeNow());

	double const absDelta(absT1 - absT0);
	double const relDelta(relT1 - relT0);

	// check within a few micro seconds
	double const microDif(std::abs(1.e6*(relDelta - absDelta)));
	static double const microTol(4.);  // allow for run time of code
	if (! (microDif < microTol))
	{
		oss << "Failure of relative time test" << std::endl;
		oss << "absT0: " << absT0 << std::endl;
		oss << "absT1: " << absT1 << std::endl;
		oss << "absDelta: " << absDelta << std::endl;
		oss << "relT0: " << relT0 << std::endl;
		oss << "relT1: " << relT1 << std::endl;
		oss << "relDelta: " << relDelta << std::endl;
		oss << "microDif: " << microDif << std::endl;
		oss << "microTol: " << microTol << std::endl;
	}

	return oss.str();
}

}

//! Unit test for sys::time
int
main
	( int const /*argc*/
	, char const * const * const /*argv*/
	)
{
	std::ostringstream oss;

	// run tests
	oss << sys_time_test0();

	// check/report results
	std::string const errMessages(oss.str());
	if (! errMessages.empty())
	{
		io::err() << errMessages << std::endl;
		return 1;
	}
	return 0;
}
<commit_msg>testsys/utime.cpp cleanup test cases a bit - still very heuristic<commit_after>//
//
// MIT License
//
// Copyright (c) 2017 Stellacore Corporation.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//

/*! \file
\brief  This file contains unit test for sys::time
*/

#include "libsys/time.h"

#include "libio/stream.h"

#include <cmath>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>

namespace
{

//! Check for basics
std::string
sys_time_test0
	()
{
	std::ostringstream oss;

	// expect executation of squential statement exectuation to *probably* be
	// simultaneous withint at least this time interval
	constexpr double tolSync{ .001 };

	// get two times that should be *approximately* "simultaneous-ish
	double const absT0{ sys::time::now() }; // since 1970.01.01-00:00:00.0
	double const relT0{ sys::time::relativeNow() }; // should be ~= 0

	// assume chorono::steady_clock should have been running at least this long
	constexpr double sinceStart{ 1. };
	if (! (sinceStart < absT0))
	{
		oss << "Failure of absolute time to return value larger than 1 sec"
			<< std::endl;
		oss << "absT0: " << absT0 << std::endl;
	}
	if (relT0 < 0.)
	{
		oss  << "Failure of positive relative time test" << std::endl;
		oss << "relT0: " << relT0 << std::endl;
	}
	if (! (relT0 < tolSync)) // relative should initilize near zero
	{
		oss << "Faiure of first relative time test" << std::endl;
		oss << "relT0: " << relT0 << std::endl;
	}

	// introduce significant delay (relative to tolSync)
	constexpr double delay{ .125 };
	constexpr long microSleep{ static_cast<long>(1.e6 * delay) };
	std::this_thread::sleep_for(std::chrono::microseconds(microSleep));

	// get another approximately "simultaneous"-ish times
	double const absT1{ sys::time::now() };
	double const relT1{ sys::time::relativeNow() }; //~= (absT1-absT0)

	double const absDelta{ absT1 - absT0 };
	double const & relDelta = relT1;  // since relT0 ~= 0

	double const dif{ std::abs(relDelta - absDelta) };
	static double const tol(10.*tolSync);  // allow for run time of code
	if (! (dif < tol))
	{
		oss << "Failure of relative time test" << std::endl;
		oss << "   absT0: " << absT0 << std::endl;
		oss << "   absT1: " << absT1 << std::endl;
		oss << "absDelta: " << absDelta << std::endl;
		oss << "   relT0: " << relT0 << std::endl;
		oss << "   relT1: " << relT1 << std::endl;
		oss << "relDelta: " << relDelta << std::endl;
		oss << "     dif: " << dif << std::endl;
		oss << "     tol: " << tol << std::endl;
	}

	return oss.str();
}

}

//! Unit test for sys::time
int
main
	( int const /*argc*/
	, char const * const * const /*argv*/
	)
{
	std::ostringstream oss;

	// run tests
	oss << sys_time_test0();

	// check/report results
	std::string const errMessages(oss.str());
	if (! errMessages.empty())
	{
		io::err() << errMessages << std::endl;
		return 1;
	}
	return 0;
}
<|endoftext|>


<commit_before>#include "pqVelodyneManager.h"
#include "vvLoadDataReaction.h"
#include "vvCalibrationDialog.h"
#include "vvPythonQtDecorators.h"

#include <pqActiveObjects.h>
#include <pqActiveView.h>
#include <pqApplicationCore.h>
#include <pqDataRepresentation.h>
#include <pqPipelineSource.h>
#include <pqPythonDialog.h>
#include <pqPythonManager.h>
#include <pqPVApplicationCore.h>
#include <pqRenderView.h>
#include <pqServer.h>
#include <pqServerManagerModel.h>
#include <pqSettings.h>
#include <pqView.h>

#include <vtkSMPropertyHelper.h>
#include <vtkSMSourceProxy.h>
#include <vtkSMViewProxy.h>
#include <vtkPythonInterpreter.h>
#include <vtkTimerLog.h>
#include <vtkVelodyneHDLReader.h>

#include <QApplication>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QLabel>
#include <QMainWindow>
#include <QTimer>

//-----------------------------------------------------------------------------
class pqVelodyneManager::pqInternal
{
public:

  pqInternal()
  {

  }

  QAction* OpenFile;
  QAction* Close;
  QAction* OpenSensor;
  QAction* ChooseCalibrationFile;
  QAction* ResetView;
  QAction* Play;
  QAction* SeekForward;
  QAction* SeekBackward;
  QAction* GotoStart;
  QAction* GotoEnd;
  QAction* Record;
  QAction* MeasurementGrid;
  QAction* SaveCSV;
};

//-----------------------------------------------------------------------------
QPointer<pqVelodyneManager> pqVelodyneManagerInstance = NULL;

//-----------------------------------------------------------------------------
pqVelodyneManager *pqVelodyneManager::instance()
{
  if (!pqVelodyneManagerInstance)
    {
    pqVelodyneManagerInstance = new pqVelodyneManager(pqApplicationCore::instance());
    }

  return pqVelodyneManagerInstance;
}

//-----------------------------------------------------------------------------
pqVelodyneManager::pqVelodyneManager(QObject *p) : QObject(p)
{
  this->Internal = new pqInternal;
}

//-----------------------------------------------------------------------------
pqVelodyneManager::~pqVelodyneManager()
{
  delete this->Internal;
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::pythonStartup()
{
  QStringList pythonDirs;
  pythonDirs << QCoreApplication::applicationDirPath()  + "/../Python" // MacOSX application bundle
             << QCoreApplication::applicationDirPath()  + "/../../../../lib/site-packages" // MacOSX application bundle in build directory
             << QCoreApplication::applicationDirPath()  + "/../lib/site-packages" // Windows NMake build directory
             << QCoreApplication::applicationDirPath()  + "/site-packages"; // Windows install tree

  foreach (const QString& dirname, pythonDirs)
    {
      if (QDir(dirname).exists())
        {
        vtkPythonInterpreter::PrependPythonPath(dirname.toAscii().data());
        break;
        }
    }

  vtkPythonInterpreter::RunSimpleString("import PythonQt");
  PythonQt::self()->addDecorators(new vvPythonQtDecorators());
  vtkPythonInterpreter::RunSimpleString("import veloview");

  this->runPython(QString(
      "import PythonQt\n"
      "QtGui = PythonQt.QtGui\n"
      "QtCore = PythonQt.QtCore\n"
      "import veloview.applogic as vv\n"
      "vv.start()\n"));

  this->onMeasurementGrid();

  bool showDialogAtStartup = false;
  if (showDialogAtStartup)
    {
    pqPythonManager* manager = pqPVApplicationCore::instance()->pythonManager();
    pqPythonDialog* dialog = manager->pythonShellDialog();
    dialog->show();
    dialog->raise();
    dialog->activateWindow();
    }
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::runPython(const QString& statements)
{
  //printf("runPython(\"%s\")\n", qPrintable(statements));
  pqPythonManager* manager = pqPVApplicationCore::instance()->pythonManager();
  pqPythonDialog* dialog = manager->pythonShellDialog();
  dialog->runString(statements);
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::saveFramesToPCAP(vtkSMSourceProxy* proxy, int startFrame, int endFrame, const QString& filename)
{
  if (!proxy)
    {
    return;
    }

  vtkVelodyneHDLReader* reader = vtkVelodyneHDLReader::SafeDownCast(proxy->GetClientSideObject());
  if (!reader)
    {
    return;
    }

  reader->Open();
  reader->DumpFrames(startFrame, endFrame, filename.toAscii().data());
  reader->Close();
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::setup(QAction* openFile, QAction* close, QAction* openSensor,
  QAction* chooseCalibrationFile, QAction* resetView, QAction* play, QAction* seekForward, QAction* seekBackward,  QAction* gotoStart, QAction* gotoEnd,
  QAction* record, QAction* measurementGrid, QAction* saveScreenshot, QAction* saveCSV)
{
  this->Internal->OpenFile = openFile;
  this->Internal->Close = close;
  this->Internal->OpenSensor = openSensor;
  this->Internal->ChooseCalibrationFile = chooseCalibrationFile;
  this->Internal->ResetView = resetView;
  this->Internal->Play = play;
  this->Internal->SeekForward = seekForward;
  this->Internal->SeekBackward = seekBackward;
  this->Internal->GotoStart = gotoStart;
  this->Internal->GotoEnd = gotoEnd;
  this->Internal->Record = record;
  this->Internal->MeasurementGrid = measurementGrid;
  this->Internal->SaveCSV = saveCSV;

  pqSettings* settings = pqApplicationCore::instance()->settings();
  bool gridVisible = settings->value("VelodyneHDLPlugin/MeasurementGrid/Visibility", true).toBool();
  measurementGrid->setChecked(gridVisible);

  this->connect(openSensor, SIGNAL(triggered()), SLOT(onOpenSensor()));
  this->connect(chooseCalibrationFile, SIGNAL(triggered()), SLOT(onChooseCalibrationFile()));

  this->connect(measurementGrid, SIGNAL(triggered()), SLOT(onMeasurementGrid()));

  new vvLoadDataReaction(openFile);

  QTimer::singleShot(0, this, SLOT(pythonStartup()));
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::openData(const QString& filename)
{
  if (QFileInfo(filename).suffix() == "pcap")
    {
      vvCalibrationDialog dialog;
      int accepted = dialog.exec();

      if (!accepted)
        {
        return;
        }

      QString calibrationFile = dialog.selectedCalibrationFile();

      this->runPython(QString("vv.openPCAP('%1', '%2')\n").arg(filename).arg(calibrationFile));
    }
  else
    {
    this->runPython(QString("vv.openData('%1')\n").arg(filename));
    }
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::onMeasurementGrid()
{
  bool gridVisible = this->Internal->MeasurementGrid->isChecked();
  pqSettings* settings = pqApplicationCore::instance()->settings();
  settings->setValue("VelodyneHDLPlugin/MeasurementGrid/Visibility", gridVisible);

  if (gridVisible)
    {
    this->runPython("vv.showMeasurementGrid()\n");
    }
  else
    {
    this->runPython("vv.hideMeasurementGrid()\n");
    }
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::onOpenSensor()
{
  vvCalibrationDialog dialog;
  int accepted = dialog.exec();

  if (!accepted)
    {
    return;
    }

  QString calibrationFile = dialog.selectedCalibrationFile();

  this->runPython(QString("vv.openSensor('%1')\n").arg(calibrationFile));
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::onChooseCalibrationFile()
{
  vvCalibrationDialog dialog;
  int accepted = dialog.exec();

  if (!accepted)
    {
    return;
    }

  QString calibrationFile = dialog.selectedCalibrationFile();

  this->runPython(QString("vv.setCalibrationFile('%1')\n").arg(calibrationFile));
}

//-----------------------------------------------------------------------------
pqServer *pqVelodyneManager::getActiveServer()
{
  pqApplicationCore *app = pqApplicationCore::instance();
  pqServerManagerModel *smModel = app->getServerManagerModel();
  pqServer *server = smModel->getItemAtIndex<pqServer*>(0);
  return server;
}

//-----------------------------------------------------------------------------
QWidget *pqVelodyneManager::getMainWindow()
{
  foreach(QWidget *topWidget, QApplication::topLevelWidgets())
    {
    if (qobject_cast<QMainWindow*>(topWidget))
      {
      return topWidget;
      }
    }
  return NULL;
}

//-----------------------------------------------------------------------------
pqView *pqVelodyneManager::findView(pqPipelineSource *source, int port, const QString &viewType)
{
  // Step 1, try to find a view in which the source is already shown.
  if (source)
    {
    foreach (pqView *view, source->getViews())
      {
      pqDataRepresentation *repr = source->getRepresentation(port, view);
      if (repr && repr->isVisible()) return view;
      }
    }

  // Step 2, check to see if the active view is the right type.
  pqView *view = pqActiveView::instance().current();
  if (view->getViewType() == viewType) return view;

  // Step 3, check all the views and see if one is the right type and not
  // showing anything.
  pqApplicationCore *core = pqApplicationCore::instance();
  pqServerManagerModel *smModel = core->getServerManagerModel();
  foreach (view, smModel->findItems<pqView*>())
    {
    if (   view && (view->getViewType() == viewType)
        && (view->getNumberOfVisibleRepresentations() < 1) )
      {
      return view;
      }
    }

  // Give up.  A new view needs to be created.
  return NULL;
}

//-----------------------------------------------------------------------------
pqView* pqVelodyneManager::getRenderView()
{
  return findView(0, 0, pqRenderView::renderViewType());
}
<commit_msg>Fix python path initialization for ParaView 4.0<commit_after>#include "pqVelodyneManager.h"
#include "vvLoadDataReaction.h"
#include "vvCalibrationDialog.h"
#include "vvPythonQtDecorators.h"

#include <pqActiveObjects.h>
#include <pqActiveView.h>
#include <pqApplicationCore.h>
#include <pqDataRepresentation.h>
#include <pqPipelineSource.h>
#include <pqPythonDialog.h>
#include <pqPythonManager.h>
#include <pqPVApplicationCore.h>
#include <pqRenderView.h>
#include <pqServer.h>
#include <pqServerManagerModel.h>
#include <pqSettings.h>
#include <pqView.h>

#include <vtkSMPropertyHelper.h>
#include <vtkSMSourceProxy.h>
#include <vtkSMViewProxy.h>
#include <vtkPythonInterpreter.h>
#include <vtkTimerLog.h>
#include <vtkVelodyneHDLReader.h>

#include <QApplication>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QLabel>
#include <QMainWindow>
#include <QTimer>

//-----------------------------------------------------------------------------
class pqVelodyneManager::pqInternal
{
public:

  pqInternal()
  {

  }

  QAction* OpenFile;
  QAction* Close;
  QAction* OpenSensor;
  QAction* ChooseCalibrationFile;
  QAction* ResetView;
  QAction* Play;
  QAction* SeekForward;
  QAction* SeekBackward;
  QAction* GotoStart;
  QAction* GotoEnd;
  QAction* Record;
  QAction* MeasurementGrid;
  QAction* SaveCSV;
};

//-----------------------------------------------------------------------------
QPointer<pqVelodyneManager> pqVelodyneManagerInstance = NULL;

//-----------------------------------------------------------------------------
pqVelodyneManager *pqVelodyneManager::instance()
{
  if (!pqVelodyneManagerInstance)
    {
    pqVelodyneManagerInstance = new pqVelodyneManager(pqApplicationCore::instance());
    }

  return pqVelodyneManagerInstance;
}

//-----------------------------------------------------------------------------
pqVelodyneManager::pqVelodyneManager(QObject *p) : QObject(p)
{
  this->Internal = new pqInternal;
}

//-----------------------------------------------------------------------------
pqVelodyneManager::~pqVelodyneManager()
{
  delete this->Internal;
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::pythonStartup()
{
  QStringList pythonDirs;
  pythonDirs << QCoreApplication::applicationDirPath()  + "/../Python" // MacOSX application bundle
             << QCoreApplication::applicationDirPath()  + "/../../../../lib/site-packages" // MacOSX application bundle in build directory
             << QCoreApplication::applicationDirPath()  + "/site-packages" // Windows NMake build directory and install tree
             << QCoreApplication::applicationDirPath()  + "/../lib/paraview-4.0/site-packages"; // Windows install tree

  foreach (const QString& dirname, pythonDirs)
    {
      if (QDir(dirname).exists())
        {
        vtkPythonInterpreter::PrependPythonPath(dirname.toAscii().data());
        }
    }

  vtkPythonInterpreter::RunSimpleString("import PythonQt");
  PythonQt::self()->addDecorators(new vvPythonQtDecorators());
  vtkPythonInterpreter::RunSimpleString("import veloview");

  this->runPython(QString(
      "import PythonQt\n"
      "QtGui = PythonQt.QtGui\n"
      "QtCore = PythonQt.QtCore\n"
      "import veloview.applogic as vv\n"
      "vv.start()\n"));

  this->onMeasurementGrid();

  bool showDialogAtStartup = false;
  if (showDialogAtStartup)
    {
    pqPythonManager* manager = pqPVApplicationCore::instance()->pythonManager();
    pqPythonDialog* dialog = manager->pythonShellDialog();
    dialog->show();
    dialog->raise();
    dialog->activateWindow();
    }
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::runPython(const QString& statements)
{
  //printf("runPython(\"%s\")\n", qPrintable(statements));
  pqPythonManager* manager = pqPVApplicationCore::instance()->pythonManager();
  pqPythonDialog* dialog = manager->pythonShellDialog();
  dialog->runString(statements);
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::saveFramesToPCAP(vtkSMSourceProxy* proxy, int startFrame, int endFrame, const QString& filename)
{
  if (!proxy)
    {
    return;
    }

  vtkVelodyneHDLReader* reader = vtkVelodyneHDLReader::SafeDownCast(proxy->GetClientSideObject());
  if (!reader)
    {
    return;
    }

  reader->Open();
  reader->DumpFrames(startFrame, endFrame, filename.toAscii().data());
  reader->Close();
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::setup(QAction* openFile, QAction* close, QAction* openSensor,
  QAction* chooseCalibrationFile, QAction* resetView, QAction* play, QAction* seekForward, QAction* seekBackward,  QAction* gotoStart, QAction* gotoEnd,
  QAction* record, QAction* measurementGrid, QAction* saveScreenshot, QAction* saveCSV)
{
  this->Internal->OpenFile = openFile;
  this->Internal->Close = close;
  this->Internal->OpenSensor = openSensor;
  this->Internal->ChooseCalibrationFile = chooseCalibrationFile;
  this->Internal->ResetView = resetView;
  this->Internal->Play = play;
  this->Internal->SeekForward = seekForward;
  this->Internal->SeekBackward = seekBackward;
  this->Internal->GotoStart = gotoStart;
  this->Internal->GotoEnd = gotoEnd;
  this->Internal->Record = record;
  this->Internal->MeasurementGrid = measurementGrid;
  this->Internal->SaveCSV = saveCSV;

  pqSettings* settings = pqApplicationCore::instance()->settings();
  bool gridVisible = settings->value("VelodyneHDLPlugin/MeasurementGrid/Visibility", true).toBool();
  measurementGrid->setChecked(gridVisible);

  this->connect(openSensor, SIGNAL(triggered()), SLOT(onOpenSensor()));
  this->connect(chooseCalibrationFile, SIGNAL(triggered()), SLOT(onChooseCalibrationFile()));

  this->connect(measurementGrid, SIGNAL(triggered()), SLOT(onMeasurementGrid()));

  new vvLoadDataReaction(openFile);

  QTimer::singleShot(0, this, SLOT(pythonStartup()));
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::openData(const QString& filename)
{
  if (QFileInfo(filename).suffix() == "pcap")
    {
      vvCalibrationDialog dialog;
      int accepted = dialog.exec();

      if (!accepted)
        {
        return;
        }

      QString calibrationFile = dialog.selectedCalibrationFile();

      this->runPython(QString("vv.openPCAP('%1', '%2')\n").arg(filename).arg(calibrationFile));
    }
  else
    {
    this->runPython(QString("vv.openData('%1')\n").arg(filename));
    }
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::onMeasurementGrid()
{
  bool gridVisible = this->Internal->MeasurementGrid->isChecked();
  pqSettings* settings = pqApplicationCore::instance()->settings();
  settings->setValue("VelodyneHDLPlugin/MeasurementGrid/Visibility", gridVisible);

  if (gridVisible)
    {
    this->runPython("vv.showMeasurementGrid()\n");
    }
  else
    {
    this->runPython("vv.hideMeasurementGrid()\n");
    }
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::onOpenSensor()
{
  vvCalibrationDialog dialog;
  int accepted = dialog.exec();

  if (!accepted)
    {
    return;
    }

  QString calibrationFile = dialog.selectedCalibrationFile();

  this->runPython(QString("vv.openSensor('%1')\n").arg(calibrationFile));
}

//-----------------------------------------------------------------------------
void pqVelodyneManager::onChooseCalibrationFile()
{
  vvCalibrationDialog dialog;
  int accepted = dialog.exec();

  if (!accepted)
    {
    return;
    }

  QString calibrationFile = dialog.selectedCalibrationFile();

  this->runPython(QString("vv.setCalibrationFile('%1')\n").arg(calibrationFile));
}

//-----------------------------------------------------------------------------
pqServer *pqVelodyneManager::getActiveServer()
{
  pqApplicationCore *app = pqApplicationCore::instance();
  pqServerManagerModel *smModel = app->getServerManagerModel();
  pqServer *server = smModel->getItemAtIndex<pqServer*>(0);
  return server;
}

//-----------------------------------------------------------------------------
QWidget *pqVelodyneManager::getMainWindow()
{
  foreach(QWidget *topWidget, QApplication::topLevelWidgets())
    {
    if (qobject_cast<QMainWindow*>(topWidget))
      {
      return topWidget;
      }
    }
  return NULL;
}

//-----------------------------------------------------------------------------
pqView *pqVelodyneManager::findView(pqPipelineSource *source, int port, const QString &viewType)
{
  // Step 1, try to find a view in which the source is already shown.
  if (source)
    {
    foreach (pqView *view, source->getViews())
      {
      pqDataRepresentation *repr = source->getRepresentation(port, view);
      if (repr && repr->isVisible()) return view;
      }
    }

  // Step 2, check to see if the active view is the right type.
  pqView *view = pqActiveView::instance().current();
  if (view->getViewType() == viewType) return view;

  // Step 3, check all the views and see if one is the right type and not
  // showing anything.
  pqApplicationCore *core = pqApplicationCore::instance();
  pqServerManagerModel *smModel = core->getServerManagerModel();
  foreach (view, smModel->findItems<pqView*>())
    {
    if (   view && (view->getViewType() == viewType)
        && (view->getNumberOfVisibleRepresentations() < 1) )
      {
      return view;
      }
    }

  // Give up.  A new view needs to be created.
  return NULL;
}

//-----------------------------------------------------------------------------
pqView* pqVelodyneManager::getRenderView()
{
  return findView(0, 0, pqRenderView::renderViewType());
}
<|endoftext|>


<commit_before><commit_msg>fix hang<commit_after><|endoftext|>


<commit_before>#include <stdarg.h>
#include <assert.h>
#include <errno.h>
#include "../newbrt/brttypes.h"
#include <db_cxx.h>

DbEnv::DbEnv (u_int32_t flags)
    : do_no_exceptions((flags&DB_CXX_NO_EXCEPTIONS)!=0),
      errcall(NULL)
{
    int ret = db_env_create(&the_env, flags & ~DB_CXX_NO_EXCEPTIONS);
    assert(ret==0); // should do an error.
    the_env->api1_internal = this;
}

DbEnv::DbEnv(DB_ENV *env, u_int32_t flags)
    : do_no_exceptions((flags&DB_CXX_NO_EXCEPTIONS)!=0), _error_stream(0)
{
    the_env = env;
    if (env == 0) {
	DB_ENV *new_env;
	int ret = db_env_create(&new_env, flags & ~DB_CXX_NO_EXCEPTIONS);
	assert(ret==0); // should do an error.
	the_env = new_env;
    }
    the_env->api1_internal = this;
}

// If still open, close it.  In most cases, the caller should call close explicitly so that they can catch the exceptions.
DbEnv::~DbEnv(void)
{
    if (the_env!=NULL) {
	(void)the_env->close(the_env, 0);
	the_env = 0;
    }
}

int DbEnv::close(u_int32_t flags) {
    int ret = EINVAL;
    if (the_env)
        ret = the_env->close(the_env, flags);
    the_env = 0; /* get rid of the env ref, so we don't touch it (even if we failed, or when the destructor is called) */
    return maybe_throw_error(ret);
}

int DbEnv::open(const char *home, u_int32_t flags, int mode) {
    int ret = the_env->open(the_env, home, flags, mode);
    return maybe_throw_error(ret);
}

int DbEnv::set_cachesize(u_int32_t gbytes, u_int32_t bytes, int ncache) {
    int ret = the_env->set_cachesize(the_env, gbytes, bytes, ncache);
    return maybe_throw_error(ret);
}

int DbEnv::set_redzone(u_int32_t percent) {
    int ret = the_env->set_redzone(the_env, percent);
    return maybe_throw_error(ret);
}

int DbEnv::set_flags(u_int32_t flags, int onoff) {
    int ret = the_env->set_flags(the_env, flags, onoff);
    return maybe_throw_error(ret);
}

#if DB_VERSION_MAJOR<4 || (DB_VERSION_MAJOR==4 && DB_VERSION_MINOR<=4)
int DbEnv::set_lk_max(u_int32_t flags) {
    int ret = the_env->set_lk_max(the_env, flags);
    return maybe_throw_error(ret);
}
#endif

int DbEnv::txn_begin(DbTxn *parenttxn, DbTxn **txnp, u_int32_t flags) {
    DB_TXN *txn;
    int ret = the_env->txn_begin(the_env, parenttxn->get_DB_TXN(), &txn, flags);
    if (ret==0) {
	*txnp = new DbTxn(txn);
    }
    return maybe_throw_error(ret);
}

int DbEnv::set_default_bt_compare(bt_compare_fcn_type bt_compare_fcn) {
    int ret = the_env->set_default_bt_compare(the_env, bt_compare_fcn);
    return maybe_throw_error(ret);
}

int DbEnv::set_data_dir(const char *dir) {
    int ret = the_env->set_data_dir(the_env, dir);
    return maybe_throw_error(ret);
}

void DbEnv::set_errpfx(const char *errpfx) {
    the_env->set_errpfx(the_env, errpfx);
}

int DbEnv::maybe_throw_error(int err, DbEnv *env, int no_exceptions) throw (DbException) {
    if (err==0 || err==DB_NOTFOUND || err==DB_KEYEXIST) return err;
    if (no_exceptions) return err;
    if (err==DB_LOCK_DEADLOCK) {
	DbDeadlockException e(env);
	throw e;
    } else {
	DbException e(err);
	e.set_env(env);
	throw e;
    }
}

int DbEnv::maybe_throw_error(int err) throw (DbException) {
    return maybe_throw_error(err, this, do_no_exceptions);
}

extern "C" {
void toku_ydb_error_all_cases(const DB_ENV * env,
                              int error,
                              BOOL include_stderrstring,
                              BOOL use_stderr_if_nothing_else,
                              const char *fmt, va_list ap);
}

void DbEnv::err(int error, const char *fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    toku_ydb_error_all_cases(the_env, error, TRUE, TRUE, fmt, ap);
    va_end(ap);
}

void DbEnv::set_errfile(FILE *errfile) {
    the_env->set_errfile(the_env, errfile);
}

int DbEnv::get_flags(u_int32_t *flagsp) {
    int ret = the_env->get_flags(the_env, flagsp);
    return maybe_throw_error(ret);
}

extern "C" void toku_db_env_errcall_c(const DB_ENV *dbenv_c, const char *errpfx, const char *msg) {
    DbEnv *dbenv = (DbEnv *) dbenv_c->api1_internal;
    dbenv->errcall(dbenv, errpfx, msg);
}

void DbEnv::set_errcall(void (*db_errcall_fcn)(const DbEnv *, const char *, const char *)) {
    errcall = db_errcall_fcn;
    the_env->set_errcall(the_env, toku_db_env_errcall_c);
}

extern "C" void toku_db_env_error_stream_c(const DB_ENV *dbenv_c, const char *errpfx, const char *msg) {
    DbEnv *dbenv = (DbEnv *) dbenv_c->api1_internal;
    if (dbenv->_error_stream) {
        if (errpfx) *(dbenv->_error_stream) << errpfx;
        if (msg) *(dbenv->_error_stream) << ":" << msg << "\n";
    }
}

void DbEnv::set_error_stream(std::ostream *new_error_stream) {
    _error_stream = new_error_stream;
    the_env->set_errcall(the_env, toku_db_env_error_stream_c);
}

int DbEnv::set_lk_max_locks(u_int32_t max_locks) {
    int ret = the_env->set_lk_max_locks(the_env, max_locks);
    return maybe_throw_error(ret);
}

int DbEnv::get_lk_max_locks(u_int32_t *max_locks) {
    int ret = the_env->get_lk_max_locks(the_env, max_locks);
    return maybe_throw_error(ret);
}

<commit_msg>close[t:3880] Fix the cxx compile. Refs #3880.<commit_after>#include <stdarg.h>
#include <errno.h>
#include <toku_assert.h>
#include "../newbrt/brttypes.h"
#include <db_cxx.h>

DbEnv::DbEnv (u_int32_t flags)
    : do_no_exceptions((flags&DB_CXX_NO_EXCEPTIONS)!=0),
      errcall(NULL)
{
    int ret = db_env_create(&the_env, flags & ~DB_CXX_NO_EXCEPTIONS);
    assert(ret==0); // should do an error.
    the_env->api1_internal = this;
}

DbEnv::DbEnv(DB_ENV *env, u_int32_t flags)
    : do_no_exceptions((flags&DB_CXX_NO_EXCEPTIONS)!=0), _error_stream(0)
{
    the_env = env;
    if (env == 0) {
	DB_ENV *new_env;
	int ret = db_env_create(&new_env, flags & ~DB_CXX_NO_EXCEPTIONS);
	assert(ret==0); // should do an error.
	the_env = new_env;
    }
    the_env->api1_internal = this;
}

// If still open, close it.  In most cases, the caller should call close explicitly so that they can catch the exceptions.
DbEnv::~DbEnv(void)
{
    if (the_env!=NULL) {
	(void)the_env->close(the_env, 0);
	the_env = 0;
    }
}

int DbEnv::close(u_int32_t flags) {
    int ret = EINVAL;
    if (the_env)
        ret = the_env->close(the_env, flags);
    the_env = 0; /* get rid of the env ref, so we don't touch it (even if we failed, or when the destructor is called) */
    return maybe_throw_error(ret);
}

int DbEnv::open(const char *home, u_int32_t flags, int mode) {
    int ret = the_env->open(the_env, home, flags, mode);
    return maybe_throw_error(ret);
}

int DbEnv::set_cachesize(u_int32_t gbytes, u_int32_t bytes, int ncache) {
    int ret = the_env->set_cachesize(the_env, gbytes, bytes, ncache);
    return maybe_throw_error(ret);
}

int DbEnv::set_redzone(u_int32_t percent) {
    int ret = the_env->set_redzone(the_env, percent);
    return maybe_throw_error(ret);
}

int DbEnv::set_flags(u_int32_t flags, int onoff) {
    int ret = the_env->set_flags(the_env, flags, onoff);
    return maybe_throw_error(ret);
}

#if DB_VERSION_MAJOR<4 || (DB_VERSION_MAJOR==4 && DB_VERSION_MINOR<=4)
int DbEnv::set_lk_max(u_int32_t flags) {
    int ret = the_env->set_lk_max(the_env, flags);
    return maybe_throw_error(ret);
}
#endif

int DbEnv::txn_begin(DbTxn *parenttxn, DbTxn **txnp, u_int32_t flags) {
    DB_TXN *txn;
    int ret = the_env->txn_begin(the_env, parenttxn->get_DB_TXN(), &txn, flags);
    if (ret==0) {
	*txnp = new DbTxn(txn);
    }
    return maybe_throw_error(ret);
}

int DbEnv::set_default_bt_compare(bt_compare_fcn_type bt_compare_fcn) {
    int ret = the_env->set_default_bt_compare(the_env, bt_compare_fcn);
    return maybe_throw_error(ret);
}

int DbEnv::set_data_dir(const char *dir) {
    int ret = the_env->set_data_dir(the_env, dir);
    return maybe_throw_error(ret);
}

void DbEnv::set_errpfx(const char *errpfx) {
    the_env->set_errpfx(the_env, errpfx);
}

int DbEnv::maybe_throw_error(int err, DbEnv *env, int no_exceptions) throw (DbException) {
    if (err==0 || err==DB_NOTFOUND || err==DB_KEYEXIST) return err;
    if (no_exceptions) return err;
    if (err==DB_LOCK_DEADLOCK) {
	DbDeadlockException e(env);
	throw e;
    } else {
	DbException e(err);
	e.set_env(env);
	throw e;
    }
}

int DbEnv::maybe_throw_error(int err) throw (DbException) {
    return maybe_throw_error(err, this, do_no_exceptions);
}

extern "C" {
void toku_ydb_error_all_cases(const DB_ENV * env,
                              int error,
                              BOOL include_stderrstring,
                              BOOL use_stderr_if_nothing_else,
                              const char *fmt, va_list ap);
}

void DbEnv::err(int error, const char *fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    toku_ydb_error_all_cases(the_env, error, TRUE, TRUE, fmt, ap);
    va_end(ap);
}

void DbEnv::set_errfile(FILE *errfile) {
    the_env->set_errfile(the_env, errfile);
}

int DbEnv::get_flags(u_int32_t *flagsp) {
    int ret = the_env->get_flags(the_env, flagsp);
    return maybe_throw_error(ret);
}

extern "C" void toku_db_env_errcall_c(const DB_ENV *dbenv_c, const char *errpfx, const char *msg) {
    DbEnv *dbenv = (DbEnv *) dbenv_c->api1_internal;
    dbenv->errcall(dbenv, errpfx, msg);
}

void DbEnv::set_errcall(void (*db_errcall_fcn)(const DbEnv *, const char *, const char *)) {
    errcall = db_errcall_fcn;
    the_env->set_errcall(the_env, toku_db_env_errcall_c);
}

extern "C" void toku_db_env_error_stream_c(const DB_ENV *dbenv_c, const char *errpfx, const char *msg) {
    DbEnv *dbenv = (DbEnv *) dbenv_c->api1_internal;
    if (dbenv->_error_stream) {
        if (errpfx) *(dbenv->_error_stream) << errpfx;
        if (msg) *(dbenv->_error_stream) << ":" << msg << "\n";
    }
}

void DbEnv::set_error_stream(std::ostream *new_error_stream) {
    _error_stream = new_error_stream;
    the_env->set_errcall(the_env, toku_db_env_error_stream_c);
}

int DbEnv::set_lk_max_locks(u_int32_t max_locks) {
    int ret = the_env->set_lk_max_locks(the_env, max_locks);
    return maybe_throw_error(ret);
}

int DbEnv::get_lk_max_locks(u_int32_t *max_locks) {
    int ret = the_env->get_lk_max_locks(the_env, max_locks);
    return maybe_throw_error(ret);
}

<|endoftext|>


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

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

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

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

#include <sstream>

#include <algorithm>
#include "source_file.h"
#include "exceptions.h"

void IHasDbPrint::print() const { dbprint(std::cout); std::cout << std::endl; }

namespace Util {
SourcePosition::SourcePosition(unsigned lineNumber, unsigned columnNumber)
        : lineNumber(lineNumber),
          columnNumber(columnNumber) {
    if (lineNumber == 0)
        BUG("Line numbering should start at one");
}

cstring SourcePosition::toString() const {
    return Util::printf_format("%d:%d", lineNumber, columnNumber);
}

//////////////////////////////////////////////////////////////////////////////////////////

SourceInfo::SourceInfo(SourcePosition start, SourcePosition end) :
        start(start),
        end(end) {
    if (!start.isValid() || !end.isValid())
        BUG("Invalid source position in SourceInfo %1%-%2%",
                          start.toString(), end.toString());
    if (start > end)
        BUG("SourceInfo position start %1% after end %2%",
                          start.toString(), end.toString());
}

cstring SourceInfo::toDebugString() const {
    return Util::printf_format("(%s)-(%s)", start.toString(), end.toString());
}

//////////////////////////////////////////////////////////////////////////////////////////

InputSources* InputSources::instance = new InputSources();

InputSources::InputSources() :
        sealed(false) {
    mapLine(nullptr, 1);  // the first line read will be line 1 of stdin
    contents.push_back("");
}

/* static */ void InputSources::reset() {
    instance = new InputSources;
}

/// prevent further changes
void InputSources::seal() {
    LOG4(toDebugString());
    if (sealed)
        BUG("InputSources already sealed");
    sealed = true;
}

unsigned InputSources::lineCount() const {
    int size = contents.size();
    if (contents.back().isNullOrEmpty()) {
        // do not count the last line if it is empty.
        size -= 1;
        if (size < 0)
            BUG("Negative line count");
    }
    return size;
}

// Append this text to the last line
void InputSources::appendToLastLine(StringRef text) {
    if (sealed)
        BUG("Appending to sealed InputSources");
    // Text should not contain any newline characters
    for (size_t i = 0; i < text.len; i++) {
        char c = text[i];
        if (c == '\n')
            BUG("Text contains newlines");
    }
    contents.back() += text.toString();
}

// Append a newline and start a new line
void InputSources::appendNewline(StringRef newline) {
    if (sealed)
        BUG("Appending to sealed InputSources");
    contents.back() += newline.toString();
    contents.push_back("");  // start a new line
}

void InputSources::appendText(const char* text) {
    if (text == nullptr)
        BUG("Null text being appended");
    StringRef ref = text;

    while (ref.len > 0) {
        const char* nl = ref.find("\r\n");
        if (nl == nullptr) {
            appendToLastLine(ref);
            break;
        }

        size_t toCut = nl - ref.p;
        if (toCut != 0) {
            StringRef nonnl(ref.p, toCut);
            appendToLastLine(nonnl);
            ref += toCut;
        } else {
            if (ref[0] == '\n') {
                appendNewline("\n");
                ref += 1;
            } else if (ref.len > 2 && ref[0] == '\r' && ref[1] == '\n') {
                appendNewline("\r\n");
                ref += 2;
            } else {
                // Just \r
                appendToLastLine(ref.substr(0, 1));
                ref += 1;
            }
        }
    }
}

cstring InputSources::getLine(unsigned lineNumber) const {
    if (lineNumber == 0) {
        return "";
        // BUG("Lines are numbered starting at 1");
        // don't throw: this code may be called by exceptions
        // reporting on elements that have no source position
    }
    return contents.at(lineNumber - 1);
}

void InputSources::mapLine(cstring file, unsigned originalSourceLineNo) {
    if (sealed)
        BUG("Changing mapping to sealed InputSources");
    unsigned lineno = getCurrentLineNumber();
    line_file_map.emplace(lineno, SourceFileLine(file, originalSourceLineNo));
}

SourceFileLine InputSources::getSourceLine(unsigned line) const {
    auto it = line_file_map.upper_bound(line+1);
    if (it == line_file_map.begin())
        // There must be always something mapped to line 0
        BUG("No source information for line %1%", line);
    LOG3(line << " mapped to " << it->first << "," << it->second.toString());
    --it;
    LOG3(line << " corrected to " << it->first << "," << it->second.toString());
    // For a source file such as
    // ----------
    // # 1 "x.p4"
    // parser start { }
    // ----------
    // The first line indicates that line 2 is the first line in x.p4
    // line=2, it->first=1, it->second.sourceLine=1
    // So we have to subtract one to get the real line number
    BUG_CHECK(line - it->first + it->second.sourceLine > 0, "invalid source line");
    return SourceFileLine(it->second.fileName, line - it->first + it->second.sourceLine - 1);
}

unsigned InputSources::getCurrentLineNumber() const {
    return contents.size();
}

SourcePosition InputSources::getCurrentPosition() const {
    unsigned line = getCurrentLineNumber();
    unsigned column = contents.back().size();
    return SourcePosition(line, column);
}

cstring InputSources::getSourceFragment(const SourcePosition &position) const {
    SourceInfo info(position, position);
    return getSourceFragment(info);
}

cstring carets(cstring source, unsigned start, unsigned end) {
    std::stringstream builder;
    if (start > source.size())
        start = source.size();

    unsigned i;
    for (i=0; i < start; i++) {
        char c = source.c_str()[i];
        if (c == ' ' || c == '\t')
            builder.put(c);
        else
            builder.put(' ');
    }

    for (; i < std::max(end, start+1); i++)
        builder.put('^');

    return builder.str();
}

cstring InputSources::getSourceFragment(const SourceInfo &position) const {
    if (!position.isValid())
        return "";

    // If the position spans multiple lines, truncate to just the first line
    if (position.getEnd().getLineNumber() > position.getStart().getLineNumber())
        return getSourceFragment(position.getStart());

    cstring result = getLine(position.getStart().getLineNumber());
    // Normally result has a newline, but if not
    // then we have to add a newline
    cstring toadd = "";
    if (result.find('\n') == nullptr)
        toadd = cstring::newline;
    cstring marker = carets(result, position.getStart().getColumnNumber(),
                            position.getEnd().getColumnNumber());
    return result + toadd + marker + cstring::newline;
}

cstring InputSources::getBriefSourceFragment(const SourceInfo &position) const {
    if (!position.isValid())
        return "";

    cstring result = getLine(position.getStart().getLineNumber());
    unsigned int start = position.getStart().getColumnNumber();
    unsigned int end;
    cstring toadd = "";

    // If the position spans multiple lines, truncate to just the first line
    if (position.getEnd().getLineNumber() > position.getStart().getLineNumber()) {
        // go to the end of the first line
        end = result.size();
        if (result.find('\n') != nullptr) {
            --end;
        }
        toadd = " ...";
    } else {
        end = position.getEnd().getColumnNumber();
    }
    return result.substr(start, end - start) + toadd;
}

cstring InputSources::toDebugString() const {
    std::stringstream builder;
    for (auto line : contents)
        builder << line;
    builder << "---------------" << std::endl;
    for (auto lf : line_file_map)
        builder << lf.first << ": " << lf.second.toString() << std::endl;
    return cstring(builder.str());
}

///////////////////////////////////////////////////

cstring SourceInfo::toSourceFragment() const {
    return InputSources::instance->getSourceFragment(*this);
}

cstring SourceInfo::toBriefSourceFragment() const {
    return InputSources::instance->getBriefSourceFragment(*this);
}

cstring SourceInfo::toPositionString() const {
    if (!isValid())
        return "";
    SourceFileLine position = InputSources::instance->getSourceLine(start.getLineNumber());
    return position.toString();
}

cstring SourceInfo::toSourcePositionData(unsigned *outLineNumber,
                                         unsigned *outColumnNumber) const {
    SourceFileLine position = InputSources::instance->getSourceLine(start.getLineNumber());
    if (outLineNumber != nullptr) {
        *outLineNumber = position.sourceLine;
    }
    if (outColumnNumber != nullptr) {
        *outColumnNumber = start.getColumnNumber();
    }
    return position.fileName.c_str();
}

SourceFileLine SourceInfo::toPosition() const {
    return InputSources::instance->getSourceLine(start.getLineNumber());
}

////////////////////////////////////////////////////////

cstring SourceFileLine::toString() const {
    return Util::printf_format("%s(%d)", fileName.c_str(), sourceLine);
}

}  // namespace Util
<commit_msg>Fix for issue #989 (#990)<commit_after>/*
Copyright 2013-present Barefoot Networks, Inc.

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

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

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

#include <sstream>

#include <algorithm>
#include "source_file.h"
#include "exceptions.h"
#include "lib/log.h"

void IHasDbPrint::print() const { dbprint(std::cout); std::cout << std::endl; }

namespace Util {
SourcePosition::SourcePosition(unsigned lineNumber, unsigned columnNumber)
        : lineNumber(lineNumber),
          columnNumber(columnNumber) {
    if (lineNumber == 0)
        BUG("Line numbering should start at one");
}

cstring SourcePosition::toString() const {
    return Util::printf_format("%d:%d", lineNumber, columnNumber);
}

//////////////////////////////////////////////////////////////////////////////////////////

SourceInfo::SourceInfo(SourcePosition start, SourcePosition end) :
        start(start),
        end(end) {
    if (!start.isValid() || !end.isValid())
        BUG("Invalid source position in SourceInfo %1%-%2%",
                          start.toString(), end.toString());
    if (start > end)
        BUG("SourceInfo position start %1% after end %2%",
                          start.toString(), end.toString());
}

cstring SourceInfo::toDebugString() const {
    return Util::printf_format("(%s)-(%s)", start.toString(), end.toString());
}

//////////////////////////////////////////////////////////////////////////////////////////

InputSources* InputSources::instance = new InputSources();

InputSources::InputSources() :
        sealed(false) {
    mapLine(nullptr, 1);  // the first line read will be line 1 of stdin
    contents.push_back("");
}

/* static */ void InputSources::reset() {
    instance = new InputSources;
}

/// prevent further changes
void InputSources::seal() {
    LOG4(toDebugString());
    if (sealed)
        BUG("InputSources already sealed");
    sealed = true;
}

unsigned InputSources::lineCount() const {
    int size = contents.size();
    if (contents.back().isNullOrEmpty()) {
        // do not count the last line if it is empty.
        size -= 1;
        if (size < 0)
            BUG("Negative line count");
    }
    return size;
}

// Append this text to the last line
void InputSources::appendToLastLine(StringRef text) {
    if (sealed)
        BUG("Appending to sealed InputSources");
    // Text should not contain any newline characters
    for (size_t i = 0; i < text.len; i++) {
        char c = text[i];
        if (c == '\n')
            BUG("Text contains newlines");
    }
    contents.back() += text.toString();
}

// Append a newline and start a new line
void InputSources::appendNewline(StringRef newline) {
    if (sealed)
        BUG("Appending to sealed InputSources");
    contents.back() += newline.toString();
    contents.push_back("");  // start a new line
}

void InputSources::appendText(const char* text) {
    if (text == nullptr)
        BUG("Null text being appended");
    StringRef ref = text;

    while (ref.len > 0) {
        const char* nl = ref.find("\r\n");
        if (nl == nullptr) {
            appendToLastLine(ref);
            break;
        }

        size_t toCut = nl - ref.p;
        if (toCut != 0) {
            StringRef nonnl(ref.p, toCut);
            appendToLastLine(nonnl);
            ref += toCut;
        } else {
            if (ref[0] == '\n') {
                appendNewline("\n");
                ref += 1;
            } else if (ref.len > 2 && ref[0] == '\r' && ref[1] == '\n') {
                appendNewline("\r\n");
                ref += 2;
            } else {
                // Just \r
                appendToLastLine(ref.substr(0, 1));
                ref += 1;
            }
        }
    }
}

cstring InputSources::getLine(unsigned lineNumber) const {
    if (lineNumber == 0) {
        return "";
        // BUG("Lines are numbered starting at 1");
        // don't throw: this code may be called by exceptions
        // reporting on elements that have no source position
    }
    return contents.at(lineNumber - 1);
}

void InputSources::mapLine(cstring file, unsigned originalSourceLineNo) {
    if (sealed)
        BUG("Changing mapping to sealed InputSources");
    unsigned lineno = getCurrentLineNumber();
    line_file_map.emplace(lineno, SourceFileLine(file, originalSourceLineNo));
}

SourceFileLine InputSources::getSourceLine(unsigned line) const {
    auto it = line_file_map.upper_bound(line+1);
    if (it == line_file_map.begin())
        // There must be always something mapped to line 0
        BUG("No source information for line %1%", line);
    LOG3(line << " mapped to " << it->first << "," << it->second.toString());
    --it;
    LOG3(line << " corrected to " << it->first << "," << it->second.toString());
    // For a source file such as
    // ----------
    // # 1 "x.p4"
    // parser start { }
    // ----------
    // The first line indicates that line 2 is the first line in x.p4
    // line=2, it->first=1, it->second.sourceLine=1
    // So we have to subtract one to get the real line number
    BUG_CHECK(line - it->first + it->second.sourceLine > 0, "invalid source line");
    return SourceFileLine(it->second.fileName, line - it->first + it->second.sourceLine - 1);
}

unsigned InputSources::getCurrentLineNumber() const {
    return contents.size();
}

SourcePosition InputSources::getCurrentPosition() const {
    unsigned line = getCurrentLineNumber();
    unsigned column = contents.back().size();
    return SourcePosition(line, column);
}

cstring InputSources::getSourceFragment(const SourcePosition &position) const {
    SourceInfo info(position, position);
    return getSourceFragment(info);
}

cstring carets(cstring source, unsigned start, unsigned end) {
    std::stringstream builder;
    if (start > source.size())
        start = source.size();

    unsigned i;
    for (i=0; i < start; i++) {
        char c = source.c_str()[i];
        if (c == ' ' || c == '\t')
            builder.put(c);
        else
            builder.put(' ');
    }

    for (; i < std::max(end, start+1); i++)
        builder.put('^');

    return builder.str();
}

cstring InputSources::getSourceFragment(const SourceInfo &position) const {
    if (!position.isValid())
        return "";

    // If the position spans multiple lines, truncate to just the first line
    if (position.getEnd().getLineNumber() > position.getStart().getLineNumber())
        return getSourceFragment(position.getStart());

    cstring result = getLine(position.getStart().getLineNumber());
    // Normally result has a newline, but if not
    // then we have to add a newline
    cstring toadd = "";
    if (result.find('\n') == nullptr)
        toadd = cstring::newline;
    cstring marker = carets(result, position.getStart().getColumnNumber(),
                            position.getEnd().getColumnNumber());
    return result + toadd + marker + cstring::newline;
}

cstring InputSources::getBriefSourceFragment(const SourceInfo &position) const {
    if (!position.isValid())
        return "";

    cstring result = getLine(position.getStart().getLineNumber());
    unsigned int start = position.getStart().getColumnNumber();
    unsigned int end;
    cstring toadd = "";

    // If the position spans multiple lines, truncate to just the first line
    if (position.getEnd().getLineNumber() > position.getStart().getLineNumber()) {
        // go to the end of the first line
        end = result.size();
        if (result.find('\n') != nullptr) {
            --end;
        }
        toadd = " ...";
    } else {
        end = position.getEnd().getColumnNumber();
    }
    return result.substr(start, end - start) + toadd;
}

cstring InputSources::toDebugString() const {
    std::stringstream builder;
    for (auto line : contents)
        builder << line;
    builder << "---------------" << std::endl;
    for (auto lf : line_file_map)
        builder << lf.first << ": " << lf.second.toString() << std::endl;
    return cstring(builder.str());
}

///////////////////////////////////////////////////

cstring SourceInfo::toSourceFragment() const {
    return InputSources::instance->getSourceFragment(*this);
}

cstring SourceInfo::toBriefSourceFragment() const {
    return InputSources::instance->getBriefSourceFragment(*this);
}

cstring SourceInfo::toPositionString() const {
    if (!isValid())
        return "";
    SourceFileLine position = InputSources::instance->getSourceLine(start.getLineNumber());
    return position.toString();
}

cstring SourceInfo::toSourcePositionData(unsigned *outLineNumber,
                                         unsigned *outColumnNumber) const {
    SourceFileLine position = InputSources::instance->getSourceLine(start.getLineNumber());
    if (outLineNumber != nullptr) {
        *outLineNumber = position.sourceLine;
    }
    if (outColumnNumber != nullptr) {
        *outColumnNumber = start.getColumnNumber();
    }
    return position.fileName.c_str();
}

SourceFileLine SourceInfo::toPosition() const {
    return InputSources::instance->getSourceLine(start.getLineNumber());
}

////////////////////////////////////////////////////////

cstring SourceFileLine::toString() const {
    return Util::printf_format("%s(%d)", fileName.c_str(), sourceLine);
}

}  // namespace Util
<|endoftext|>


<commit_before>/**
 * Copyright [2016]
 *
 * \author [Artur Troian <troian dot ap at gmail dot com>]
 * \author [Oleg Kravchenko <troian dot ap at gmail dot com>]
 *
 * 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 <sys/file.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/resource.h>

#include <unistd.h>

#include <string>
#include <iostream>
#include <fstream>

#include <boost/filesystem.hpp>
#include <daemon/daemonize.hpp>

namespace daemonize {

static Json::Value *g_config = nullptr;
static int *g_lock_fd        = nullptr;
static cleanup_cb cleanup    = nullptr;
static void *cleanup_ctx     = nullptr;

void exit_daemon(int err)
{
	if (cleanup)
		cleanup(cleanup_ctx);

	if (g_lock_fd) {
		if (*g_lock_fd > 0) {
			if (flock(*g_lock_fd, LOCK_UN) != 0) {
				std::cerr << "Can't unlock the lock file";
			}
			close(*g_lock_fd);
			*g_lock_fd = 0;
		}

		delete g_lock_fd;
	}

	if (!g_config->operator[]("pid_file").empty()) {
		unlink(g_config->operator[]("pid_file").asString().c_str());
	}

	delete g_config;

	_exit(err);
}

static void already_running(const std::string &lock_file)
{
	*g_lock_fd = open(lock_file.c_str(), O_RDONLY, S_IRUSR | S_IWUSR);
	if (*g_lock_fd <= 0) {
		fprintf(stderr, "Can't open executable to lock: \"%s\": %s\n", lock_file.c_str(), strerror(errno));
		exit_daemon(EXIT_FAILURE);
	}

	if (flock(*g_lock_fd, LOCK_EX | LOCK_NB) != 0) {
		fprintf(stderr, "Can't lock the lock file \"%s\". Is another instance running?\n", lock_file.c_str());
		exit_daemon(EXIT_FAILURE);
	}
}

static void write_pid(const std::string &pid_file)
{
	try {
		std::ofstream file(pid_file, std::ios_base::trunc);
		file << std::to_string(getpid());
	} catch (const std::exception &e) {
		exit_daemon(EXIT_FAILURE);
	}
}

static void verify_config(Json::Value *config)
{
	if (!config->isMember("lock_file")) {
		std::cerr << "Daemon config must provide \"lock_file\" member";
		exit_daemon(EXIT_FAILURE);
	}

	if (!config->isMember("env_dir")) {
		std::cerr << "Daemon config must provide \"env_dir\" member";
		exit_daemon(EXIT_FAILURE);
	}

	if (!config->isMember("as_daemon")) {
		std::cerr << "Daemon config must provide \"as_daemon\" member";
		exit_daemon(EXIT_FAILURE);
	}
}

pid_t make_daemon(Json::Value *config, cleanup_cb cb, void *userdata)
{
	g_lock_fd   = new int;
	g_config    = config;
	cleanup     = cb;
	cleanup_ctx = userdata;

	verify_config(config);

	already_running(config->operator[]("lock_file").asString());

	if (config->operator[]("as_daemon").asBool()) {
		pid_t p = daemonize::detached::make();
		if (p > 0 || p < 0)
			return p;
	}

	// Setup environment dir
	if (chdir(config->operator[]("env_dir").asString().c_str()) < 0) {
		exit_daemon(EXIT_FAILURE);
	}

	// check of log directory exists
	std::string log_path(config->operator[]("env_dir").asString());
	if (log_path.back() != '/') {
		log_path += "/";
	}

	if (config->operator[]("log")["dir"].asString().substr(0, 1) != "/") {
		log_path += config->operator[]("log")["dir"].asString();
	}

	if (!boost::filesystem::exists(log_path)) {
		boost::filesystem::create_directory(log_path);
	}

	std::string std_file;
	Json::Value io_config;

	if (config->operator[]("io_mode").asString().compare("io_daemon") == 0) {
		io_config = config->operator[]("io_daemon");
	} else {
		io_config = config->operator[]("io_debug");
	}

	if (io_config["stdin"].asString().compare("stdin") != 0) {
		// stdin needs redirection
		if (io_config["stdin"].asString().compare("/dev/null") == 0) {
			std_file = "/dev/null";
		} else {
			std_file = config->operator[]("log")["dir"].asString();
			std_file.append("/");
			std_file.append(io_config["stdin"].asString());
		}

		close(STDIN_FILENO);

		int stdin_fd = open(std_file.c_str(), O_RDONLY);

		if (stdin_fd != 0) {
			if (stdin_fd > 0)
				close(stdin_fd);
			fprintf(stderr, "Unable to redirect stdin: Opened to: %d. Error: %s", stdin_fd, strerror(errno));
			exit_daemon(EXIT_FAILURE);
		}
	}

	if (io_config["stdout"].asString().compare("stdout") != 0) {
		// stdout needs redirection
		if (io_config["stdout"].asString().compare("/dev/null") == 0) {
			std_file = "/dev/null";
		} else {
			std_file = config->operator[]("log")["dir"].asString();
			std_file.append("/");
			std_file.append(io_config["stdout"].asString());
		}

		close(STDOUT_FILENO);

		int stdout_fd = open(std_file.c_str(), O_CREAT | O_WRONLY | O_TRUNC);
		if (stdout_fd != 1) {
			if (stdout_fd > 0)
				close(stdout_fd);
			fprintf(stderr, "Unable to redirect stdout: Opened to: %d. Error: %s\n", stdout_fd, strerror(errno));
			exit_daemon(EXIT_FAILURE);
		}

		if (std_file.compare("/dev/null") != 0) {
			if (chmod(std_file.c_str(), 0644) < 0) {
				fprintf(stderr, "Unable change file permision: [%s]. Reason: %s\n", std_file.c_str(), strerror(errno));
				exit_daemon(EXIT_FAILURE);
			}
		}
	}

	if (io_config["stderr"].asString().compare("stdout") != 0) {
		// stderr needs redirection
		if (io_config["stderr"].asString().compare("/dev/null") == 0) {
			std_file = "/dev/null";
		} else {
			std_file = config->operator[]("log")["dir"].asString();
			std_file.append("/");
			std_file.append(io_config["stderr"].asString());
		}

		close(STDERR_FILENO);

		int stderr_fd = open(std_file.c_str(), O_CREAT | O_WRONLY | O_TRUNC);

		if (stderr_fd != 2) {
			if (stderr_fd > 0)
				close(stderr_fd);
			fprintf(stderr, "Unable to redirect stderr: Opened to: %d. Error: %s", stderr_fd, strerror(errno));
			exit_daemon(EXIT_FAILURE);
		}

		if (std_file.compare("/dev/null") != 0) {
			if (chmod(std_file.c_str(), 0644) < 0) {
				fprintf(stderr, "Unable change file permision: [%s]. Reason: %s", std_file.c_str(), strerror(errno));
				exit_daemon(EXIT_FAILURE);
			}
		}
	}

	rlimit core_limits;
	core_limits.rlim_cur = core_limits.rlim_max = (rlim_t)RLIM_INFINITY;

	if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
		fprintf(stderr, "Unable to set rlimits. Error: %s", strerror(errno));
		exit_daemon(EXIT_FAILURE);
	}

	if (!g_config->operator[]("pid_file").empty()) {
		write_pid(config->operator[]("pid_file").asString());
	}

	return 0;
}

} // namespace daemonize
<commit_msg>style: typo fix<commit_after>/**
 * Copyright [2016]
 *
 * \author [Artur Troian <troian dot ap at gmail dot com>]
 * \author [Oleg Kravchenko <troian dot ap at gmail dot com>]
 *
 * 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 <sys/file.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/resource.h>

#include <unistd.h>

#include <string>
#include <iostream>
#include <fstream>

#include <boost/filesystem.hpp>
#include <daemon/daemonize.hpp>

namespace daemonize {

static Json::Value *g_config = nullptr;
static int *g_lock_fd        = nullptr;
static cleanup_cb cleanup    = nullptr;
static void *cleanup_ctx     = nullptr;

void exit_daemon(int err)
{
	if (cleanup)
		cleanup(cleanup_ctx);

	if (g_lock_fd) {
		if (*g_lock_fd > 0) {
			if (flock(*g_lock_fd, LOCK_UN) != 0) {
				std::cerr << "Can't unlock the lock file";
			}
			close(*g_lock_fd);
			*g_lock_fd = 0;
		}

		delete g_lock_fd;
	}

	if (!g_config->operator[]("pid_file").empty()) {
		unlink(g_config->operator[]("pid_file").asString().c_str());
	}

	delete g_config;

	_exit(err);
}

static void already_running(const std::string &lock_file)
{
	*g_lock_fd = open(lock_file.c_str(), O_RDONLY, S_IRUSR | S_IWUSR);
	if (*g_lock_fd <= 0) {
		fprintf(stderr, "Can't open executable to lock: \"%s\": %s\n", lock_file.c_str(), strerror(errno));
		exit_daemon(EXIT_FAILURE);
	}

	if (flock(*g_lock_fd, LOCK_EX | LOCK_NB) != 0) {
		fprintf(stderr, "Can't lock the lock file \"%s\". Is another instance running?\n", lock_file.c_str());
		exit_daemon(EXIT_FAILURE);
	}
}

static void write_pid(const std::string &pid_file)
{
	try {
		std::ofstream file(pid_file, std::ios_base::trunc);
		file << std::to_string(getpid());
	} catch (const std::exception &e) {
		exit_daemon(EXIT_FAILURE);
	}
}

static void verify_config(Json::Value *config)
{
	if (!config->isMember("lock_file")) {
		std::cerr << "Daemon config must provide \"lock_file\" member";
		exit_daemon(EXIT_FAILURE);
	}

	if (!config->isMember("env_dir")) {
		std::cerr << "Daemon config must provide \"env_dir\" member";
		exit_daemon(EXIT_FAILURE);
	}

	if (!config->isMember("as_daemon")) {
		std::cerr << "Daemon config must provide \"as_daemon\" member";
		exit_daemon(EXIT_FAILURE);
	}
}

pid_t make_daemon(Json::Value *config, cleanup_cb cb, void *userdata)
{
	g_lock_fd   = new int;
	g_config    = config;
	cleanup     = cb;
	cleanup_ctx = userdata;

	verify_config(config);

	already_running(config->operator[]("lock_file").asString());

	if (config->operator[]("as_daemon").asBool()) {
		pid_t p = daemonize::detached::make();
		if (p > 0 || p < 0)
			return p;
	}

	// Setup environment dir
	if (chdir(config->operator[]("env_dir").asString().c_str()) < 0) {
		exit_daemon(EXIT_FAILURE);
	}

	// check of log directory exists
	std::string log_path(config->operator[]("env_dir").asString());
	if (log_path.back() != '/') {
		log_path += "/";
	}

	if (config->operator[]("log")["dir"].asString().substr(0, 1) != "/") {
		log_path += config->operator[]("log")["dir"].asString();
	}

	if (!boost::filesystem::exists(log_path)) {
		boost::filesystem::create_directory(log_path);
	}

	std::string std_file;
	Json::Value io_config;

	if (config->operator[]("io_mode").asString().compare("io_daemon") == 0) {
		io_config = config->operator[]("io_daemon");
	} else {
		io_config = config->operator[]("io_debug");
	}

	if (io_config["stdin"].asString().compare("stdin") != 0) {
		// stdin needs redirection
		if (io_config["stdin"].asString().compare("/dev/null") == 0) {
			std_file = "/dev/null";
		} else {
			std_file = config->operator[]("log")["dir"].asString();
			std_file.append("/");
			std_file.append(io_config["stdin"].asString());
		}

		close(STDIN_FILENO);

		int stdin_fd = open(std_file.c_str(), O_RDONLY);

		if (stdin_fd != 0) {
			if (stdin_fd > 0)
				close(stdin_fd);
			fprintf(stderr, "Unable to redirect stdin: Opened to: %d. Error: %s", stdin_fd, strerror(errno));
			exit_daemon(EXIT_FAILURE);
		}
	}

	if (io_config["stdout"].asString().compare("stdout") != 0) {
		// stdout needs redirection
		if (io_config["stdout"].asString().compare("/dev/null") == 0) {
			std_file = "/dev/null";
		} else {
			std_file = config->operator[]("log")["dir"].asString();
			std_file.append("/");
			std_file.append(io_config["stdout"].asString());
		}

		close(STDOUT_FILENO);

		int stdout_fd = open(std_file.c_str(), O_CREAT | O_WRONLY | O_TRUNC);
		if (stdout_fd != 1) {
			if (stdout_fd > 0)
				close(stdout_fd);
			fprintf(stderr, "Unable to redirect stdout: Opened to: %d. Error: %s\n", stdout_fd, strerror(errno));
			exit_daemon(EXIT_FAILURE);
		}

		if (std_file.compare("/dev/null") != 0) {
			if (chmod(std_file.c_str(), 0644) < 0) {
				fprintf(stderr, "Unable change file permission: [%s]. Reason: %s\n", std_file.c_str(), strerror(errno));
				exit_daemon(EXIT_FAILURE);
			}
		}
	}

	if (io_config["stderr"].asString().compare("stdout") != 0) {
		// stderr needs redirection
		if (io_config["stderr"].asString().compare("/dev/null") == 0) {
			std_file = "/dev/null";
		} else {
			std_file = config->operator[]("log")["dir"].asString();
			std_file.append("/");
			std_file.append(io_config["stderr"].asString());
		}

		close(STDERR_FILENO);

		int stderr_fd = open(std_file.c_str(), O_CREAT | O_WRONLY | O_TRUNC);

		if (stderr_fd != 2) {
			if (stderr_fd > 0)
				close(stderr_fd);
			fprintf(stderr, "Unable to redirect stderr: Opened to: %d. Error: %s", stderr_fd, strerror(errno));
			exit_daemon(EXIT_FAILURE);
		}

		if (std_file.compare("/dev/null") != 0) {
			if (chmod(std_file.c_str(), 0644) < 0) {
				fprintf(stderr, "Unable change file permision: [%s]. Reason: %s", std_file.c_str(), strerror(errno));
				exit_daemon(EXIT_FAILURE);
			}
		}
	}

	rlimit core_limits;
	core_limits.rlim_cur = core_limits.rlim_max = (rlim_t)RLIM_INFINITY;

	if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
		fprintf(stderr, "Unable to set rlimits. Error: %s", strerror(errno));
		exit_daemon(EXIT_FAILURE);
	}

	if (!g_config->operator[]("pid_file").empty()) {
		write_pid(config->operator[]("pid_file").asString());
	}

	return 0;
}

} // namespace daemonize
<|endoftext|>


<commit_before>/*************************************************************************/
/*  resource_saver.cpp                                                   */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#include "resource_saver.h"
#include "core/config/project_settings.h"
#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/object/script_language.h"

Ref<ResourceFormatSaver> ResourceSaver::saver[MAX_SAVERS];

int ResourceSaver::saver_count = 0;
bool ResourceSaver::timestamp_on_save = false;
ResourceSavedCallback ResourceSaver::save_callback = nullptr;
ResourceSaverGetResourceIDForPath ResourceSaver::save_get_id_for_path = nullptr;

Error ResourceFormatSaver::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
	int64_t res;
	if (GDVIRTUAL_CALL(_save, p_resource, p_path, p_flags, res)) {
		return (Error)res;
	}

	return ERR_METHOD_NOT_FOUND;
}

bool ResourceFormatSaver::recognize(const Ref<Resource> &p_resource) const {
	bool success;
	if (GDVIRTUAL_CALL(_recognize, p_resource, success)) {
		return success;
	}

	return false;
}

void ResourceFormatSaver::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
	PackedStringArray exts;
	if (GDVIRTUAL_CALL(_get_recognized_extensions, p_resource, exts)) {
		const String *r = exts.ptr();
		for (int i = 0; i < exts.size(); ++i) {
			p_extensions->push_back(r[i]);
		}
	}
}

void ResourceFormatSaver::_bind_methods() {
	GDVIRTUAL_BIND(_save, "path", "resource", "flags");
	GDVIRTUAL_BIND(_recognize, "resource");
	GDVIRTUAL_BIND(_get_recognized_extensions, "resource");
}

Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
	String path = p_path;
	if (path.is_empty()) {
		path = p_resource->get_path();
	}
	ERR_FAIL_COND_V_MSG(p_path.is_empty(), ERR_INVALID_PARAMETER, "Can't save resource to empty path. Provide non-empty path or a Resource with non-empty resource_path.");

	String extension = path.get_extension();
	Error err = ERR_FILE_UNRECOGNIZED;

	for (int i = 0; i < saver_count; i++) {
		if (!saver[i]->recognize(p_resource)) {
			continue;
		}

		List<String> extensions;
		bool recognized = false;
		saver[i]->get_recognized_extensions(p_resource, &extensions);

		for (const String &E : extensions) {
			if (E.nocasecmp_to(extension) == 0) {
				recognized = true;
			}
		}

		if (!recognized) {
			continue;
		}

		String old_path = p_resource->get_path();

		String local_path = ProjectSettings::get_singleton()->localize_path(path);

		Ref<Resource> rwcopy = p_resource;
		if (p_flags & FLAG_CHANGE_PATH) {
			rwcopy->set_path(local_path);
		}

		err = saver[i]->save(p_resource, path, p_flags);

		if (err == OK) {
#ifdef TOOLS_ENABLED

			((Resource *)p_resource.ptr())->set_edited(false);
			if (timestamp_on_save) {
				uint64_t mt = FileAccess::get_modified_time(path);

				((Resource *)p_resource.ptr())->set_last_modified_time(mt);
			}
#endif

			if (p_flags & FLAG_CHANGE_PATH) {
				rwcopy->set_path(old_path);
			}

			if (save_callback && path.begins_with("res://")) {
				save_callback(p_resource, path);
			}

			return OK;
		}
	}

	return err;
}

void ResourceSaver::set_save_callback(ResourceSavedCallback p_callback) {
	save_callback = p_callback;
}

void ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) {
	for (int i = 0; i < saver_count; i++) {
		saver[i]->get_recognized_extensions(p_resource, p_extensions);
	}
}

void ResourceSaver::add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front) {
	ERR_FAIL_COND_MSG(p_format_saver.is_null(), "It's not a reference to a valid ResourceFormatSaver object.");
	ERR_FAIL_COND(saver_count >= MAX_SAVERS);

	if (p_at_front) {
		for (int i = saver_count; i > 0; i--) {
			saver[i] = saver[i - 1];
		}
		saver[0] = p_format_saver;
		saver_count++;
	} else {
		saver[saver_count++] = p_format_saver;
	}
}

void ResourceSaver::remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver) {
	ERR_FAIL_COND_MSG(p_format_saver.is_null(), "It's not a reference to a valid ResourceFormatSaver object.");

	// Find saver
	int i = 0;
	for (; i < saver_count; ++i) {
		if (saver[i] == p_format_saver) {
			break;
		}
	}

	ERR_FAIL_COND(i >= saver_count); // Not found

	// Shift next savers up
	for (; i < saver_count - 1; ++i) {
		saver[i] = saver[i + 1];
	}
	saver[saver_count - 1].unref();
	--saver_count;
}

Ref<ResourceFormatSaver> ResourceSaver::_find_custom_resource_format_saver(String path) {
	for (int i = 0; i < saver_count; ++i) {
		if (saver[i]->get_script_instance() && saver[i]->get_script_instance()->get_script()->get_path() == path) {
			return saver[i];
		}
	}
	return Ref<ResourceFormatSaver>();
}

bool ResourceSaver::add_custom_resource_format_saver(String script_path) {
	if (_find_custom_resource_format_saver(script_path).is_valid()) {
		return false;
	}

	Ref<Resource> res = ResourceLoader::load(script_path);
	ERR_FAIL_COND_V(res.is_null(), false);
	ERR_FAIL_COND_V(!res->is_class("Script"), false);

	Ref<Script> s = res;
	StringName ibt = s->get_instance_base_type();
	bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatSaver");
	ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceSaver: " + script_path + ".");

	Object *obj = ClassDB::instantiate(ibt);

	ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + ".");

	Ref<ResourceFormatSaver> crl = Object::cast_to<ResourceFormatSaver>(obj);
	crl->set_script(s);
	ResourceSaver::add_resource_format_saver(crl);

	return true;
}

void ResourceSaver::remove_custom_resource_format_saver(String script_path) {
	Ref<ResourceFormatSaver> custom_saver = _find_custom_resource_format_saver(script_path);
	if (custom_saver.is_valid()) {
		remove_resource_format_saver(custom_saver);
	}
}

void ResourceSaver::add_custom_savers() {
	// Custom resource savers exploits global class names

	String custom_saver_base_class = ResourceFormatSaver::get_class_static();

	List<StringName> global_classes;
	ScriptServer::get_global_class_list(&global_classes);

	for (const StringName &class_name : global_classes) {
		StringName base_class = ScriptServer::get_global_class_native_base(class_name);

		if (base_class == custom_saver_base_class) {
			String path = ScriptServer::get_global_class_path(class_name);
			add_custom_resource_format_saver(path);
		}
	}
}

void ResourceSaver::remove_custom_savers() {
	Vector<Ref<ResourceFormatSaver>> custom_savers;
	for (int i = 0; i < saver_count; ++i) {
		if (saver[i]->get_script_instance()) {
			custom_savers.push_back(saver[i]);
		}
	}

	for (int i = 0; i < custom_savers.size(); ++i) {
		remove_resource_format_saver(custom_savers[i]);
	}
}

ResourceUID::ID ResourceSaver::get_resource_id_for_path(const String &p_path, bool p_generate) {
	if (save_get_id_for_path) {
		return save_get_id_for_path(p_path, p_generate);
	}
	return ResourceUID::INVALID_ID;
}

void ResourceSaver::set_get_resource_id_for_path(ResourceSaverGetResourceIDForPath p_callback) {
	save_get_id_for_path = p_callback;
}
<commit_msg>Fix using wrong variable when checking in `ResourceSaver::save`<commit_after>/*************************************************************************/
/*  resource_saver.cpp                                                   */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#include "resource_saver.h"
#include "core/config/project_settings.h"
#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/object/script_language.h"

Ref<ResourceFormatSaver> ResourceSaver::saver[MAX_SAVERS];

int ResourceSaver::saver_count = 0;
bool ResourceSaver::timestamp_on_save = false;
ResourceSavedCallback ResourceSaver::save_callback = nullptr;
ResourceSaverGetResourceIDForPath ResourceSaver::save_get_id_for_path = nullptr;

Error ResourceFormatSaver::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
	int64_t res;
	if (GDVIRTUAL_CALL(_save, p_resource, p_path, p_flags, res)) {
		return (Error)res;
	}

	return ERR_METHOD_NOT_FOUND;
}

bool ResourceFormatSaver::recognize(const Ref<Resource> &p_resource) const {
	bool success;
	if (GDVIRTUAL_CALL(_recognize, p_resource, success)) {
		return success;
	}

	return false;
}

void ResourceFormatSaver::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
	PackedStringArray exts;
	if (GDVIRTUAL_CALL(_get_recognized_extensions, p_resource, exts)) {
		const String *r = exts.ptr();
		for (int i = 0; i < exts.size(); ++i) {
			p_extensions->push_back(r[i]);
		}
	}
}

void ResourceFormatSaver::_bind_methods() {
	GDVIRTUAL_BIND(_save, "path", "resource", "flags");
	GDVIRTUAL_BIND(_recognize, "resource");
	GDVIRTUAL_BIND(_get_recognized_extensions, "resource");
}

Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
	String path = p_path;
	if (path.is_empty()) {
		path = p_resource->get_path();
	}
	ERR_FAIL_COND_V_MSG(path.is_empty(), ERR_INVALID_PARAMETER, "Can't save resource to empty path. Provide non-empty path or a Resource with non-empty resource_path.");

	String extension = path.get_extension();
	Error err = ERR_FILE_UNRECOGNIZED;

	for (int i = 0; i < saver_count; i++) {
		if (!saver[i]->recognize(p_resource)) {
			continue;
		}

		List<String> extensions;
		bool recognized = false;
		saver[i]->get_recognized_extensions(p_resource, &extensions);

		for (const String &E : extensions) {
			if (E.nocasecmp_to(extension) == 0) {
				recognized = true;
			}
		}

		if (!recognized) {
			continue;
		}

		String old_path = p_resource->get_path();

		String local_path = ProjectSettings::get_singleton()->localize_path(path);

		Ref<Resource> rwcopy = p_resource;
		if (p_flags & FLAG_CHANGE_PATH) {
			rwcopy->set_path(local_path);
		}

		err = saver[i]->save(p_resource, path, p_flags);

		if (err == OK) {
#ifdef TOOLS_ENABLED

			((Resource *)p_resource.ptr())->set_edited(false);
			if (timestamp_on_save) {
				uint64_t mt = FileAccess::get_modified_time(path);

				((Resource *)p_resource.ptr())->set_last_modified_time(mt);
			}
#endif

			if (p_flags & FLAG_CHANGE_PATH) {
				rwcopy->set_path(old_path);
			}

			if (save_callback && path.begins_with("res://")) {
				save_callback(p_resource, path);
			}

			return OK;
		}
	}

	return err;
}

void ResourceSaver::set_save_callback(ResourceSavedCallback p_callback) {
	save_callback = p_callback;
}

void ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) {
	for (int i = 0; i < saver_count; i++) {
		saver[i]->get_recognized_extensions(p_resource, p_extensions);
	}
}

void ResourceSaver::add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front) {
	ERR_FAIL_COND_MSG(p_format_saver.is_null(), "It's not a reference to a valid ResourceFormatSaver object.");
	ERR_FAIL_COND(saver_count >= MAX_SAVERS);

	if (p_at_front) {
		for (int i = saver_count; i > 0; i--) {
			saver[i] = saver[i - 1];
		}
		saver[0] = p_format_saver;
		saver_count++;
	} else {
		saver[saver_count++] = p_format_saver;
	}
}

void ResourceSaver::remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver) {
	ERR_FAIL_COND_MSG(p_format_saver.is_null(), "It's not a reference to a valid ResourceFormatSaver object.");

	// Find saver
	int i = 0;
	for (; i < saver_count; ++i) {
		if (saver[i] == p_format_saver) {
			break;
		}
	}

	ERR_FAIL_COND(i >= saver_count); // Not found

	// Shift next savers up
	for (; i < saver_count - 1; ++i) {
		saver[i] = saver[i + 1];
	}
	saver[saver_count - 1].unref();
	--saver_count;
}

Ref<ResourceFormatSaver> ResourceSaver::_find_custom_resource_format_saver(String path) {
	for (int i = 0; i < saver_count; ++i) {
		if (saver[i]->get_script_instance() && saver[i]->get_script_instance()->get_script()->get_path() == path) {
			return saver[i];
		}
	}
	return Ref<ResourceFormatSaver>();
}

bool ResourceSaver::add_custom_resource_format_saver(String script_path) {
	if (_find_custom_resource_format_saver(script_path).is_valid()) {
		return false;
	}

	Ref<Resource> res = ResourceLoader::load(script_path);
	ERR_FAIL_COND_V(res.is_null(), false);
	ERR_FAIL_COND_V(!res->is_class("Script"), false);

	Ref<Script> s = res;
	StringName ibt = s->get_instance_base_type();
	bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatSaver");
	ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceSaver: " + script_path + ".");

	Object *obj = ClassDB::instantiate(ibt);

	ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + ".");

	Ref<ResourceFormatSaver> crl = Object::cast_to<ResourceFormatSaver>(obj);
	crl->set_script(s);
	ResourceSaver::add_resource_format_saver(crl);

	return true;
}

void ResourceSaver::remove_custom_resource_format_saver(String script_path) {
	Ref<ResourceFormatSaver> custom_saver = _find_custom_resource_format_saver(script_path);
	if (custom_saver.is_valid()) {
		remove_resource_format_saver(custom_saver);
	}
}

void ResourceSaver::add_custom_savers() {
	// Custom resource savers exploits global class names

	String custom_saver_base_class = ResourceFormatSaver::get_class_static();

	List<StringName> global_classes;
	ScriptServer::get_global_class_list(&global_classes);

	for (const StringName &class_name : global_classes) {
		StringName base_class = ScriptServer::get_global_class_native_base(class_name);

		if (base_class == custom_saver_base_class) {
			String path = ScriptServer::get_global_class_path(class_name);
			add_custom_resource_format_saver(path);
		}
	}
}

void ResourceSaver::remove_custom_savers() {
	Vector<Ref<ResourceFormatSaver>> custom_savers;
	for (int i = 0; i < saver_count; ++i) {
		if (saver[i]->get_script_instance()) {
			custom_savers.push_back(saver[i]);
		}
	}

	for (int i = 0; i < custom_savers.size(); ++i) {
		remove_resource_format_saver(custom_savers[i]);
	}
}

ResourceUID::ID ResourceSaver::get_resource_id_for_path(const String &p_path, bool p_generate) {
	if (save_get_id_for_path) {
		return save_get_id_for_path(p_path, p_generate);
	}
	return ResourceUID::INVALID_ID;
}

void ResourceSaver::set_get_resource_id_for_path(ResourceSaverGetResourceIDForPath p_callback) {
	save_get_id_for_path = p_callback;
}
<|endoftext|>


<commit_before><commit_msg>use subfolders for instancecontenttype and export eobj rotation<commit_after><|endoftext|>