<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkSTLWriter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkSTLWriter.h"

#include "vtkByteSwap.h"
#include "vtkCellArray.h"
#include "vtkErrorCode.h"
#include "vtkInformation.h"
#include "vtkObjectFactory.h"
#include "vtkPolyData.h"
#include "vtkTriangle.h"
#include <vtksys/SystemTools.hxx>

#if !defined(_WIN32) || defined(__CYGWIN__)
# include <unistd.h> /* unlink */
#else
# include <io.h> /* unlink */
#endif

vtkStandardNewMacro(vtkSTLWriter);

static char header[]="Visualization Toolkit generated SLA File                                        ";

vtkSTLWriter::vtkSTLWriter()
{
  this->FileType = VTK_ASCII;
  this->FileName = NULL;
  this->Header = new char[257];
  strcpy(this->Header, header);
}

void vtkSTLWriter::WriteData()
{
  vtkPoints *pts;
  vtkCellArray *polys;
  vtkPolyData *input = this->GetInput();

  polys = input->GetPolys();
  pts = input->GetPoints();
  if (pts == NULL || polys == NULL )
    {
    vtkErrorMacro(<<"No data to write!");
    return;
    }

  if ( this->FileName == NULL)
    {
    vtkErrorMacro(<< "Please specify FileName to write");
    this->SetErrorCode(vtkErrorCode::NoFileNameError);
    return;
    }

  if ( this->FileType == VTK_BINARY )
    {
    this->WriteBinarySTL(pts,polys);
    if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
      {
      vtkErrorMacro("Ran out of disk space; deleting file: "
                    << this->FileName);
      unlink(this->FileName);
      }
    }
  else
    {
    this->WriteAsciiSTL(pts,polys);
    if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
      {
      vtkErrorMacro("Ran out of disk space; deleting file: "
                    << this->FileName);
      unlink(this->FileName);
      }
    }
}

void vtkSTLWriter::WriteAsciiSTL(vtkPoints *pts, vtkCellArray *polys)
{
  FILE *fp;
  double n[3], v1[3], v2[3], v3[3];
  vtkIdType npts = 0;
  vtkIdType *indx = 0;

  if ((fp = fopen(this->FileName, "w")) == NULL)
    {
    vtkErrorMacro(<< "Couldn't open file: " << this->FileName);
    this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
    return;
    }
//
//  Write header
//
  vtkDebugMacro("Writing ASCII sla file");
  if (fprintf (fp, "solid ascii\n") < 0)
    {
    fclose(fp);
    this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
    return;
    }
//
//  Write out triangle polygons.  In not a triangle polygon, only first
//  three vertices are written.
//
  for (polys->InitTraversal(); polys->GetNextCell(npts,indx); )
    {
    pts->GetPoint(indx[0],v1);
    pts->GetPoint(indx[1],v2);
    pts->GetPoint(indx[2],v3);

    vtkTriangle::ComputeNormal(pts, npts, indx, n);

    if (fprintf (fp, " facet normal %.6g %.6g %.6g\n  outer loop\n",
                 n[0], n[1], n[2]) < 0)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }

    if (fprintf (fp, "   vertex %.6g %.6g %.6g\n", v1[0], v1[1], v1[2]) < 0)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    if (fprintf (fp, "   vertex %.6g %.6g %.6g\n", v2[0], v2[1], v2[2]) < 0)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    if (fprintf (fp, "   vertex %.6g %.6g %.6g\n", v3[0], v3[1], v3[2]) < 0)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }

    if (fprintf (fp, "  endloop\n endfacet\n") < 0)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    }
  if (fprintf (fp, "endsolid\n") < 0)
    {
    this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
    }
  fclose (fp);
}

void vtkSTLWriter::WriteBinarySTL(vtkPoints *pts, vtkCellArray *polys)
{
  FILE *fp;
  double dn[3], v1[3], v2[3], v3[3];
  vtkIdType npts = 0;
  vtkIdType *indx = 0;
  unsigned long ulint;
  unsigned short ibuff2=0;

  if ((fp = fopen(this->FileName, "wb")) == NULL)
    {
    vtkErrorMacro(<< "Couldn't open file: " << this->FileName);
    this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
    return;
    }

  //  Write header
  //
  vtkDebugMacro("Writing Binary STL file");

  char szHeader[80+1];

  // Check for STL ASCII format key word 'solid'. According to STL file format
  // only ASCII files can have 'solid' as start key word, so we ignore it and
  // use VTK string instead.
  if (vtksys::SystemTools::StringStartsWith(this->Header, "solid"))
  {
    vtkDebugMacro("Invalid header for Binary STL file");
    strcpy(szHeader, header);
  }
  else
  {
    memset(szHeader, 32, 80);  // fill with space (ASCII=>32)
    sprintf(szHeader, "%s", this->Header);
  }

  if (fwrite (szHeader, 1, 80, fp) < 80)
    {
    fclose(fp);
    this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
    return;
    }

  ulint = (unsigned long int) polys->GetNumberOfCells();
  vtkByteSwap::Swap4LE(&ulint);
  if (fwrite (&ulint, 1, 4, fp) < 4)
    {
    fclose(fp);
    this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
    return;
    }

  //  Write out triangle polygons.  In not a triangle polygon, only first
  //  three vertices are written.
  //
  for (polys->InitTraversal(); polys->GetNextCell(npts,indx); )
    {
    pts->GetPoint(indx[0],v1);
    pts->GetPoint(indx[1],v2);
    pts->GetPoint(indx[2],v3);

    vtkTriangle::ComputeNormal(pts, npts, indx, dn);
    float n[3];
    n[0] = (float)dn[0];
    n[1] = (float)dn[1];
    n[2] = (float)dn[2];
    vtkByteSwap::Swap4LE(n);
    vtkByteSwap::Swap4LE(n+1);
    vtkByteSwap::Swap4LE(n+2);
    if (fwrite (n, 4, 3, fp) < 3)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }

    n[0] = (float)v1[0];  n[1] = (float)v1[1];  n[2] = (float)v1[2];
    vtkByteSwap::Swap4LE(n);
    vtkByteSwap::Swap4LE(n+1);
    vtkByteSwap::Swap4LE(n+2);
    if (fwrite (n, 4, 3, fp) < 3)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }

    n[0] = (float)v2[0];  n[1] = (float)v2[1];  n[2] = (float)v2[2];
    vtkByteSwap::Swap4LE(n);
    vtkByteSwap::Swap4LE(n+1);
    vtkByteSwap::Swap4LE(n+2);
    if (fwrite (n, 4, 3, fp) < 3)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }

    n[0] = (float)v3[0];  n[1] = (float)v3[1];  n[2] = (float)v3[2];
    vtkByteSwap::Swap4LE(n);
    vtkByteSwap::Swap4LE(n+1);
    vtkByteSwap::Swap4LE(n+2);
    if (fwrite (n, 4, 3, fp) < 3)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }

    if (fwrite (&ibuff2, 2, 1, fp) < 1)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    }
  fclose (fp);
}

//----------------------------------------------------------------------------
void vtkSTLWriter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}

//----------------------------------------------------------------------------
vtkPolyData* vtkSTLWriter::GetInput()
{
  return vtkPolyData::SafeDownCast(this->Superclass::GetInput());
}

//----------------------------------------------------------------------------
vtkPolyData* vtkSTLWriter::GetInput(int port)
{
  return vtkPolyData::SafeDownCast(this->Superclass::GetInput(port));
}

//----------------------------------------------------------------------------
int vtkSTLWriter::FillInputPortInformation(int, vtkInformation *info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
  return 1;
}
<commit_msg>STLWriter: Raise an error for non-triangles<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkSTLWriter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkSTLWriter.h"

#include "vtkByteSwap.h"
#include "vtkCellArray.h"
#include "vtkErrorCode.h"
#include "vtkInformation.h"
#include "vtkObjectFactory.h"
#include "vtkPolyData.h"
#include "vtkTriangle.h"
#include <vtksys/SystemTools.hxx>

#if !defined(_WIN32) || defined(__CYGWIN__)
# include <unistd.h> /* unlink */
#else
# include <io.h> /* unlink */
#endif

vtkStandardNewMacro(vtkSTLWriter);

static char header[]="Visualization Toolkit generated SLA File                                        ";

vtkSTLWriter::vtkSTLWriter()
{
  this->FileType = VTK_ASCII;
  this->FileName = NULL;
  this->Header = new char[257];
  strcpy(this->Header, header);
}

void vtkSTLWriter::WriteData()
{
  vtkPoints *pts;
  vtkCellArray *polys;
  vtkPolyData *input = this->GetInput();

  polys = input->GetPolys();
  pts = input->GetPoints();
  if (pts == NULL || polys == NULL )
    {
    vtkErrorMacro(<<"No data to write!");
    return;
    }

  if ( this->FileName == NULL)
    {
    vtkErrorMacro(<< "Please specify FileName to write");
    this->SetErrorCode(vtkErrorCode::NoFileNameError);
    return;
    }

  if ( this->FileType == VTK_BINARY )
    {
    this->WriteBinarySTL(pts,polys);
    if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
      {
      vtkErrorMacro("Ran out of disk space; deleting file: "
                    << this->FileName);
      unlink(this->FileName);
      }
    }
  else
    {
    this->WriteAsciiSTL(pts,polys);
    if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
      {
      vtkErrorMacro("Ran out of disk space; deleting file: "
                    << this->FileName);
      unlink(this->FileName);
      }
    }
}

void vtkSTLWriter::WriteAsciiSTL(vtkPoints *pts, vtkCellArray *polys)
{
  FILE *fp;
  double n[3], v1[3], v2[3], v3[3];
  vtkIdType npts = 0;
  vtkIdType *indx = 0;

  if ((fp = fopen(this->FileName, "w")) == NULL)
    {
    vtkErrorMacro(<< "Couldn't open file: " << this->FileName);
    this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
    return;
    }
//
//  Write header
//
  vtkDebugMacro("Writing ASCII sla file");
  if (fprintf (fp, "solid ascii\n") < 0)
    {
    fclose(fp);
    this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
    return;
    }
//
//  Write out triangle polygons.  In not a triangle polygon, only first
//  three vertices are written.
//
  for (polys->InitTraversal(); polys->GetNextCell(npts,indx); )
    {
    if (npts > 3)
      {
      fclose(fp);
      vtkErrorMacro(<<"STL file only supports triangles");
      this->SetErrorCode(vtkErrorCode::FileFormatError);
      return;
      }

    pts->GetPoint(indx[0],v1);
    pts->GetPoint(indx[1],v2);
    pts->GetPoint(indx[2],v3);

    vtkTriangle::ComputeNormal(pts, npts, indx, n);

    if (fprintf (fp, " facet normal %.6g %.6g %.6g\n  outer loop\n",
                 n[0], n[1], n[2]) < 0)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }

    if (fprintf (fp, "   vertex %.6g %.6g %.6g\n", v1[0], v1[1], v1[2]) < 0)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    if (fprintf (fp, "   vertex %.6g %.6g %.6g\n", v2[0], v2[1], v2[2]) < 0)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    if (fprintf (fp, "   vertex %.6g %.6g %.6g\n", v3[0], v3[1], v3[2]) < 0)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }

    if (fprintf (fp, "  endloop\n endfacet\n") < 0)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    }
  if (fprintf (fp, "endsolid\n") < 0)
    {
    this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
    }
  fclose (fp);
}

void vtkSTLWriter::WriteBinarySTL(vtkPoints *pts, vtkCellArray *polys)
{
  FILE *fp;
  double dn[3], v1[3], v2[3], v3[3];
  vtkIdType npts = 0;
  vtkIdType *indx = 0;
  unsigned long ulint;
  unsigned short ibuff2=0;

  if ((fp = fopen(this->FileName, "wb")) == NULL)
    {
    vtkErrorMacro(<< "Couldn't open file: " << this->FileName);
    this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
    return;
    }

  //  Write header
  //
  vtkDebugMacro("Writing Binary STL file");

  char szHeader[80+1];

  // Check for STL ASCII format key word 'solid'. According to STL file format
  // only ASCII files can have 'solid' as start key word, so we ignore it and
  // use VTK string instead.
  if (vtksys::SystemTools::StringStartsWith(this->Header, "solid"))
  {
    vtkDebugMacro("Invalid header for Binary STL file");
    strcpy(szHeader, header);
  }
  else
  {
    memset(szHeader, 32, 80);  // fill with space (ASCII=>32)
    sprintf(szHeader, "%s", this->Header);
  }

  if (fwrite (szHeader, 1, 80, fp) < 80)
    {
    fclose(fp);
    this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
    return;
    }

  ulint = (unsigned long int) polys->GetNumberOfCells();
  vtkByteSwap::Swap4LE(&ulint);
  if (fwrite (&ulint, 1, 4, fp) < 4)
    {
    fclose(fp);
    this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
    return;
    }

  //  Write out triangle polygons.  In not a triangle polygon, only first
  //  three vertices are written.
  //
  for (polys->InitTraversal(); polys->GetNextCell(npts,indx); )
    {
    if (npts > 3)
      {
      fclose(fp);
      vtkErrorMacro(<<"STL file only supports triangles");
      this->SetErrorCode(vtkErrorCode::FileFormatError);
      return;
      }

    pts->GetPoint(indx[0],v1);
    pts->GetPoint(indx[1],v2);
    pts->GetPoint(indx[2],v3);

    vtkTriangle::ComputeNormal(pts, npts, indx, dn);
    float n[3];
    n[0] = (float)dn[0];
    n[1] = (float)dn[1];
    n[2] = (float)dn[2];
    vtkByteSwap::Swap4LE(n);
    vtkByteSwap::Swap4LE(n+1);
    vtkByteSwap::Swap4LE(n+2);
    if (fwrite (n, 4, 3, fp) < 3)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }

    n[0] = (float)v1[0];  n[1] = (float)v1[1];  n[2] = (float)v1[2];
    vtkByteSwap::Swap4LE(n);
    vtkByteSwap::Swap4LE(n+1);
    vtkByteSwap::Swap4LE(n+2);
    if (fwrite (n, 4, 3, fp) < 3)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }

    n[0] = (float)v2[0];  n[1] = (float)v2[1];  n[2] = (float)v2[2];
    vtkByteSwap::Swap4LE(n);
    vtkByteSwap::Swap4LE(n+1);
    vtkByteSwap::Swap4LE(n+2);
    if (fwrite (n, 4, 3, fp) < 3)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }

    n[0] = (float)v3[0];  n[1] = (float)v3[1];  n[2] = (float)v3[2];
    vtkByteSwap::Swap4LE(n);
    vtkByteSwap::Swap4LE(n+1);
    vtkByteSwap::Swap4LE(n+2);
    if (fwrite (n, 4, 3, fp) < 3)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }

    if (fwrite (&ibuff2, 2, 1, fp) < 1)
      {
      fclose(fp);
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    }
  fclose (fp);
}

//----------------------------------------------------------------------------
void vtkSTLWriter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}

//----------------------------------------------------------------------------
vtkPolyData* vtkSTLWriter::GetInput()
{
  return vtkPolyData::SafeDownCast(this->Superclass::GetInput());
}

//----------------------------------------------------------------------------
vtkPolyData* vtkSTLWriter::GetInput(int port)
{
  return vtkPolyData::SafeDownCast(this->Superclass::GetInput(port));
}

//----------------------------------------------------------------------------
int vtkSTLWriter::FillInputPortInformation(int, vtkInformation *info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
  return 1;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2005, 2006, 2007 Florian Schmitz
 *
 * This file is part of CSSTidy.
 *
 *  CSSTidy is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   CSSTidy 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 Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "csspp_globals.hpp"
using namespace std;

extern vector<string> unit_values,color_values;
extern map<string,string> replace_colors,all_properties;

string shorthand(string value)
{
	string important = "";

	if(is_important(value))
	{
		value = gvw_important(value);
		important = "!important";
	}

	vector<string> values = explode(" ",value);
	switch(values.size())
	{
		case 4:
		if(values[0] == values[1] && values[0] == values[2] && values[0] == values[3])
		{
			return values[0] + important;
		}
		else if(values[1] == values[3] && values[0] == values[2])
		{
			return values[0] + " " + values[1] + important;
		}
		else if(values[1] == values[3])
		{
			return values[0] + " " + values[1] + " " + values[2] + important;
		}
		else return value + important;
		break;

		case 3:
		if(values[0] == values[1] && values[0] == values[2])
		{
			return values[0] + important;
		}
		else if(values[0] == values[2])
		{
			return values[0] + " " + values[1] + important;
		}
		else return value + important;
		break;

		case 2:
		if(values[0] == values[1])
		{
			return values[0] + important;
		}
		else return value + important;
		break;

		default:
		return value + important;
	}
}

string compress_numbers(string subvalue, string property, string function)
{
	string units[] = {"in", "cm", "mm", "pt", "pc", "px", "rem", "%", "ex", "gd", "em", "vw", "vh",
	                  "vm", "ch", "deg", "grad", "rad", "turn", "ms", "s", "khz", "hz" }; // sync  for loop

	vector<string> temp;
	if(property == "font")
	{
		temp = explode("/",subvalue);
	}
	else
	{
		temp.push_back(subvalue);
	}

	for (int i = 0; i < temp.size(); ++i)
	{
		if(!(temp[i].length() > 0 && (ctype_digit(temp[i][0]) || temp[i][0] == '+' || temp[i][0] == '-' ) ))
		{
			continue;
		}

		if(function == "" && in_str_array(color_values,property))
		{
			temp[i] = "#" + temp[i];
			//csstidy::log("Inserting missing '#'", Warning); // FIXME: Make log() a static method
		}

		if(str2f(temp[i]) == 0)
		{
			temp[i] = "0";
		}
		else
		{
			bool unit_found = false;
			temp[i] = strtolower(temp[i]);
			for(int j = 0; j < 21; ++j )
			{
				if(temp[i].find(units[j]) != string::npos)
				{
					temp[i] = f2str(str2f(temp[i])) + units[j];
					unit_found = true;
					break;
				}
			}
			if(function == "" && !unit_found && in_str_array(unit_values,property))
			{
				temp[i] = f2str(str2f(temp[i]));
				temp[i] += "px";
				//csstidy::log("Unit required, inserting 'px'", Warning); // FIXME: Make log() a static method
			}
			else if(!unit_found)
			{
				temp[i] = f2str(str2f(temp[i]));
			}
			// Remove leading zero
            if (abs( (int) str2f(temp[i])) < 1) {
                if (str2f(temp[i]) < 0) {
                    temp[i] = '-' + temp[i].substr(2);
                } else {
                    temp[i] = temp[i].substr(1);
                }
            }
		}
	}

	return (temp.size() > 1) ? temp[0] + "/" + temp[1] : ((temp.size() > 0) ? temp[0] : "");
}

bool property_is_next(string istring, int pos)
{
	istring = istring.substr(pos,istring.length()-pos);
	pos = istring.find_first_of(':',0);
	if(pos == string::npos)
	{
		return false;
	}
	istring = strtolower(trim(istring.substr(0,pos)));
	return (all_properties.count(istring) > 0);
}

string cut_color(string color)
{
	if(strtolower(color.substr(0,4)) == "rgb(")
	{
		vector<string> color_tmp = explode(",",color.substr(4,color.length()-5));

		for (int i = 0; i < color_tmp.size(); ++i)
		{
			color_tmp[i] = trim(color_tmp[i]);
			if(color_tmp[i].at(color_tmp[i].length()-1) == '%')
			{
				color_tmp[i] = f2str(round(255 * atoi(color_tmp[i].c_str())/100,0));
			}
			if(atoi(color_tmp[i].c_str()) > 255) color_tmp[i] = 255;
		}

		color = "#";
		for (int i = 0; i < color_tmp.size(); ++i)
		{
			if(atoi(color_tmp[i].c_str()) < 16)
			{
				color += "0" + dechex(atoi(color_tmp[i].c_str()));
			}
			else
			{
				color += dechex(atoi(color_tmp[i].c_str()));
			}
		}
	}

	// Fix bad color names
	if(replace_colors.count(strtolower(color)) > 0)
	{
		color = replace_colors[strtolower(color)];
	}

	if(color.length() == 7)
	{
		string color_temp = strtoupper(color);

		if(color_temp[0] == '#' && color_temp[1] == color_temp[2] && color_temp[3] == color_temp[4] && color_temp[5] == color_temp[6])
		{
			color = "#";
			color += color_temp[2];
			color += color_temp[3];
			color += color_temp[5];
		}
	}

	string temp = strtolower(color);
	/* color name -> hex code */
	if(temp == "black")		return "#000";
	if(temp == "fuchsia")	return "#F0F";
	if(temp == "white")		return "#FFF";
	if(temp == "yellow")	return "#FF0";
	/* hex code -> color name */
	if(temp == "#800000")	return "maroon";
	if(temp == "#ffa500")	return "orange";
	if(temp == "#808000")	return "olive";
	if(temp == "#800080")	return "purple";
	if(temp == "#008000")	return "green";
	if(temp == "#000080")	return "navy";
	if(temp == "#008080")	return "teal";
	if(temp == "#c0c0c0")	return "silver";
	if(temp == "#808080")	return "gray";
	if(temp == "#f00")		return "red";

	return color;
}

int c_font_weight(string& value)
{
	string important = "";
	if(is_important(value))
	{
		important = "!important";
		value = gvw_important(value);
	}
	if(value == "bold")
	{
		value = "700"+important;
		return 700;
	}
	else if(value == "normal")
	{
		value = "400"+important;
		return 400;
	}
	return 0;
}

void merge_selectors(sstore& input)
{
	for(sstore::iterator i = input.begin(), e = input.end(); i != e;)
	{
		string newsel = "";

		// Check if properties also exist in another selector
		vector<string> keys;
		for(sstore::iterator j = input.begin(); j != input.end(); j++ )
		{
			if(j->first == i->first)
			{
				continue;
			}

			if(input[j->first] == input[i->first])
			{
				keys.push_back(j->first);
			}
		}

		if(keys.size() > 0)
		{
			newsel = i->first;

			for(int k = 0; k < keys.size(); ++k)
			{
				input.erase(keys[k]);
				newsel += "," + keys[k];
			}

			input[newsel] = i->second;

			input.erase(i);
			e = input.end();
		} else {
			i++;
		}
	}
}
<commit_msg>Added new CSS 3 units (“ch” and “turn”). http://www.w3.org/TR/css3-values/#relative0<commit_after>/*
 * Copyright 2005, 2006, 2007 Florian Schmitz
 *
 * This file is part of CSSTidy.
 *
 *  CSSTidy is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   CSSTidy 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 Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "csspp_globals.hpp"
using namespace std;

extern vector<string> unit_values,color_values;
extern map<string,string> replace_colors,all_properties;

string shorthand(string value)
{
	string important = "";

	if(is_important(value))
	{
		value = gvw_important(value);
		important = "!important";
	}

	vector<string> values = explode(" ",value);
	switch(values.size())
	{
		case 4:
		if(values[0] == values[1] && values[0] == values[2] && values[0] == values[3])
		{
			return values[0] + important;
		}
		else if(values[1] == values[3] && values[0] == values[2])
		{
			return values[0] + " " + values[1] + important;
		}
		else if(values[1] == values[3])
		{
			return values[0] + " " + values[1] + " " + values[2] + important;
		}
		else return value + important;
		break;

		case 3:
		if(values[0] == values[1] && values[0] == values[2])
		{
			return values[0] + important;
		}
		else if(values[0] == values[2])
		{
			return values[0] + " " + values[1] + important;
		}
		else return value + important;
		break;

		case 2:
		if(values[0] == values[1])
		{
			return values[0] + important;
		}
		else return value + important;
		break;

		default:
		return value + important;
	}
}

string compress_numbers(string subvalue, string property, string function)
{
	string units[] = {"in", "cm", "mm", "pt", "pc", "px", "rem", "%", "ex", "gd", "em", "vw", "vh",
	                  "vm", "ch", "deg", "grad", "rad", "turn", "ms", "s", "khz", "hz" }; // sync  for loop

	vector<string> temp;
	if(property == "font")
	{
		temp = explode("/",subvalue);
	}
	else
	{
		temp.push_back(subvalue);
	}

	for (int i = 0; i < temp.size(); ++i)
	{
		if(!(temp[i].length() > 0 && (ctype_digit(temp[i][0]) || temp[i][0] == '+' || temp[i][0] == '-' ) ))
		{
			continue;
		}

		if(function == "" && in_str_array(color_values,property))
		{
			temp[i] = "#" + temp[i];
			//csstidy::log("Inserting missing '#'", Warning); // FIXME: Make log() a static method
		}

		if(str2f(temp[i]) == 0)
		{
			temp[i] = "0";
		}
		else
		{
			bool unit_found = false;
			temp[i] = strtolower(temp[i]);
			for(int j = 0; j < 21; ++j )
			{
				if(temp[i].find(units[j]) != string::npos)
				{
					temp[i] = f2str(str2f(temp[i])) + units[j];
					unit_found = true;
					break;
				}
			}
			if(function == "" && !unit_found && in_str_array(unit_values,property))
			{
				temp[i] = f2str(str2f(temp[i]));
				temp[i] += "px";
				//csstidy::log("Unit required, inserting 'px'", Warning); // FIXME: Make log() a static method
			}
			else if(!unit_found)
			{
				temp[i] = f2str(str2f(temp[i]));
			}
			// Remove leading zero
            if (abs( (int) str2f(temp[i])) < 1) {
                if (str2f(temp[i]) < 0) {
                    temp[i] = '-' + temp[i].substr(2);
                } else {
                    temp[i] = temp[i].substr(1);
                }
            }
		}
	}

	return (temp.size() > 1) ? temp[0] + "/" + temp[1] : ((temp.size() > 0) ? temp[0] : "");
}

bool property_is_next(string istring, int pos)
{
	istring = istring.substr(pos,istring.length()-pos);
	pos = istring.find_first_of(':',0);
	if(pos == string::npos)
	{
		return false;
	}
	istring = strtolower(trim(istring.substr(0,pos)));
	return (all_properties.count(istring) > 0);
}

string cut_color(string color)
{
	if(strtolower(color.substr(0,4)) == "rgb(")
	{
		vector<string> color_tmp = explode(",",color.substr(4,color.length()-5));

		for (int i = 0; i < color_tmp.size(); ++i)
		{
			color_tmp[i] = trim(color_tmp[i]);
			if(color_tmp[i].at(color_tmp[i].length()-1) == '%')
			{
				color_tmp[i] = f2str(round(255 * atoi(color_tmp[i].c_str())/100,0));
			}
			if(atoi(color_tmp[i].c_str()) > 255) color_tmp[i] = 255;
		}

		color = "#";
		for (int i = 0; i < color_tmp.size(); ++i)
		{
			if(atoi(color_tmp[i].c_str()) < 16)
			{
				color += "0" + dechex(atoi(color_tmp[i].c_str()));
			}
			else
			{
				color += dechex(atoi(color_tmp[i].c_str()));
			}
		}
	}

	// Fix bad color names
	if(replace_colors.count(strtolower(color)) > 0)
	{
		color = replace_colors[strtolower(color)];
	}

	if(color.length() == 7)
	{
		string color_temp = strtoupper(color);

		if(color_temp[0] == '#' && color_temp[1] == color_temp[2] && color_temp[3] == color_temp[4] && color_temp[5] == color_temp[6])
		{
			color = "#";
			color += color_temp[2];
			color += color_temp[3];
			color += color_temp[5];
		}
	}

	string temp = strtolower(color);
	/* color name -> hex code */
	if(temp == "black")		return "#000";
	if(temp == "fuchsia")	return "#f0f";
	if(temp == "white")		return "#fff";
	if(temp == "yellow")	return "#ff0";
	/* hex code -> color name */
	if(temp == "#800000")	return "maroon";
	if(temp == "#ffa500")	return "orange";
	if(temp == "#808000")	return "olive";
	if(temp == "#800080")	return "purple";
	if(temp == "#008000")	return "green";
	if(temp == "#000080")	return "navy";
	if(temp == "#008080")	return "teal";
	if(temp == "#c0c0c0")	return "silver";
	if(temp == "#808080")	return "gray";
	if(temp == "#f00")		return "red";

	return color;
}

int c_font_weight(string& value)
{
	string important = "";
	if(is_important(value))
	{
		important = "!important";
		value = gvw_important(value);
	}
	if(value == "bold")
	{
		value = "700"+important;
		return 700;
	}
	else if(value == "normal")
	{
		value = "400"+important;
		return 400;
	}
	return 0;
}

void merge_selectors(sstore& input)
{
	for(sstore::iterator i = input.begin(), e = input.end(); i != e;)
	{
		string newsel = "";

		// Check if properties also exist in another selector
		vector<string> keys;
		for(sstore::iterator j = input.begin(); j != input.end(); j++ )
		{
			if(j->first == i->first)
			{
				continue;
			}

			if(input[j->first] == input[i->first])
			{
				keys.push_back(j->first);
			}
		}

		if(keys.size() > 0)
		{
			newsel = i->first;

			for(int k = 0; k < keys.size(); ++k)
			{
				input.erase(keys[k]);
				newsel += "," + keys[k];
			}

			input[newsel] = i->second;

			input.erase(i);
			e = input.end();
		} else {
			i++;
		}
	}
}
<|endoftext|>


<commit_before>// LAF OS Library
// Copyright (C) 2017  David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "os/draw_text.h"

#include "ft/algorithm.h"
#include "ft/hb_shaper.h"
#include "gfx/clip.h"
#include "os/common/freetype_font.h"
#include "os/common/generic_surface.h"
#include "os/common/sprite_sheet_font.h"

namespace os {

gfx::Rect draw_text(Surface* surface, Font* font,
                    const base::utf8_const_iterator& begin,
                    const base::utf8_const_iterator& end,
                    gfx::Color fg, gfx::Color bg,
                    int x, int y,
                    DrawTextDelegate* delegate)
{
  base::utf8_const_iterator it = begin;
  gfx::Rect textBounds;

retry:;
  // Check if this font is enough to draw the given string or we will
  // need the fallback for some special Unicode chars
  if (font->fallback()) {
    // TODO compose unicode characters and check those codepoints, the
    //      same in the drawing code of sprite sheet font
    for (auto it=begin; it!=end; ++it) {
      uint32_t code = *it;
      if (code && !font->hasCodePoint(code)) {
        Font* newFont = font->fallback();

        // Search a valid fallback
        while (newFont && !newFont->hasCodePoint(code))
          newFont = newFont->fallback();
        if (!newFont)
          break;

        y += font->height()/2 - newFont->height()/2;

        font = newFont;
        goto retry;
      }
    }
  }

  switch (font->type()) {

    case FontType::kSpriteSheet: {
      SpriteSheetFont* ssFont = static_cast<SpriteSheetFont*>(font);
      Surface* sheet = ssFont->getSurfaceSheet();

      if (surface) {
        sheet->lock();
        surface->lock();
      }

      while (it != end) {
        int chr = *it;
        if (delegate) {
          int i = it-begin;
          delegate->preProcessChar(i, chr, fg, bg);
        }

        gfx::Rect charBounds = ssFont->getCharBounds(chr);
        gfx::Rect outCharBounds(x, y, charBounds.w, charBounds.h);
        if (delegate && !delegate->preDrawChar(outCharBounds))
          break;

        if (!charBounds.isEmpty()) {
          if (surface)
            surface->drawColoredRgbaSurface(sheet, fg, bg, gfx::Clip(x, y, charBounds));
        }

        textBounds |= outCharBounds;
        if (delegate)
          delegate->postDrawChar(outCharBounds);

        x += charBounds.w;
        ++it;
      }

      if (surface) {
        surface->unlock();
        sheet->unlock();
      }
      break;
    }

    case FontType::kTrueType: {
      FreeTypeFont* ttFont = static_cast<FreeTypeFont*>(font);
      bool antialias = ttFont->face().antialias();
      int fg_alpha = gfx::geta(fg);

      gfx::Rect clipBounds;
      os::SurfaceFormatData fd;
      if (surface) {
        clipBounds = surface->getClipBounds();
        surface->getFormat(&fd);
        surface->lock();
      }

      ft::ForEachGlyph<FreeTypeFont::Face> feg(ttFont->face());
      if (feg.initialize(it, end)) {
        do {
          if (delegate) {
            delegate->preProcessChar(feg.charIndex(),
                                     feg.unicodeChar(), fg, bg);
          }

          auto glyph = feg.glyph();
          if (!glyph)
            continue;

          gfx::Rect origDstBounds(
            x + int(glyph->startX),
            y + int(glyph->y),
            int(glyph->endX) - int(glyph->startX),
            int(glyph->bitmap->rows) ? int(glyph->bitmap->rows): 1);

          if (delegate && !delegate->preDrawChar(origDstBounds))
            break;

          origDstBounds.x = x + int(glyph->x);
          origDstBounds.w = int(glyph->bitmap->width);
          origDstBounds.h = int(glyph->bitmap->rows);

          gfx::Rect dstBounds = origDstBounds;
          if (surface)
            dstBounds &= clipBounds;

          if (surface && !dstBounds.isEmpty()) {
            int clippedRows = dstBounds.y - origDstBounds.y;
            int dst_y = dstBounds.y;
            int t;
            for (int v=0; v<dstBounds.h; ++v, ++dst_y) {
              int bit = 0;
              const uint8_t* p = glyph->bitmap->buffer
                + (v+clippedRows)*glyph->bitmap->pitch;
              int dst_x = dstBounds.x;
              uint32_t* dst_address =
                (uint32_t*)surface->getData(dst_x, dst_y);

              // Skip first clipped pixels
              for (int u=0; u<dstBounds.x-origDstBounds.x; ++u) {
                if (antialias) {
                  ++p;
                }
                else {
                  if (bit == 8) {
                    bit = 0;
                    ++p;
                  }
                }
              }

              for (int u=0; u<dstBounds.w; ++u, ++dst_x) {
                ASSERT(clipBounds.contains(gfx::Point(dst_x, dst_y)));

                int alpha;
                if (antialias) {
                  alpha = *(p++);
                }
                else {
                  alpha = ((*p) & (1 << (7 - (bit++))) ? 255: 0);
                  if (bit == 8) {
                    bit = 0;
                    ++p;
                  }
                }

                uint32_t backdrop = *dst_address;
                gfx::Color backdropColor =
                  gfx::rgba(
                    ((backdrop & fd.redMask) >> fd.redShift),
                    ((backdrop & fd.greenMask) >> fd.greenShift),
                    ((backdrop & fd.blueMask) >> fd.blueShift),
                    ((backdrop & fd.alphaMask) >> fd.alphaShift));

                gfx::Color output = gfx::rgba(gfx::getr(fg),
                                              gfx::getg(fg),
                                              gfx::getb(fg),
                                              MUL_UN8(fg_alpha, alpha, t));
                if (gfx::geta(bg) > 0)
                  output = blend(blend(backdropColor, bg), output);
                else
                  output = blend(backdropColor, output);

                *dst_address =
                  ((gfx::getr(output) << fd.redShift  ) & fd.redMask  ) |
                  ((gfx::getg(output) << fd.greenShift) & fd.greenMask) |
                  ((gfx::getb(output) << fd.blueShift ) & fd.blueMask ) |
                  ((gfx::geta(output) << fd.alphaShift) & fd.alphaMask);

                ++dst_address;
              }
            }
          }

          if (!origDstBounds.w) origDstBounds.w = 1;
          if (!origDstBounds.h) origDstBounds.h = 1;
          textBounds |= origDstBounds;
          if (delegate)
            delegate->postDrawChar(origDstBounds);
        } while (feg.nextChar());
      }

      if (surface)
        surface->unlock();
      break;
    }

  }

  return textBounds;
}

} // namespace os
<commit_msg>Add missing case for kUnknown FontType in draw_text()<commit_after>// LAF OS Library
// Copyright (C) 2017  David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "os/draw_text.h"

#include "ft/algorithm.h"
#include "ft/hb_shaper.h"
#include "gfx/clip.h"
#include "os/common/freetype_font.h"
#include "os/common/generic_surface.h"
#include "os/common/sprite_sheet_font.h"

namespace os {

gfx::Rect draw_text(Surface* surface, Font* font,
                    const base::utf8_const_iterator& begin,
                    const base::utf8_const_iterator& end,
                    gfx::Color fg, gfx::Color bg,
                    int x, int y,
                    DrawTextDelegate* delegate)
{
  base::utf8_const_iterator it = begin;
  gfx::Rect textBounds;

retry:;
  // Check if this font is enough to draw the given string or we will
  // need the fallback for some special Unicode chars
  if (font->fallback()) {
    // TODO compose unicode characters and check those codepoints, the
    //      same in the drawing code of sprite sheet font
    for (auto it=begin; it!=end; ++it) {
      uint32_t code = *it;
      if (code && !font->hasCodePoint(code)) {
        Font* newFont = font->fallback();

        // Search a valid fallback
        while (newFont && !newFont->hasCodePoint(code))
          newFont = newFont->fallback();
        if (!newFont)
          break;

        y += font->height()/2 - newFont->height()/2;

        font = newFont;
        goto retry;
      }
    }
  }

  switch (font->type()) {

    case FontType::kUnknown:
      // Do nothing
      break;

    case FontType::kSpriteSheet: {
      SpriteSheetFont* ssFont = static_cast<SpriteSheetFont*>(font);
      Surface* sheet = ssFont->getSurfaceSheet();

      if (surface) {
        sheet->lock();
        surface->lock();
      }

      while (it != end) {
        int chr = *it;
        if (delegate) {
          int i = it-begin;
          delegate->preProcessChar(i, chr, fg, bg);
        }

        gfx::Rect charBounds = ssFont->getCharBounds(chr);
        gfx::Rect outCharBounds(x, y, charBounds.w, charBounds.h);
        if (delegate && !delegate->preDrawChar(outCharBounds))
          break;

        if (!charBounds.isEmpty()) {
          if (surface)
            surface->drawColoredRgbaSurface(sheet, fg, bg, gfx::Clip(x, y, charBounds));
        }

        textBounds |= outCharBounds;
        if (delegate)
          delegate->postDrawChar(outCharBounds);

        x += charBounds.w;
        ++it;
      }

      if (surface) {
        surface->unlock();
        sheet->unlock();
      }
      break;
    }

    case FontType::kTrueType: {
      FreeTypeFont* ttFont = static_cast<FreeTypeFont*>(font);
      bool antialias = ttFont->face().antialias();
      int fg_alpha = gfx::geta(fg);

      gfx::Rect clipBounds;
      os::SurfaceFormatData fd;
      if (surface) {
        clipBounds = surface->getClipBounds();
        surface->getFormat(&fd);
        surface->lock();
      }

      ft::ForEachGlyph<FreeTypeFont::Face> feg(ttFont->face());
      if (feg.initialize(it, end)) {
        do {
          if (delegate) {
            delegate->preProcessChar(feg.charIndex(),
                                     feg.unicodeChar(), fg, bg);
          }

          auto glyph = feg.glyph();
          if (!glyph)
            continue;

          gfx::Rect origDstBounds(
            x + int(glyph->startX),
            y + int(glyph->y),
            int(glyph->endX) - int(glyph->startX),
            int(glyph->bitmap->rows) ? int(glyph->bitmap->rows): 1);

          if (delegate && !delegate->preDrawChar(origDstBounds))
            break;

          origDstBounds.x = x + int(glyph->x);
          origDstBounds.w = int(glyph->bitmap->width);
          origDstBounds.h = int(glyph->bitmap->rows);

          gfx::Rect dstBounds = origDstBounds;
          if (surface)
            dstBounds &= clipBounds;

          if (surface && !dstBounds.isEmpty()) {
            int clippedRows = dstBounds.y - origDstBounds.y;
            int dst_y = dstBounds.y;
            int t;
            for (int v=0; v<dstBounds.h; ++v, ++dst_y) {
              int bit = 0;
              const uint8_t* p = glyph->bitmap->buffer
                + (v+clippedRows)*glyph->bitmap->pitch;
              int dst_x = dstBounds.x;
              uint32_t* dst_address =
                (uint32_t*)surface->getData(dst_x, dst_y);

              // Skip first clipped pixels
              for (int u=0; u<dstBounds.x-origDstBounds.x; ++u) {
                if (antialias) {
                  ++p;
                }
                else {
                  if (bit == 8) {
                    bit = 0;
                    ++p;
                  }
                }
              }

              for (int u=0; u<dstBounds.w; ++u, ++dst_x) {
                ASSERT(clipBounds.contains(gfx::Point(dst_x, dst_y)));

                int alpha;
                if (antialias) {
                  alpha = *(p++);
                }
                else {
                  alpha = ((*p) & (1 << (7 - (bit++))) ? 255: 0);
                  if (bit == 8) {
                    bit = 0;
                    ++p;
                  }
                }

                uint32_t backdrop = *dst_address;
                gfx::Color backdropColor =
                  gfx::rgba(
                    ((backdrop & fd.redMask) >> fd.redShift),
                    ((backdrop & fd.greenMask) >> fd.greenShift),
                    ((backdrop & fd.blueMask) >> fd.blueShift),
                    ((backdrop & fd.alphaMask) >> fd.alphaShift));

                gfx::Color output = gfx::rgba(gfx::getr(fg),
                                              gfx::getg(fg),
                                              gfx::getb(fg),
                                              MUL_UN8(fg_alpha, alpha, t));
                if (gfx::geta(bg) > 0)
                  output = blend(blend(backdropColor, bg), output);
                else
                  output = blend(backdropColor, output);

                *dst_address =
                  ((gfx::getr(output) << fd.redShift  ) & fd.redMask  ) |
                  ((gfx::getg(output) << fd.greenShift) & fd.greenMask) |
                  ((gfx::getb(output) << fd.blueShift ) & fd.blueMask ) |
                  ((gfx::geta(output) << fd.alphaShift) & fd.alphaMask);

                ++dst_address;
              }
            }
          }

          if (!origDstBounds.w) origDstBounds.w = 1;
          if (!origDstBounds.h) origDstBounds.h = 1;
          textBounds |= origDstBounds;
          if (delegate)
            delegate->postDrawChar(origDstBounds);
        } while (feg.nextChar());
      }

      if (surface)
        surface->unlock();
      break;
    }

  }

  return textBounds;
}

} // namespace os
<|endoftext|>


<commit_before>#include <stdexcept>

#include "python_api.h"

static int python_count=0;

Python::Python()
{
    this->_init(-1, NULL);
}

Python::Python(int argc, char* argv[])
{
    this->_init(argc, argv);
}

void Python::_init(int argc, char* argv[])
{
    python_count++;
    if (python_count == 1) {
        // This is a hack:
        putenv((char *)"PYTHONPATH=../..");
        Py_Initialize();
        if (argc >= 0)
            PySys_SetArgv(argc, argv);
        if (import__hermes_common())
            throw std::runtime_error("hermes_common failed to import.");
    }
    this->_namespace = namespace_create();
}

Python::~Python()
{
    // free the namespace:
    Py_DECREF(this->_namespace);

    // Don't finalize the interpreter, because for some reason,
    // import__hermes_common() doesn't work when called again in the second
    // interpreter (segfaults). So for now we just keep one interpreter and
    // that's it.
    /*
    python_count--;
    if (python_count == 0) {
        Py_Finalize();
    }
    */
}

void Python::print()
{
    namespace_print(_namespace);
}

void Python::exec(const char *text)
{
    run_cmd(text, this->_namespace);
}

void Python::push(const char *name, PyObject *o)
{
    namespace_push(this->_namespace, name, o);
    Py_DECREF(o);
}

PyObject *Python::pull(const char *name)
{
    return namespace_pull(this->_namespace, name);
}
<commit_msg>Free the interpreter automatically<commit_after>#include <stdexcept>

#include "python_api.h"

static int python_count=0;

Python::Python()
{
    this->_init(-1, NULL);
}

Python::Python(int argc, char* argv[])
{
    this->_init(argc, argv);
}

void Python::_init(int argc, char* argv[])
{
    python_count++;
    if (python_count == 1) {
        // This is a hack, so that we can load hermes_common below. Some better
        // mechanism should be used instead, once we figure out how to do it:
        putenv((char *)"PYTHONPATH=../..");
        Py_Initialize();
        if (argc >= 0)
            PySys_SetArgv(argc, argv);
        if (import__hermes_common())
            throw std::runtime_error("hermes_common failed to import.");
    }
    this->_namespace = namespace_create();
}

Python::~Python()
{
    // free the namespace:
    Py_DECREF(this->_namespace);

    // free the interpreter if this was the last instance using it:
    python_count--;
    if (python_count == 0) {
        Py_Finalize();
    }
}

void Python::print()
{
    namespace_print(_namespace);
}

void Python::exec(const char *text)
{
    run_cmd(text, this->_namespace);
}

void Python::push(const char *name, PyObject *o)
{
    namespace_push(this->_namespace, name, o);
    Py_DECREF(o);
}

PyObject *Python::pull(const char *name)
{
    return namespace_pull(this->_namespace, name);
}
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// 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.                                           //
// ======================================================================== //

// own
#include "Importer.h"
// ospcommon
#include "ospcommon/FileName.h"

// scene graph
#include "sg/module/Module.h"
#include "sg/importer/Importer.h"
#include "sg/Renderer.h"

#include <string>

namespace ospray {
  namespace importer {

    void importOSP(const FileName &fileName, Group *existingGroupToAddTo);
    void importRM(const FileName &fileName, Group *existingGroupToAddTo);

    Group *import(const std::string &fn, Group *existingGroupToAddTo)
    {
      FileName fileName = fn;
      Group *group = existingGroupToAddTo;
      if (!group) group = new Group;

      if (fileName.ext() == "osp" || fileName.ext() == "osg") {
          std::shared_ptr<sg::World> world;;
          std::cout << "loading osp file: \n";
          world = sg::loadOSP(fn);
          std::shared_ptr<sg::Volume> volumeNode;
          for (auto node : world->getChildren()) {
            if (node->getType().find("Volume") != std::string::npos)
              volumeNode = std::dynamic_pointer_cast<sg::Volume>(node.get());
          }
          if (!volumeNode) {
            throw std::runtime_error("#ospray:importer: no volume found "
                                     "in osp file");
          }
          sg::RenderContext ctx;
          world->traverse(ctx, "verify");
          std::cout << "scenegraph:\n";
          world->traverse(ctx, "print");
          std::cout << "end scenegraph\n";
          world->traverse(ctx, "commit");

          OSPVolume volume = volumeNode->volume;

          Volume* msgVolume = new Volume;
          msgVolume->bounds = volumeNode->getBounds();
          msgVolume->handle = volumeNode->volume;
          assert(msgVolume->handle);
          msgVolume->voxelRange = volumeNode->getChild("voxelRange")->getValue<vec2f>();
          group->volume.push_back(msgVolume);
      } else if (fileName.ext() == "bob") {
        importRM(fn, group);
      } else {
        throw std::runtime_error("#ospray:importer: do not know how to import file of type "
            + fileName.ext());
      }

      return group;
    }

  } // ::ospray::importer
} // ::ospray
<commit_msg>removing output<commit_after>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// 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.                                           //
// ======================================================================== //

// own
#include "Importer.h"
// ospcommon
#include "ospcommon/FileName.h"

// scene graph
#include "sg/module/Module.h"
#include "sg/importer/Importer.h"
#include "sg/Renderer.h"

#include <string>

namespace ospray {
  namespace importer {

    void importOSP(const FileName &fileName, Group *existingGroupToAddTo);
    void importRM(const FileName &fileName, Group *existingGroupToAddTo);

    Group *import(const std::string &fn, Group *existingGroupToAddTo)
    {
      FileName fileName = fn;
      Group *group = existingGroupToAddTo;
      if (!group) group = new Group;

      if (fileName.ext() == "osp" || fileName.ext() == "osg") {
          std::shared_ptr<sg::World> world;;
          std::cout << "loading osp file: \n";
          world = sg::loadOSP(fn);
          std::shared_ptr<sg::Volume> volumeNode;
          for (auto node : world->getChildren()) {
            if (node->getType().find("Volume") != std::string::npos)
              volumeNode = std::dynamic_pointer_cast<sg::Volume>(node.get());
          }
          if (!volumeNode) {
            throw std::runtime_error("#ospray:importer: no volume found "
                                     "in osp file");
          }
          sg::RenderContext ctx;
          world->traverse(ctx, "verify");
          world->traverse(ctx, "print");
          world->traverse(ctx, "commit");

          OSPVolume volume = volumeNode->volume;

          Volume* msgVolume = new Volume;
          msgVolume->bounds = volumeNode->getBounds();
          msgVolume->handle = volumeNode->volume;
          assert(msgVolume->handle);
          msgVolume->voxelRange = volumeNode->getChild("voxelRange")->getValue<vec2f>();
          group->volume.push_back(msgVolume);
      } else if (fileName.ext() == "bob") {
        importRM(fn, group);
      } else {
        throw std::runtime_error("#ospray:importer: do not know how to import file of type "
            + fileName.ext());
      }

      return group;
    }

  } // ::ospray::importer
} // ::ospray
<|endoftext|>


<commit_before>
#include "canvas.h"
#include "font.h"
#include <draw/path.h>
#include <core/contract.h>

namespace cairo
{

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

canvas::canvas( void )
{
}

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

canvas::~canvas( void )
{
	if ( _context )
		cairo_destroy( _context );
}

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

void canvas::set_surface( cairo_surface_t *surf )
{
	_surface = surf;
	precondition( _surface, "null surface" );

	_context = cairo_create( _surface );
	check_error();

	postcondition( _context, "context could not be created" );
}

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

void canvas::clear_surface( void )
{
	if( _context )
	{
		cairo_surface_finish( _surface );
		cairo_destroy( _context );
		_context = nullptr;
		_surface = nullptr;
		check_error();
	}
}

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

void canvas::fill( const draw::paint &c )
{
	if( !_context )
		return;

	set_cairo( c );
	if ( !set_cairo_fill( c ) )
		set_cairo_stroke( c );
	cairo_paint( _context );
	check_error();
}

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

void canvas::fill( const draw::rect &r, const draw::paint &c )
{
	cairo_rectangle( _context, r.x(), r.y(), r.width(), r.height() );
	if( !_context )
		return;

	set_cairo( c );
	if ( !set_cairo_fill( c ) )
		set_cairo_stroke( c );
	cairo_fill( _context );
	check_error();
}

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

void canvas::draw_path( const draw::path &path, const draw::paint &c )
{
	cairo_save( _context );
	if( !_context )
		return;

	size_t p = 0;
	for ( auto v: path.get_actions() )
	{
		switch ( v )
		{
			case draw::path::action::MOVE:
			{
				auto &p1 = path.get_point( p++ );
				cairo_move_to( _context, p1.x(), p1.y() );
				break;
			}

			case draw::path::action::LINE:
			{
				auto &p1 = path.get_point( p++ );
				cairo_line_to( _context, p1.x(), p1.y() );
				break;
			}

			case draw::path::action::QUADRATIC:
			{
				p += 2;
				throw std::runtime_error( "not yet implemented" );
//				break;
			}

			case draw::path::action::CUBIC:
			{
				auto &p1 = path.get_point( p++ );
				auto &p2 = path.get_point( p++ );
				auto &p3 = path.get_point( p++ );
				cairo_curve_to( _context, p1.x(), p1.y(), p2.x(), p2.y(), p3.x(), p3.y() );
				break;
			}

			case draw::path::action::ARC:
			{
				auto &c = path.get_point( p++ );
				auto &r = path.get_point( p++ );
				auto &a = path.get_point( p++ );
				cairo_arc( _context, c.x(), c.y(), draw::point::distance( c, r ), a.x(), a.y() );
				break;
			}

			case draw::path::action::CLOSE:
			{
				cairo_close_path( _context );
				break;
			}
		}
	}
	postcondition ( p == path.get_points().size(), "too many points?" );

	set_cairo( c );
	if ( set_cairo_fill( c ) )
		cairo_fill_preserve( _context );
	set_cairo_stroke( c );
	cairo_stroke( _context );

	check_error();
	cairo_restore( _context );
}

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

void canvas::draw_text( const std::shared_ptr<draw::font> &font, const draw::point &p, const std::string &utf8, const draw::paint &c )
{
	cairo_save( _context );

	set_cairo_font( font );

	cairo_move_to( _context, p.x(), p.y() );
	cairo_text_path( _context, utf8.c_str() );

	set_cairo( c );
	if ( set_cairo_fill( c ) )
		cairo_fill_preserve( _context );
	set_cairo_stroke( c );
	cairo_stroke( _context );

	check_error();
	cairo_restore( _context );
}

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

void canvas::clip( const draw::rect &r )
{
	cairo_rectangle( _context, r.x(), r.y(), r.width(), r.height() );
	cairo_clip( _context );
}

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

void canvas::translate( double x, double y )
{
	cairo_translate( _context, x, y );
}

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

void canvas::present( void )
{
	if ( !_surface )
		return;

	cairo_surface_flush( _surface );
	check_error();
}

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

void canvas::save( void )
{
	cairo_save( _context );
}

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

void canvas::restore( void )
{
	cairo_restore( _context );
}

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

void canvas::screenshot_png( const char *filename )
{
	if ( !_surface )
		throw std::runtime_error( "missing surface" );

	cairo_surface_write_to_png( _surface, filename );
}

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

void canvas::set_cairo( const draw::paint &p )
{
	cairo_set_antialias( _context, p.has_antialias() ? CAIRO_ANTIALIAS_SUBPIXEL : CAIRO_ANTIALIAS_NONE );
}

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

void canvas::set_cairo_stroke( const draw::paint &p )
{
	const draw::color &c = p.get_stroke_color();
	cairo_set_source_rgba( _context, c.red(), c.green(), c.blue(), c.alpha() );
	cairo_set_line_width( _context, p.get_stroke_width() );
}

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

bool canvas::set_cairo_fill( const draw::paint &p )
{
	if ( p.has_fill_color() )
	{
		const draw::color &c = p.get_fill_color();
		cairo_pattern_t *pat = cairo_pattern_create_rgba( c.red(), c.green(), c.blue(), c.alpha() );
		cairo_set_source( _context, pat );
		cairo_pattern_destroy( pat );
		return true;
	}
	else if ( p.has_fill_linear() )
	{
		const draw::point &p1 = p.get_fill_linear_p1();
		const draw::point &p2 = p.get_fill_linear_p2();
		cairo_pattern_t *pat = cairo_pattern_create_linear( p1.x(), p1.y(), p2.x(), p2.y() );
		for ( auto s: p.get_fill_linear_stops() )
		{
			const draw::color &c = s.second;
			cairo_pattern_add_color_stop_rgba( pat, s.first, c.red(), c.green(), c.blue(), c.alpha() );
		}
		cairo_set_source( _context, pat );
		cairo_pattern_destroy( pat );
		return true;
	}
	else if ( p.has_fill_radial() )
	{
		const draw::point &p1 = p.get_fill_radial_p1();
		const draw::point &p2 = p.get_fill_radial_p2();
		double r1 = p.get_fill_radial_r1();
		double r2 = p.get_fill_radial_r2();

		cairo_pattern_t *pat = cairo_pattern_create_radial( p1.x(), p1.y(), r1, p2.x(), p2.y(), r2 );
		for ( auto s: p.get_fill_radial_stops() )
		{
			const draw::color &c = s.second;
			cairo_pattern_add_color_stop_rgba( pat, s.first, c.red(), c.green(), c.blue(), c.alpha() );
		}
		cairo_set_source( _context, pat );
		cairo_pattern_destroy( pat );
		return true;
	}

	return false;
}

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

void canvas::set_cairo_font( const std::shared_ptr<draw::font> &bfont )
{
	auto *font = dynamic_cast<cairo::font*>( bfont.get() );
	precondition( font, "draw_text with null font" );

	cairo_set_scaled_font( _context, font->cairo_font() );
}

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

void canvas::check_error( void )
{
	if ( _context )
		if ( cairo_status( _context ) )
			throw std::runtime_error( cairo_status_to_string( cairo_status( _context ) ) );
}

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

}
<commit_msg>Fixed negative arcs.<commit_after>
#include "canvas.h"
#include "font.h"
#include <draw/path.h>
#include <core/contract.h>

namespace cairo
{

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

canvas::canvas( void )
{
}

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

canvas::~canvas( void )
{
	if ( _context )
		cairo_destroy( _context );
}

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

void canvas::set_surface( cairo_surface_t *surf )
{
	_surface = surf;
	precondition( _surface, "null surface" );

	_context = cairo_create( _surface );
	check_error();

	postcondition( _context, "context could not be created" );
}

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

void canvas::clear_surface( void )
{
	if( _context )
	{
		cairo_surface_finish( _surface );
		cairo_destroy( _context );
		_context = nullptr;
		_surface = nullptr;
		check_error();
	}
}

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

void canvas::fill( const draw::paint &c )
{
	if( !_context )
		return;

	set_cairo( c );
	if ( !set_cairo_fill( c ) )
		set_cairo_stroke( c );
	cairo_paint( _context );
	check_error();
}

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

void canvas::fill( const draw::rect &r, const draw::paint &c )
{
	cairo_rectangle( _context, r.x(), r.y(), r.width(), r.height() );
	if( !_context )
		return;

	set_cairo( c );
	if ( !set_cairo_fill( c ) )
		set_cairo_stroke( c );
	cairo_fill( _context );
	check_error();
}

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

void canvas::draw_path( const draw::path &path, const draw::paint &c )
{
	cairo_save( _context );
	if( !_context )
		return;

	size_t p = 0;
	for ( auto v: path.get_actions() )
	{
		switch ( v )
		{
			case draw::path::action::MOVE:
			{
				auto &p1 = path.get_point( p++ );
				cairo_move_to( _context, p1.x(), p1.y() );
				break;
			}

			case draw::path::action::LINE:
			{
				auto &p1 = path.get_point( p++ );
				cairo_line_to( _context, p1.x(), p1.y() );
				break;
			}

			case draw::path::action::QUADRATIC:
			{
				p += 2;
				throw std::runtime_error( "not yet implemented" );
//				break;
			}

			case draw::path::action::CUBIC:
			{
				auto &p1 = path.get_point( p++ );
				auto &p2 = path.get_point( p++ );
				auto &p3 = path.get_point( p++ );
				cairo_curve_to( _context, p1.x(), p1.y(), p2.x(), p2.y(), p3.x(), p3.y() );
				break;
			}

			case draw::path::action::ARC:
			{
				auto &c = path.get_point( p++ );
				auto &r = path.get_point( p++ );
				auto &a = path.get_point( p++ );
				if ( a.x() < a.y() )
					cairo_arc( _context, c.x(), c.y(), draw::point::distance( c, r ), a.x(), a.y() );
				else
					cairo_arc_negative( _context, c.x(), c.y(), draw::point::distance( c, r ), a.x(), a.y() );
				break;
			}

			case draw::path::action::CLOSE:
			{
				cairo_close_path( _context );
				break;
			}
		}
	}
	postcondition ( p == path.get_points().size(), "too many points?" );

	set_cairo( c );
	if ( set_cairo_fill( c ) )
		cairo_fill_preserve( _context );
	set_cairo_stroke( c );
	cairo_stroke( _context );

	check_error();
	cairo_restore( _context );
}

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

void canvas::draw_text( const std::shared_ptr<draw::font> &font, const draw::point &p, const std::string &utf8, const draw::paint &c )
{
	cairo_save( _context );

	set_cairo_font( font );

	cairo_move_to( _context, p.x(), p.y() );
	cairo_text_path( _context, utf8.c_str() );

	set_cairo( c );
	if ( set_cairo_fill( c ) )
		cairo_fill_preserve( _context );
	set_cairo_stroke( c );
	cairo_stroke( _context );

	check_error();
	cairo_restore( _context );
}

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

void canvas::clip( const draw::rect &r )
{
	cairo_rectangle( _context, r.x(), r.y(), r.width(), r.height() );
	cairo_clip( _context );
}

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

void canvas::translate( double x, double y )
{
	cairo_translate( _context, x, y );
}

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

void canvas::present( void )
{
	if ( !_surface )
		return;

	cairo_surface_flush( _surface );
	check_error();
}

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

void canvas::save( void )
{
	cairo_save( _context );
}

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

void canvas::restore( void )
{
	cairo_restore( _context );
}

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

void canvas::screenshot_png( const char *filename )
{
	if ( !_surface )
		throw std::runtime_error( "missing surface" );

	cairo_surface_write_to_png( _surface, filename );
}

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

void canvas::set_cairo( const draw::paint &p )
{
	cairo_set_antialias( _context, p.has_antialias() ? CAIRO_ANTIALIAS_SUBPIXEL : CAIRO_ANTIALIAS_NONE );
}

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

void canvas::set_cairo_stroke( const draw::paint &p )
{
	const draw::color &c = p.get_stroke_color();
	cairo_set_source_rgba( _context, c.red(), c.green(), c.blue(), c.alpha() );
	cairo_set_line_width( _context, p.get_stroke_width() );
}

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

bool canvas::set_cairo_fill( const draw::paint &p )
{
	if ( p.has_fill_color() )
	{
		const draw::color &c = p.get_fill_color();
		cairo_pattern_t *pat = cairo_pattern_create_rgba( c.red(), c.green(), c.blue(), c.alpha() );
		cairo_set_source( _context, pat );
		cairo_pattern_destroy( pat );
		return true;
	}
	else if ( p.has_fill_linear() )
	{
		const draw::point &p1 = p.get_fill_linear_p1();
		const draw::point &p2 = p.get_fill_linear_p2();
		cairo_pattern_t *pat = cairo_pattern_create_linear( p1.x(), p1.y(), p2.x(), p2.y() );
		for ( auto s: p.get_fill_linear_stops() )
		{
			const draw::color &c = s.second;
			cairo_pattern_add_color_stop_rgba( pat, s.first, c.red(), c.green(), c.blue(), c.alpha() );
		}
		cairo_set_source( _context, pat );
		cairo_pattern_destroy( pat );
		return true;
	}
	else if ( p.has_fill_radial() )
	{
		const draw::point &p1 = p.get_fill_radial_p1();
		const draw::point &p2 = p.get_fill_radial_p2();
		double r1 = p.get_fill_radial_r1();
		double r2 = p.get_fill_radial_r2();

		cairo_pattern_t *pat = cairo_pattern_create_radial( p1.x(), p1.y(), r1, p2.x(), p2.y(), r2 );
		for ( auto s: p.get_fill_radial_stops() )
		{
			const draw::color &c = s.second;
			cairo_pattern_add_color_stop_rgba( pat, s.first, c.red(), c.green(), c.blue(), c.alpha() );
		}
		cairo_set_source( _context, pat );
		cairo_pattern_destroy( pat );
		return true;
	}

	return false;
}

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

void canvas::set_cairo_font( const std::shared_ptr<draw::font> &bfont )
{
	auto *font = dynamic_cast<cairo::font*>( bfont.get() );
	precondition( font, "draw_text with null font" );

	cairo_set_scaled_font( _context, font->cairo_font() );
}

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

void canvas::check_error( void )
{
	if ( _context )
		if ( cairo_status( _context ) )
			throw std::runtime_error( cairo_status_to_string( cairo_status( _context ) ) );
}

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

}
<|endoftext|>


<commit_before>#include "umundo/core.h"
#include <iostream>

using namespace umundo;

bool testRecursiveMutex() {
	Mutex mutex;
	UMUNDO_LOCK(mutex);
	if(!mutex.tryLock()) {
		LOG_ERR("tryLock should be possible from within the same thread");
		assert(false);
	}
	UMUNDO_LOCK(mutex);
	// can we unlock it as well?
	UMUNDO_UNLOCK(mutex);
	UMUNDO_UNLOCK(mutex);
	return true;
}

static Mutex testMutex;
bool testThreads() {
	class Thread1 : public Thread {
		void run() {
			if(testMutex.tryLock()) {
				LOG_ERR("tryLock should return false with a mutex locked in another thread");
				assert(false);
			}
			UMUNDO_LOCK(testMutex); // blocks
			Thread::sleepMs(50);
			UMUNDO_UNLOCK(testMutex);
			Thread::sleepMs(100);
		}
	};

	/**
	 * tl=tryLock, l=lock, u=unlock b=block, sN=sleep(N)
	 * thread1:        start tl l  l s50      u
	 *    main: start l s50       u s20  tl    l join
	 *    t->          0         50     70   100
	 */

	UMUNDO_LOCK(testMutex);
	Thread1 thread1;
	thread1.start();
	Thread::sleepMs(50); // thread1 will trylock and block on lock
	UMUNDO_UNLOCK(testMutex);  // unlock
	Thread::sleepMs(20); // yield cpu and sleep
	// thread1 sleeps with lock on mutex
	if(testMutex.tryLock()) {
		LOG_ERR("tryLock should return false with a mutex locked in another thread");
		assert(false);
	}
	UMUNDO_LOCK(testMutex);    // thread1 will unlock and sleep
	thread1.join();      // join with thread1
	if(thread1.isStarted()) {
		LOG_ERR("thread still running after join");
		assert(false);
	}
	return true;
}

static Monitor testMonitor;
static int passedMonitor = 0;
bool testMonitors() {
	struct TestThread : public Thread {
		int _ms;
		TestThread(int ms) : _ms(ms) {}
		void run() {
			testMonitor.wait();
			Thread::sleepMs(10); // avoid clash with other threads
			passedMonitor++;
		}
	};

	TestThread thread1(0);
	TestThread thread2(5);
	TestThread thread3(10);

	for (int i = 0; i < 10; i++) {
		passedMonitor = 0;

		// all will block on monitor
		thread1.start();
		thread2.start();
		thread3.start();
		Thread::sleepMs(5); // give threads a chance to run into wait
		if(passedMonitor != 0) {
			LOG_ERR("%d threads already passed the monitor", passedMonitor);
			assert(false);
		}
		UMUNDO_SIGNAL(testMonitor); // signal a single thread
		Thread::sleepMs(15); // thread will increase passedMonitor
		if(passedMonitor != 1) {
			LOG_ERR("Expected 1 threads to pass the monitor, but %d did", passedMonitor);
			assert(false);
		}
		UMUNDO_BROADCAST(testMonitor); // signal all other threads
		Thread::sleepMs(15);

		if (thread1.isStarted() || thread2.isStarted() || thread3.isStarted()) {
			LOG_ERR("Threads ran to completion but still insist on being started");
			assert(false);
		}
	}
	return true;
}

static Monitor testTimedMonitor;
static int passedTimedMonitor = 0;
bool testTimedMonitors() {
	struct TestThread : public Thread {
		int _ms;
		TestThread(int ms) : _ms(ms) {}
		void run() {
			testTimedMonitor.wait(_ms);
			passedTimedMonitor++;
		}
	};

	TestThread thread1(40);
	TestThread thread2(0); // waits forever
	TestThread thread3(0); // waits forever
	TestThread thread4(0); // waits forever
	TestThread thread5(0); // waits forever

	for (int i = 0; i < 10; i++) {
		// test waiting for a given time
		passedTimedMonitor = 0;
		thread1.start(); // wait for 15ms at mutex before resuming
		Thread::sleepMs(10);
		assert(passedTimedMonitor == 0); // thread1 should not have passed
		Thread::sleepMs(60);
		assert(passedTimedMonitor == 1); // thread1 should have passed
		assert(!thread1.isStarted());

		// test signalling a set of threads
		passedTimedMonitor = 0;
		thread2.start();
		thread3.start();
		thread4.start();
		thread5.start();
		Thread::sleepMs(5);
		testTimedMonitor.signal(2); // signal 2 threads
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 2);
		testTimedMonitor.signal(1); // signal another thread
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 3);
		testTimedMonitor.broadcast(); // signal last thread
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 4);
		assert(!thread2.isStarted() && !thread3.isStarted() && !thread4.isStarted() && !thread5.isStarted());

		// test timed and unlimited waiting
		passedTimedMonitor = 0;
		thread1.start();
		thread2.start(); // with another thread
		thread3.start(); // with another thread
		Thread::sleepMs(5);
		testTimedMonitor.signal(); // explicit signal
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 1);
		// wo do not know which thread passed
		assert(!thread1.isStarted() || !thread2.isStarted() || !thread3.isStarted());
		if (thread1.isStarted()) {
			// thread1 is still running, just wait
			Thread::sleepMs(60);
			assert(passedTimedMonitor == 2);
		}
		testTimedMonitor.broadcast(); // explicit signal
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 3);
		assert(!thread1.isStarted() && !thread2.isStarted() && !thread3.isStarted());

		// test signalling prior to waiting
		passedTimedMonitor = 0;
		testTimedMonitor.signal();
		thread1.start();
		Thread::sleepMs(10);
		thread2.start();
		Thread::sleepMs(10);
		assert(passedTimedMonitor == 1);
		assert(!thread1.isStarted());
		assert(thread2.isStarted());
		testTimedMonitor.signal();
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 2);

		assert(!thread1.isStarted());
		assert(!thread2.isStarted());
		assert(!thread3.isStarted());

	}
	return true;
}

class FooTracer : public Traceable, public Thread {
	void run() {
		while(isStarted()) {
			trace("This is foo");
			Thread::sleepMs(20);
		}
	}

  void retrace(const std::string& msg, std::map<std::string, std::string> info) {
  };

};

bool testTracing() {
	FooTracer* tr1 = new FooTracer();
	FooTracer* tr2 = new FooTracer();
	FooTracer* tr3 = new FooTracer();

	tr1->setTraceFile("trace.txt");
	tr2->setTraceFile("trace.txt");
	tr3->setTraceFile("trace.txt");

	tr1->start();
	tr2->start();
	tr3->start();

	Thread::sleepMs(100);
	delete tr1;
	delete tr2;
	delete tr3;

  Thread::sleepMs(100);

  FooTracer* tr4 = new FooTracer();
  tr4->replay("trace.txt");

	return true;
}

int main(int argc, char** argv) {
	if(!testTracing())
		return EXIT_FAILURE;
	if(!testRecursiveMutex())
		return EXIT_FAILURE;
	if(!testThreads())
		return EXIT_FAILURE;
	if(!testMonitors())
		return EXIT_FAILURE;
	if(!testTimedMonitors())
		return EXIT_FAILURE;
}
<commit_msg>adapted timeouts once more<commit_after>#include "umundo/core.h"
#include <iostream>

using namespace umundo;

bool testRecursiveMutex() {
	Mutex mutex;
	UMUNDO_LOCK(mutex);
	if(!mutex.tryLock()) {
		LOG_ERR("tryLock should be possible from within the same thread");
		assert(false);
	}
	UMUNDO_LOCK(mutex);
	// can we unlock it as well?
	UMUNDO_UNLOCK(mutex);
	UMUNDO_UNLOCK(mutex);
	return true;
}

static Mutex testMutex;
bool testThreads() {
	class Thread1 : public Thread {
		void run() {
			if(testMutex.tryLock()) {
				LOG_ERR("tryLock should return false with a mutex locked in another thread");
				assert(false);
			}
			UMUNDO_LOCK(testMutex); // blocks
			Thread::sleepMs(50);
			UMUNDO_UNLOCK(testMutex);
			Thread::sleepMs(100);
		}
	};

	/**
	 * tl=tryLock, l=lock, u=unlock b=block, sN=sleep(N)
	 * thread1:        start tl l  l s50      u
	 *    main: start l s50       u s20  tl    l join
	 *    t->          0         50     70   100
	 */

	UMUNDO_LOCK(testMutex);
	Thread1 thread1;
	thread1.start();
	Thread::sleepMs(50); // thread1 will trylock and block on lock
	UMUNDO_UNLOCK(testMutex);  // unlock
	Thread::sleepMs(20); // yield cpu and sleep
	// thread1 sleeps with lock on mutex
	if(testMutex.tryLock()) {
		LOG_ERR("tryLock should return false with a mutex locked in another thread");
		assert(false);
	}
	UMUNDO_LOCK(testMutex);    // thread1 will unlock and sleep
	thread1.join();      // join with thread1
	if(thread1.isStarted()) {
		LOG_ERR("thread still running after join");
		assert(false);
	}
	return true;
}

static Monitor testMonitor;
static int passedMonitor = 0;
bool testMonitors() {
	struct TestThread : public Thread {
		int _ms;
		TestThread(int ms) : _ms(ms) {}
		void run() {
			testMonitor.wait();
			Thread::sleepMs(10); // avoid clash with other threads
			passedMonitor++;
		}
	};

	TestThread thread1(0);
	TestThread thread2(5);
	TestThread thread3(10);

	for (int i = 0; i < 10; i++) {
		passedMonitor = 0;

		// all will block on monitor
		thread1.start();
		thread2.start();
		thread3.start();
		Thread::sleepMs(5); // give threads a chance to run into wait
		if(passedMonitor != 0) {
			LOG_ERR("%d threads already passed the monitor", passedMonitor);
			assert(false);
		}
		UMUNDO_SIGNAL(testMonitor); // signal a single thread
		Thread::sleepMs(15); // thread will increase passedMonitor
		if(passedMonitor != 1) {
			LOG_ERR("Expected 1 threads to pass the monitor, but %d did", passedMonitor);
			assert(false);
		}
		UMUNDO_BROADCAST(testMonitor); // signal all other threads
		Thread::sleepMs(40);

		if (thread1.isStarted() || thread2.isStarted() || thread3.isStarted()) {
			LOG_ERR("Threads ran to completion but still insist on being started");
			assert(false);
		}
	}
	return true;
}

static Monitor testTimedMonitor;
static int passedTimedMonitor = 0;
bool testTimedMonitors() {
	struct TestThread : public Thread {
		int _ms;
		TestThread(int ms) : _ms(ms) {}
		void run() {
			testTimedMonitor.wait(_ms);
			passedTimedMonitor++;
		}
	};

	TestThread thread1(40);
	TestThread thread2(0); // waits forever
	TestThread thread3(0); // waits forever
	TestThread thread4(0); // waits forever
	TestThread thread5(0); // waits forever

	for (int i = 0; i < 10; i++) {
		// test waiting for a given time
		passedTimedMonitor = 0;
		thread1.start(); // wait for 15ms at mutex before resuming
		Thread::sleepMs(10);
		assert(passedTimedMonitor == 0); // thread1 should not have passed
		Thread::sleepMs(60);
		assert(passedTimedMonitor == 1); // thread1 should have passed
		assert(!thread1.isStarted());

		// test signalling a set of threads
		passedTimedMonitor = 0;
		thread2.start();
		thread3.start();
		thread4.start();
		thread5.start();
		Thread::sleepMs(5);
		testTimedMonitor.signal(2); // signal 2 threads
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 2);
		testTimedMonitor.signal(1); // signal another thread
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 3);
		testTimedMonitor.broadcast(); // signal last thread
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 4);
		assert(!thread2.isStarted() && !thread3.isStarted() && !thread4.isStarted() && !thread5.isStarted());

		// test timed and unlimited waiting
		passedTimedMonitor = 0;
		thread1.start();
		thread2.start(); // with another thread
		thread3.start(); // with another thread
		Thread::sleepMs(5);
		testTimedMonitor.signal(); // explicit signal
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 1);
		// wo do not know which thread passed
		assert(!thread1.isStarted() || !thread2.isStarted() || !thread3.isStarted());
		if (thread1.isStarted()) {
			// thread1 is still running, just wait
			Thread::sleepMs(60);
			assert(passedTimedMonitor == 2);
		}
		testTimedMonitor.broadcast(); // explicit signal
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 3);
		assert(!thread1.isStarted() && !thread2.isStarted() && !thread3.isStarted());

		// test signalling prior to waiting
		passedTimedMonitor = 0;
		testTimedMonitor.signal();
		thread1.start();
		Thread::sleepMs(10);
		thread2.start();
		Thread::sleepMs(10);
		assert(passedTimedMonitor == 1);
		assert(!thread1.isStarted());
		assert(thread2.isStarted());
		testTimedMonitor.signal();
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 2);

		assert(!thread1.isStarted());
		assert(!thread2.isStarted());
		assert(!thread3.isStarted());

	}
	return true;
}

class FooTracer : public Traceable, public Thread {
	void run() {
		while(isStarted()) {
			trace("This is foo");
			Thread::sleepMs(20);
		}
	}

  void retrace(const std::string& msg, std::map<std::string, std::string> info) {
  };

};

bool testTracing() {
	FooTracer* tr1 = new FooTracer();
	FooTracer* tr2 = new FooTracer();
	FooTracer* tr3 = new FooTracer();

	tr1->setTraceFile("trace.txt");
	tr2->setTraceFile("trace.txt");
	tr3->setTraceFile("trace.txt");

	tr1->start();
	tr2->start();
	tr3->start();

	Thread::sleepMs(100);
	delete tr1;
	delete tr2;
	delete tr3;

  Thread::sleepMs(100);

  FooTracer* tr4 = new FooTracer();
  tr4->replay("trace.txt");

	return true;
}

int main(int argc, char** argv) {
	if(!testTracing())
		return EXIT_FAILURE;
	if(!testRecursiveMutex())
		return EXIT_FAILURE;
	if(!testThreads())
		return EXIT_FAILURE;
	if(!testMonitors())
		return EXIT_FAILURE;
	if(!testTimedMonitors())
		return EXIT_FAILURE;
}
<|endoftext|>