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

  Program:   Monteverdi2
  Language:  C++

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See Copyright.txt for details.

  Monteverdi2 is distributed under the CeCILL licence version 2. See
  Licence_CeCILL_V2-en.txt or
  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt for more 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 notices for more information.

=========================================================================*/
#include "Gui/mvdHistogramWidget.h"
#include "Gui/ui_mvdHistogramWidget.h"

/*****************************************************************************/
/* INCLUDE SECTION                                                           */

//
// Qt includes (sorted by alphabetic order)
//// Must be included before system/custom includes.

//
// Qwt includes
#include <qwt_plot_curve.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_marker.h>
#include <qwt_scale_engine.h>

//
// System includes (sorted by alphabetic order)

//
// ITK includes (sorted by alphabetic order)

//
// OTB includes (sorted by alphabetic order)

//
// Monteverdi includes (sorted by alphabetic order)

namespace mvd
{

/*
  TRANSLATOR mvd::HistogramWidget

  Necessary for lupdate to be aware of C++ namespaces.

  Context comment for translator.
*/

/*****************************************************************************/
/* CONSTANTS                                                                 */

/**
 * \brief Array of enhanced band names that OTB can return.
 *
 * It is defined (statically) as a constant for translation purposes.
 */
const char*
HistogramWidget::CURVE_NAMES[ HistogramWidget::CURVE_COUNT ] =
{
  QT_TRANSLATE_NOOP( "mvd::HistogramWidget", "Red" ),
  QT_TRANSLATE_NOOP( "mvd::HistogramWidget", "Green" ),
  QT_TRANSLATE_NOOP( "mvd::HistogramWidget", "Blue" ),
};

const QColor
HistogramWidget::CURVE_COLORS[ HistogramWidget::CURVE_COUNT ] =
{
  QColor( 0xFF, 0x44, 0x44/*, 0x88*/ ),
  QColor( 0x44, 0xFF, 0x44/*, 0x88*/ ),
  QColor( 0x44, 0x44, 0xFF/*, 0x88*/ )
};

const QColor
HistogramWidget::MARKER_COLORS[ HistogramWidget::CURVE_COUNT ] =
{
  QColor( 0xFF, 0x77, 0x77/*, 0x00*/ ),
  QColor( 0x77, 0xFF, 0x77/*, 0x77*/ ),
  QColor( 0x77, 0x77, 0xFF/*, 0x00*/ )
};

namespace
{
const QColor CANVAS_BACKGROUND( 0x33, 0x33, 0x33 );
const QColor GRID_MAJ_PEN_COLOR( 0x88, 0x88, 0x88 );
const QColor GRID_MIN_PEN_COLOR( 0x66, 0x66, 0x66 );
}

/*****************************************************************************/
/* STATIC IMPLEMENTATION SECTION                                             */

/*****************************************************************************/
/* CLASS IMPLEMENTATION SECTION                                              */

/*******************************************************************************/
HistogramWidget
::HistogramWidget( QWidget* parent, Qt::WindowFlags flags  ):
  QWidget( parent, flags ),
  m_UI( new mvd::Ui::HistogramWidget() ),
  m_PlotGrid( NULL ),
  m_PlotCurves(),
  m_Bounds()
{
  m_UI->setupUi( this );

  m_UI->histogramPlot->setCanvasBackground( CANVAS_BACKGROUND  );

  m_PlotGrid = new QwtPlotGrid();
  m_PlotGrid->attach( m_UI->histogramPlot );

  m_PlotGrid->setMajPen( GRID_MAJ_PEN_COLOR );
  m_PlotGrid->setMinPen( GRID_MIN_PEN_COLOR );

  for( CountType i=0; i<HistogramWidget::CURVE_COUNT; ++i )
    {
    //
    // Curve
    m_PlotCurves[ i ] =
      new QwtPlotCurve( tr( HistogramWidget::CURVE_NAMES[ i ] ) );

#if HISTOGRAM_CURVE_TYPE==0

#elif HISTOGRAM_CURVE_TYPE==1
    m_PlotCurves[ i ]->setStyle( QwtPlotCurve::Steps );

#elif HISTOGRAM_CURVE_TYPE==2

#else
#endif

    m_PlotCurves[ i ]->setPen( QPen( CURVE_COLORS[ i ] ) );

    m_PlotCurves[ i ]->attach( m_UI->histogramPlot );

    //
    // Markers

    m_LowPlotMarkers[ i ] = new QwtPlotMarker();
    m_LowPlotMarkers[ i ]->setLineStyle( QwtPlotMarker::VLine );
    m_LowPlotMarkers[ i ]->setLinePen(
      QPen( HistogramWidget::MARKER_COLORS[ i ] )
    );
    m_LowPlotMarkers[ i ]->attach( m_UI->histogramPlot );

    m_HighPlotMarkers[ i ] = new QwtPlotMarker();
    m_HighPlotMarkers[ i ]->setLineStyle( QwtPlotMarker::VLine );
    m_HighPlotMarkers[ i ]->setLinePen(
      QPen( HistogramWidget::MARKER_COLORS[ i ] )
    );
    m_HighPlotMarkers[ i ]->attach( m_UI->histogramPlot );
    }
}

/*******************************************************************************/
HistogramWidget
::~HistogramWidget()
{
  for( CountType i=0; i<HistogramWidget::CURVE_COUNT; ++i )
    {
    delete m_PlotCurves[ i ];
    m_PlotCurves[ i ] = NULL;

    delete m_LowPlotMarkers[ i ];
    m_LowPlotMarkers[ i ] = NULL;

    delete m_HighPlotMarkers[ i ];
    m_HighPlotMarkers[ i ] = NULL;
    }

  delete m_PlotGrid;
  m_PlotGrid = NULL;

  delete m_UI;
  m_UI = NULL;
}

/*******************************************************************************/
void
HistogramWidget
::SetBounds( RgbwChannel channel,
	     double xMin, double xMax,
	     double yMin, double yMax )
{
  CountType begin = 0;
  CountType end = 0;

  if( !RgbBounds( begin, end, channel ) )
    return;

  for( CountType i=begin; i<end; ++i )
    {
    m_Bounds[ i ].m_XMin = xMin;
    m_Bounds[ i ].m_XMax = xMax;

    m_Bounds[ i ].m_YMin = yMin;
    m_Bounds[ i ].m_YMax = yMax;
    }

  RefreshScale();
}

/*******************************************************************************/
void
HistogramWidget
::SetData( RgbwChannel channel,
	   double * const x, double * const y, size_t size,
	   double xMin, double yMin,
	   double xMax, double yMax )
{
  assert( x!=NULL );
  assert( y!=NULL );

  CountType begin = 0;
  CountType end = 0;

  if( !RgbBounds( begin, end, channel ) )
    return;

  for( CountType i=begin; i<end; ++i )
    {
    assert( i<HistogramWidget::CURVE_COUNT );
    assert( m_PlotCurves[ i ]!=NULL );

    m_PlotCurves[ i ]->setData( x, y, size );

    qDebug()
      << RGBW_CHANNEL_NAMES[ i ]
      << "[" << xMin << "; " << xMax << "]"
      << "x [" << yMin << "; " << yMax << "]";

    m_Bounds[ i ].m_XMin = xMin;
    m_Bounds[ i ].m_XMax = xMax;

    m_Bounds[ i ].m_YMin = yMin;
    m_Bounds[ i ].m_YMax = yMax;
    }
}

/*******************************************************************************/
void
HistogramWidget
::SetLowMarker( RgbwChannel channel,
		double low )
{
  qDebug()
    << this << "::SetLowMarker("
    << RGBW_CHANNEL_NAMES[ channel ] << ", " << low << ")";

  CountType begin = 0;
  CountType end = 0;

  if( !RgbBounds( begin, end, channel ) )
    return;

  for( CountType i=begin; i<end; ++i )
    {
    m_LowPlotMarkers[ i ]->setXValue( low );
    }
}

/*******************************************************************************/
void
HistogramWidget
::SetHighMarker( RgbwChannel channel,
		double high )
{
  qDebug()
    << this << "::SetLowMarker("
    << RGBW_CHANNEL_NAMES[ channel ] << ", " << high << ")";

  CountType begin = 0;
  CountType end = 0;

  if( !RgbBounds( begin, end, channel ) )
    return;

  for( CountType i=begin; i<end; ++i )
    {
    m_HighPlotMarkers[ i ]->setXValue( high );
    }
}

/*******************************************************************************/
void
HistogramWidget
::Replot()
{
  RefreshScale();

  m_UI->histogramPlot->replot();
}

/*******************************************************************************/
void
HistogramWidget
::RefreshScale()
{
  assert( std::numeric_limits< double >::has_infinity );

  double xMin = +std::numeric_limits< double >::infinity();
  double xMax = -std::numeric_limits< double >::infinity();

  double yMin = +std::numeric_limits< double >::infinity();
  double yMax = -std::numeric_limits< double >::infinity();

  CountType begin = 0;
  CountType end = 0;

  if( !RgbBounds( begin, end, RGBW_CHANNEL_RGB ) )
    return;

  for( CountType i=begin; i<end; ++i )
    {
    if( m_Bounds[ i ].m_XMin<xMin )
      xMin = m_Bounds[ i ].m_XMin;

    if( m_Bounds[ i ].m_XMax>xMax )
      xMax = m_Bounds[ i ].m_XMax;

    if( m_Bounds[ i ].m_YMin<yMin )
      yMin = m_Bounds[ i ].m_YMin;

    if( m_Bounds[ i ].m_YMax>yMax )
      yMax = m_Bounds[ i ].m_YMax;
    }

  qDebug()
    << "[" << xMin << "; " << xMax << "]"
    << "x [" << yMin << "; " << yMax << "]";

  m_UI->histogramPlot
    ->axisScaleDiv( QwtPlot::xBottom )
    ->setInterval( xMin, xMax );

  m_UI->histogramPlot
    ->axisScaleDiv( QwtPlot::yLeft )
    ->setInterval( yMin, yMax );
}

/*******************************************************************************/
/* SLOTS                                                                       */
/*******************************************************************************/

} // end namespace 'mvd'
<commit_msg>ENH: Changed histogram colors.<commit_after>/*=========================================================================

  Program:   Monteverdi2
  Language:  C++

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See Copyright.txt for details.

  Monteverdi2 is distributed under the CeCILL licence version 2. See
  Licence_CeCILL_V2-en.txt or
  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt for more 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 notices for more information.

=========================================================================*/
#include "Gui/mvdHistogramWidget.h"
#include "Gui/ui_mvdHistogramWidget.h"

/*****************************************************************************/
/* INCLUDE SECTION                                                           */

//
// Qt includes (sorted by alphabetic order)
//// Must be included before system/custom includes.

//
// Qwt includes
#include <qwt_plot_curve.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_marker.h>
#include <qwt_scale_engine.h>

//
// System includes (sorted by alphabetic order)

//
// ITK includes (sorted by alphabetic order)

//
// OTB includes (sorted by alphabetic order)

//
// Monteverdi includes (sorted by alphabetic order)

namespace mvd
{

/*
  TRANSLATOR mvd::HistogramWidget

  Necessary for lupdate to be aware of C++ namespaces.

  Context comment for translator.
*/

/*****************************************************************************/
/* CONSTANTS                                                                 */

/**
 * \brief Array of enhanced band names that OTB can return.
 *
 * It is defined (statically) as a constant for translation purposes.
 */
const char*
HistogramWidget::CURVE_NAMES[ HistogramWidget::CURVE_COUNT ] =
{
  QT_TRANSLATE_NOOP( "mvd::HistogramWidget", "Red" ),
  QT_TRANSLATE_NOOP( "mvd::HistogramWidget", "Green" ),
  QT_TRANSLATE_NOOP( "mvd::HistogramWidget", "Blue" ),
};

const QColor
HistogramWidget::CURVE_COLORS[ HistogramWidget::CURVE_COUNT ] =
{
  QColor( 0xFF, 0x44, 0x44/*, 0x88*/ ),
  QColor( 0x44, 0xFF, 0x44/*, 0x88*/ ),
  QColor( 0x44, 0x44, 0xFF/*, 0x88*/ )
};

const QColor
HistogramWidget::MARKER_COLORS[ HistogramWidget::CURVE_COUNT ] =
{
  QColor( 0xFF, 0x77, 0x77/*, 0x00*/ ),
  QColor( 0x77, 0xFF, 0x77/*, 0x77*/ ),
  QColor( 0x77, 0x77, 0xFF/*, 0x00*/ )
};

namespace
{
const QColor CANVAS_BACKGROUND( 0x33, 0x33, 0x33 );
const QColor GRID_MAJ_PEN_COLOR( 0x66, 0x66, 0x66 );
const QColor GRID_MIN_PEN_COLOR( 0x44, 0x44, 0x44 );
}

/*****************************************************************************/
/* STATIC IMPLEMENTATION SECTION                                             */

/*****************************************************************************/
/* CLASS IMPLEMENTATION SECTION                                              */

/*******************************************************************************/
HistogramWidget
::HistogramWidget( QWidget* parent, Qt::WindowFlags flags  ):
  QWidget( parent, flags ),
  m_UI( new mvd::Ui::HistogramWidget() ),
  m_PlotGrid( NULL ),
  m_PlotCurves(),
  m_Bounds()
{
  m_UI->setupUi( this );

  m_UI->histogramPlot->setCanvasBackground( CANVAS_BACKGROUND  );

  m_PlotGrid = new QwtPlotGrid();
  m_PlotGrid->attach( m_UI->histogramPlot );

  m_PlotGrid->setMajPen( GRID_MAJ_PEN_COLOR );
  m_PlotGrid->setMinPen( GRID_MIN_PEN_COLOR );

  for( CountType i=0; i<HistogramWidget::CURVE_COUNT; ++i )
    {
    //
    // Curve
    m_PlotCurves[ i ] =
      new QwtPlotCurve( tr( HistogramWidget::CURVE_NAMES[ i ] ) );

#if HISTOGRAM_CURVE_TYPE==0

#elif HISTOGRAM_CURVE_TYPE==1
    m_PlotCurves[ i ]->setStyle( QwtPlotCurve::Steps );

#elif HISTOGRAM_CURVE_TYPE==2

#else
#endif

    m_PlotCurves[ i ]->setPen( QPen( CURVE_COLORS[ i ] ) );

    m_PlotCurves[ i ]->attach( m_UI->histogramPlot );

    //
    // Markers

    m_LowPlotMarkers[ i ] = new QwtPlotMarker();
    m_LowPlotMarkers[ i ]->setLineStyle( QwtPlotMarker::VLine );
    m_LowPlotMarkers[ i ]->setLinePen(
      QPen( HistogramWidget::MARKER_COLORS[ i ] )
    );
    m_LowPlotMarkers[ i ]->attach( m_UI->histogramPlot );

    m_HighPlotMarkers[ i ] = new QwtPlotMarker();
    m_HighPlotMarkers[ i ]->setLineStyle( QwtPlotMarker::VLine );
    m_HighPlotMarkers[ i ]->setLinePen(
      QPen( HistogramWidget::MARKER_COLORS[ i ] )
    );
    m_HighPlotMarkers[ i ]->attach( m_UI->histogramPlot );
    }
}

/*******************************************************************************/
HistogramWidget
::~HistogramWidget()
{
  for( CountType i=0; i<HistogramWidget::CURVE_COUNT; ++i )
    {
    delete m_PlotCurves[ i ];
    m_PlotCurves[ i ] = NULL;

    delete m_LowPlotMarkers[ i ];
    m_LowPlotMarkers[ i ] = NULL;

    delete m_HighPlotMarkers[ i ];
    m_HighPlotMarkers[ i ] = NULL;
    }

  delete m_PlotGrid;
  m_PlotGrid = NULL;

  delete m_UI;
  m_UI = NULL;
}

/*******************************************************************************/
void
HistogramWidget
::SetBounds( RgbwChannel channel,
	     double xMin, double xMax,
	     double yMin, double yMax )
{
  CountType begin = 0;
  CountType end = 0;

  if( !RgbBounds( begin, end, channel ) )
    return;

  for( CountType i=begin; i<end; ++i )
    {
    m_Bounds[ i ].m_XMin = xMin;
    m_Bounds[ i ].m_XMax = xMax;

    m_Bounds[ i ].m_YMin = yMin;
    m_Bounds[ i ].m_YMax = yMax;
    }

  RefreshScale();
}

/*******************************************************************************/
void
HistogramWidget
::SetData( RgbwChannel channel,
	   double * const x, double * const y, size_t size,
	   double xMin, double yMin,
	   double xMax, double yMax )
{
  assert( x!=NULL );
  assert( y!=NULL );

  CountType begin = 0;
  CountType end = 0;

  if( !RgbBounds( begin, end, channel ) )
    return;

  for( CountType i=begin; i<end; ++i )
    {
    assert( i<HistogramWidget::CURVE_COUNT );
    assert( m_PlotCurves[ i ]!=NULL );

    m_PlotCurves[ i ]->setData( x, y, size );

    qDebug()
      << RGBW_CHANNEL_NAMES[ i ]
      << "[" << xMin << "; " << xMax << "]"
      << "x [" << yMin << "; " << yMax << "]";

    m_Bounds[ i ].m_XMin = xMin;
    m_Bounds[ i ].m_XMax = xMax;

    m_Bounds[ i ].m_YMin = yMin;
    m_Bounds[ i ].m_YMax = yMax;
    }
}

/*******************************************************************************/
void
HistogramWidget
::SetLowMarker( RgbwChannel channel,
		double low )
{
  qDebug()
    << this << "::SetLowMarker("
    << RGBW_CHANNEL_NAMES[ channel ] << ", " << low << ")";

  CountType begin = 0;
  CountType end = 0;

  if( !RgbBounds( begin, end, channel ) )
    return;

  for( CountType i=begin; i<end; ++i )
    {
    m_LowPlotMarkers[ i ]->setXValue( low );
    }
}

/*******************************************************************************/
void
HistogramWidget
::SetHighMarker( RgbwChannel channel,
		double high )
{
  qDebug()
    << this << "::SetLowMarker("
    << RGBW_CHANNEL_NAMES[ channel ] << ", " << high << ")";

  CountType begin = 0;
  CountType end = 0;

  if( !RgbBounds( begin, end, channel ) )
    return;

  for( CountType i=begin; i<end; ++i )
    {
    m_HighPlotMarkers[ i ]->setXValue( high );
    }
}

/*******************************************************************************/
void
HistogramWidget
::Replot()
{
  RefreshScale();

  m_UI->histogramPlot->replot();
}

/*******************************************************************************/
void
HistogramWidget
::RefreshScale()
{
  assert( std::numeric_limits< double >::has_infinity );

  double xMin = +std::numeric_limits< double >::infinity();
  double xMax = -std::numeric_limits< double >::infinity();

  double yMin = +std::numeric_limits< double >::infinity();
  double yMax = -std::numeric_limits< double >::infinity();

  CountType begin = 0;
  CountType end = 0;

  if( !RgbBounds( begin, end, RGBW_CHANNEL_RGB ) )
    return;

  for( CountType i=begin; i<end; ++i )
    {
    if( m_Bounds[ i ].m_XMin<xMin )
      xMin = m_Bounds[ i ].m_XMin;

    if( m_Bounds[ i ].m_XMax>xMax )
      xMax = m_Bounds[ i ].m_XMax;

    if( m_Bounds[ i ].m_YMin<yMin )
      yMin = m_Bounds[ i ].m_YMin;

    if( m_Bounds[ i ].m_YMax>yMax )
      yMax = m_Bounds[ i ].m_YMax;
    }

  qDebug()
    << "[" << xMin << "; " << xMax << "]"
    << "x [" << yMin << "; " << yMax << "]";

  m_UI->histogramPlot
    ->axisScaleDiv( QwtPlot::xBottom )
    ->setInterval( xMin, xMax );

  m_UI->histogramPlot
    ->axisScaleDiv( QwtPlot::yLeft )
    ->setInterval( yMin, yMax );
}

/*******************************************************************************/
/* SLOTS                                                                       */
/*******************************************************************************/

} // end namespace 'mvd'
<|endoftext|>


<commit_before>#include "particle-dst.h"

void DST::begin(dst_limit_t beginning_limit, dst_limit_t end_limit, int offset)
{
  // save beginning and end limits
  beginning_l = beginning_limit;
  end_l = end_limit;

  // set DST offset
  Time.setDSTOffset(offset);
}

bool DST::check()
{
  if (!Time.isValid()) {
    Serial.println("[TIME]: time not synced");
    // if time is not valid, sync it
    Particle.syncTime();
    Serial.println("[TIME]: syncing time");
    waitUntil(Particle.syncTimeDone);
  }

  if (Time.isDST()) {
    // disable DST to avoid problems
    // needed to compare local time
    Time.endDST();
  }

  int now = Time.local();
  int beginning = timestamp(beginning_l);
  int end = timestamp(end_l);

  Serial.printlnf("beginning: %d\nend: %d\nnow: %d", beginning, end, Time.local());

  if (Time.local() >= beginning && Time.local() < end) {
    // now is DST so enable DST mode
    Time.beginDST();
    Serial.println("DST: on");
    return true;
  }
  else {
    Serial.println("DST: off");
    return false;
  }
}

int DST::timestamp(dst_limit_t limit)
{
  time_t ts; //timestamp
  struct tm first_of_month; // date struct

  first_of_month.tm_sec = 0;
  first_of_month.tm_min = 0;
  first_of_month.tm_mday = 1; // first day of month

  first_of_month.tm_hour = limit.hour;
  first_of_month.tm_mon = limit.month - 1;

  // tm struct stores years since 1900
  first_of_month.tm_year = Time.year() - 1900;

  // convert time struct to timestamp
  // calculate timestamp of the first day of the month
  ts = mktime(&first_of_month);

  // number of days until the first occurrence
  int first_occurrence = (6 + limit.day - first_of_month.tm_wday) % 7;
  Serial.printlnf("first of month: %d | first occurrence: %d", first_of_month.tm_wday, first_occurrence);

  int weeks;
  // check if occurrence from beginning or from end of the month
  if (limit.occurrence > 0) {
    weeks = limit.occurrence - 1;
  }
  else {
    // find days until the requested occurrence
    int from_end = (abs(limit.occurrence) - 1) * 7;

    // calculate number of weeks in the month
    weeks = round((DAYS[limit.month - 1] - 1 - first_occurrence - from_end) / 7);
  }

  // seconds added to the first of month to get to the requested occurrence
  return ts + ((first_occurrence + (weeks * 7)) * 24 * 3600);
}
<commit_msg>Added support to countries where DST starts in a year and ends in the next one<commit_after>#include "particle-dst.h"

void DST::begin(dst_limit_t beginning_limit, dst_limit_t end_limit, int offset)
{
  // save beginning and end limits
  beginning_l = beginning_limit;
  end_l = end_limit;

  // set DST offset
  Time.setDSTOffset(offset);
}

bool DST::check()
{
  if (!Time.isValid()) {
    Serial.println("[TIME]: time not synced");
    // if time is not valid, sync it
    Particle.syncTime();
    Serial.println("[TIME]: syncing time");
    waitUntil(Particle.syncTimeDone);
  }

  if (Time.isDST()) {
    // disable DST to avoid problems
    // needed to compare limits with local time
    Time.endDST();
  }

  int now = Time.local();
  // calculate beginning and end limits
  int beginning = timestamp(beginning_l);
  int end = timestamp(end_l);

  Serial.printlnf("beginning: %d\nend: %d\nnow: %d", beginning, end, now);

  // check if beginning and end are in the same year
  if (beginning < end) {
    // DST starts and ends in the same year
    if (now >= beginning && now < end) {
      // now is DST so enable DST mode
      Time.beginDST();
      Serial.println("DST: on");
      return true;
    }
  }
  // or beginning is in a year and end is in the next one
  else {
    // DST ends next year or has started last year
    if (now >= beginning || now < end) {
      // now is DST so enable DST mode
      Time.beginDST();
      Serial.println("DST: on");
      return true;
    }
  }

  Serial.println("DST: off");
  return false;
}

int DST::timestamp(dst_limit_t limit)
{
  time_t ts; //timestamp
  struct tm first_of_month; // date struct

  first_of_month.tm_sec = 0;
  first_of_month.tm_min = 0;
  first_of_month.tm_mday = 1; // first day of month

  first_of_month.tm_hour = limit.hour;
  first_of_month.tm_mon = limit.month - 1;

  // tm struct stores years since 1900
  first_of_month.tm_year = Time.year() - 1900;

  // convert time struct to timestamp
  // calculate timestamp of the first day of the month
  ts = mktime(&first_of_month);

  // number of days until the first occurrence
  int first_occurrence = (6 + limit.day - first_of_month.tm_wday) % 7;
  Serial.printlnf("first of month: %d | first occurrence: %d", first_of_month.tm_wday, first_occurrence);

  int weeks;
  // check if occurrence from beginning or from end of the month
  if (limit.occurrence > 0) {
    weeks = limit.occurrence - 1;
  }
  else {
    // find days until the requested occurrence
    int from_end = (abs(limit.occurrence) - 1) * 7;

    // calculate number of weeks in the month
    weeks = round((DAYS[limit.month - 1] - 1 - first_occurrence - from_end) / 7);
  }

  // seconds added to the first of month to get to the requested occurrence
  return ts + ((first_occurrence + (weeks * 7)) * 24 * 3600);
}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    TestCxxFeatures.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 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.

=========================================================================*/

// .NAME TestCxxFeatures
// .SECTION Description
// Provides a reference for the set of C++ features that can be used
// by VTK.

#include "vtkConfigure.h"

//----------------------------------------------------------------------------

/* Check for known compilers.  */

#if defined(_MSC_VER)
# define VTK_CXX_MSVC
#endif

#if defined(__sgi) && !defined(__GNUC__)
# define VTK_CXX_SGI
# if !defined(_COMPILER_VERSION)
#  define VTK_CXX_SGI_6
# endif
#endif

#if defined(__HP_aCC)
# define VTK_CXX_ACC
#endif

#if defined(__SUNPRO_CC)
# define VTK_CXX_SUNPRO
#endif

#if defined(__GNUC__) && (__GNUC__ < 3)
# if (__GNUC__ < 3)
#  define VTK_CXX_GCC_2
# elif (__GNUC__ == 3)
#  define VTK_CXX_GCC_3
# endif
#endif

//----------------------------------------------------------------------------

/* Check for known compiler limitations.  */

// Check for IRIX64-6.5-CC-o32 (old SGI compiler).
#if defined(VTK_CXX_SGI_6)
# define VTK_TYPENAME /* empty */
# define VTK_CLASS_TEMPLATE_SPECIALIZATION /* empty */
#endif

// Check for MSVC.
#if defined(VTK_CXX_MSVC) && (_MSC_VER < 1310)
# define VTK_TYPENAME /* empty */
#endif

// Assume standard behavior if symbol is not already defined.
#if !defined(VTK_TYPENAME)
# define VTK_TYPENAME typename
#endif

// Assume standard behavior if symbol is not already defined.
#if !defined(VTK_CLASS_TEMPLATE_SPECIALIZATION)
# define VTK_CLASS_TEMPLATE_SPECIALIZATION template <>
#endif

//----------------------------------------------------------------------------

#include "vtkSystemIncludes.h"

//----------------------------------------------------------------------------

/* Test inclusion of sstream header.  */
//#if !(defined(VTK_CXX_GCC_2) || defined(VTK_CXX_ACC) || defined(VTK_CXX_SGI_6))
#if defined(VTK_CXX_GCC_3)
# include <sstream>
#endif

//----------------------------------------------------------------------------

/* Test inclusion of typeinfo header.  */

#include <typeinfo>

//----------------------------------------------------------------------------

/* Test use of namespaces.  */

#if !defined(VTK_CXX_SGI_6)
// Fails on kulu.crd IRIX64-6.5-CC-o32 (old SGI compiler).
namespace NamespaceTest {}
namespace {}
void NamespaceTestFunc() {}
namespace NamespaceTest
{
  using ::NamespaceTestFunc;
}
using namespace NamespaceTest;
#endif

//----------------------------------------------------------------------------

/* Test inclusion of some stl headers.  */
#ifdef _MSC_VER
#pragma warning (push, 2)
#endif

#include <vector>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#if !defined(VTK_CXX_SGI_6)
// Fails on kulu.crd IRIX64-6.5-CC-o32 (old SGI compiler).
void UsingStdVector()
{
  using vtkstd::vector;
  vector<int>();
}
#endif

//----------------------------------------------------------------------------

/* Test full template specialization of functions.  */
template <class T>
int FullySpecializedFunction(T*)
{
  return 0;
}

#if !defined(VTK_CXX_SGI)
// Fails on kulu.crd IRIX64-6.5-CC-o32 (old SGI compiler).
// Fails on manifold.crd IRIX64-6.5-CC-n32 (new SGI compiler).
template <>
int FullySpecializedFunction<int>(int*)
{
  return 1;
}
#else
// Let overload resolution pick this one instead.
int FullySpecializedFunction(int*)
{
  return 1;
}
#endif

int TestFullySpecializedFunction()
{
  int result = 1;
  int should_be_0 = FullySpecializedFunction(static_cast<float*>(0));
  if(should_be_0 != 0)
    {
    cerr << "FullySpecializedFunction<float*>() returned "
         << should_be_0 << ", not 0.\n";
    result = 0;
    }
  int should_be_1 = FullySpecializedFunction(static_cast<int*>(0));
  if(should_be_1 != 1)
    {
    cerr << "FullySpecializedFunction(int*) returned "
         << should_be_1 << ", not 1.\n";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test use of standard "bool" type and values.  */

#if !defined(VTK_CXX_SGI_6)
bool GetFalse()
{
  return false;
}

bool GetTrue()
{
  return true;
}

int TestBool()
{
  int result = 1;
  bool should_be_false = GetFalse();
  bool should_be_true = GetTrue();
  if(should_be_false)
    {
    cerr << "GetFalse() returned " << should_be_false << ", not false.\n";
    result = 0;
    }
  if(!should_be_true)
    {
    cerr << "GetTrue() returned " << should_be_true << ", not true.\n";
    result = 0;
    }
  return result;
}
#endif
//----------------------------------------------------------------------------

/* Test full template specialization of classes.  */

template <class T>
struct FullySpecializedClass
{
  static int Method() { return 0; }
  typedef T Type;
};

VTK_CLASS_TEMPLATE_SPECIALIZATION
struct FullySpecializedClass<float>
{
  static int Method() { return 1; }
  typedef int Type;
};

template <class T>
int TestFullySpecializedClassTrait(T*)
{
  typedef VTK_TYPENAME FullySpecializedClass<T>::Type Type;
  if(static_cast<Type>(3.1) == 3.1)
    {
    return 0;
    }
  return 1;
}

int TestFullySpecializedClass()
{
  int result = 1;
  int should_be_0 = FullySpecializedClass<int>::Method();
  if(should_be_0 != 0)
    {
    cerr << "FullySpecializedClass<int>::Method() returned "
         << should_be_0 << ", not 0.\n";
    result = 0;
    }
  int should_be_1 = FullySpecializedClass<float>::Method();
  if(should_be_1 != 1)
    {
    cerr << "FullySpecializedClass<float>::Method() returned "
         << should_be_1 << ", not 1.\n";
    result = 0;
    }
  if(!TestFullySpecializedClassTrait(static_cast<float*>(0)))
    {
    cerr << "Trait lookup of float didn't produce int.";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test if(int x = f()) style scoping.  */

int TestIfScopeHelper(int i)
{
  int result = 1;
  if(int x = i)
    {
    if(x != i)
      {
      cerr << "TestIfScope: x != " << i << "\n";
      result = 0;
      }
    }
  else
    {
    if(x != i)
      {
      cerr << "TestIfScope: x != " << i << "\n";
      result = 0;
      }
    }
  int x = result;
  return x;
}

int TestIfScope()
{
  int result = 1;
  if(!TestIfScopeHelper(1))
    {
    result = 0;
    }
  if(!TestIfScopeHelper(0))
    {
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test non-type template parameter.  */

template <int I>
struct NonTypeTemplate
{
  static int GetValue() { return I; }
};

int TestNonTypeTemplate()
{
  int result = 1;
  if(NonTypeTemplate<0>::GetValue() != 0)
    {
    cerr << "NonTypeTemplate<0>::GetValue() != 0\n";
    result = 0;
    }
  if(NonTypeTemplate<1>::GetValue() != 1)
    {
    cerr << "NonTypeTemplate<1>::GetValue() != 1\n";
    result = 0;
    }
  if(NonTypeTemplate<2>::GetValue() != 2)
    {
    cerr << "NonTypeTemplate<2>::GetValue() != 2\n";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test mixed type and non-type template arguments in a non-trival way.  */

template <class T, int N>
int TestMixedTypeTemplateFunction(T (*)[N])
{
  return N;
}

int TestMixedTypeTemplate()
{
  int x2[2];
  float x3[3];
  int result = 1;
  if(TestMixedTypeTemplateFunction(&x2) != 2)
    {
    cerr << "TestMixedTypeTemplateFunction(&x2) != 2\n";
    result = 0;
    }
  if(TestMixedTypeTemplateFunction(&x3) != 3)
    {
    cerr << "TestMixedTypeTemplateFunction(&x3) != 3\n";
    result = 0;
    }
  return 0;
}

//----------------------------------------------------------------------------

int TestBinaryWriting()
{
  int result = 1;
  // ios::binary does not exist on SGI and OSF cxx (DEC)
  // it failed to compile on these machines:
  // ct02_oc.crd IRIX64-6.5-CC-64
  // manifold IRIX64-6.5-CC-n32
  // kulu.crd IRIX64-6.5-CC-o32
  // a62.iue.tuwien.ac.at OSF1-V5.1-cxx
#if defined(VTK_CXX_SGI) || defined( __DECCXX_VER)
  ofstream fout_with_warning_C4701("TestCxxFeatures_TestBinaryWriting", ios::out );
#else
  ofstream fout_with_warning_C4701("TestCxxFeatures_TestBinaryWriting", ios::out | ios::binary);
#endif
  if(!fout_with_warning_C4701)
    {
    cerr << "Error opening TestCxxFeatures_TestBinaryWriting for binary writing.\n";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

class SafeBoolIdiomClass
{
private:
  struct SafeBoolDummy { void Dummy() {} };
  typedef void (SafeBoolDummy::* SafeBool)();
public:
  SafeBoolIdiomClass(int x): Value(x) {}
  operator SafeBool()
    {
    return this->Value? &SafeBoolDummy::Dummy : 0;
    }
  SafeBool operator !()
    {
    return this->Value? 0 : &SafeBoolDummy::Dummy;
    }
protected:
  int Value;
};

int TestSafeBoolIdiom()
{
  int result = 1;
  SafeBoolIdiomClass cTrue(1);
  SafeBoolIdiomClass cFalse(0);
  if(cTrue) {}
  else
    {
    cerr << "if(cTrue) evaluates to false.\n";
    result = 0;
    }
  if(!cTrue)
    {
    cerr << "if(!cTrue) evaluates to true.\n";
    result = 0;
    }
  if(cFalse)
    {
    cerr << "if(cFalse) evaluates to true.\n";
    result = 0;
    }
  if(!cFalse) {}
  else
    {
    cerr << "if(!cFalse) evaluates to false.\n";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

#define DO_TEST(x) \
  if(x()) { cout << "Passed: " #x "\n"; } \
  else { cout << "Failed: " #x "\n"; result = 1; }

int main()
{
  int result = 0;
  DO_TEST(TestFullySpecializedFunction);
#if !defined(VTK_CXX_SGI_6)
  DO_TEST(TestBool);
#endif
  DO_TEST(TestFullySpecializedClass);
  DO_TEST(TestIfScope);
  DO_TEST(TestNonTypeTemplate);
  DO_TEST(TestMixedTypeTemplate);
  DO_TEST(TestBinaryWriting);
  DO_TEST(TestSafeBoolIdiom);
  return result;
}
<commit_msg>ERR: bad test logic.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestCxxFeatures.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 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.

=========================================================================*/

// .NAME TestCxxFeatures
// .SECTION Description
// Provides a reference for the set of C++ features that can be used
// by VTK.

#include "vtkConfigure.h"

//----------------------------------------------------------------------------

/* Check for known compilers.  */

#if defined(_MSC_VER)
# define VTK_CXX_MSVC
#endif

#if defined(__sgi) && !defined(__GNUC__)
# define VTK_CXX_SGI
# if !defined(_COMPILER_VERSION)
#  define VTK_CXX_SGI_6
# endif
#endif

#if defined(__HP_aCC)
# define VTK_CXX_ACC
#endif

#if defined(__SUNPRO_CC)
# define VTK_CXX_SUNPRO
#endif

#if defined(__GNUC__) && (__GNUC__ < 3)
# if (__GNUC__ < 3)
#  define VTK_CXX_GCC_2
# elif (__GNUC__ == 3)
#  define VTK_CXX_GCC_3
# endif
#endif

//----------------------------------------------------------------------------

/* Check for known compiler limitations.  */

// Check for IRIX64-6.5-CC-o32 (old SGI compiler).
#if defined(VTK_CXX_SGI_6)
# define VTK_TYPENAME /* empty */
# define VTK_CLASS_TEMPLATE_SPECIALIZATION /* empty */
#endif

// Check for MSVC.
#if defined(VTK_CXX_MSVC) && (_MSC_VER < 1310)
# define VTK_TYPENAME /* empty */
#endif

// Assume standard behavior if symbol is not already defined.
#if !defined(VTK_TYPENAME)
# define VTK_TYPENAME typename
#endif

// Assume standard behavior if symbol is not already defined.
#if !defined(VTK_CLASS_TEMPLATE_SPECIALIZATION)
# define VTK_CLASS_TEMPLATE_SPECIALIZATION template <>
#endif

//----------------------------------------------------------------------------

#include "vtkSystemIncludes.h"

//----------------------------------------------------------------------------

/* Test inclusion of sstream header.  */
//#if !(defined(VTK_CXX_GCC_2) || defined(VTK_CXX_ACC) || defined(VTK_CXX_SGI_6))
#if defined(VTK_CXX_GCC_3)
# include <sstream>
#endif

//----------------------------------------------------------------------------

/* Test inclusion of typeinfo header.  */

#include <typeinfo>

//----------------------------------------------------------------------------

/* Test use of namespaces.  */

#if !defined(VTK_CXX_SGI_6)
// Fails on kulu.crd IRIX64-6.5-CC-o32 (old SGI compiler).
namespace NamespaceTest {}
namespace {}
void NamespaceTestFunc() {}
namespace NamespaceTest
{
  using ::NamespaceTestFunc;
}
using namespace NamespaceTest;
#endif

//----------------------------------------------------------------------------

/* Test inclusion of some stl headers.  */
#ifdef _MSC_VER
#pragma warning (push, 2)
#endif

#include <vector>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#if !defined(VTK_CXX_SGI_6)
// Fails on kulu.crd IRIX64-6.5-CC-o32 (old SGI compiler).
void UsingStdVector()
{
  using vtkstd::vector;
  vector<int>();
}
#endif

//----------------------------------------------------------------------------

/* Test full template specialization of functions.  */
template <class T>
int FullySpecializedFunction(T*)
{
  return 0;
}

#if !defined(VTK_CXX_SGI)
// Fails on kulu.crd IRIX64-6.5-CC-o32 (old SGI compiler).
// Fails on manifold.crd IRIX64-6.5-CC-n32 (new SGI compiler).
template <>
int FullySpecializedFunction<int>(int*)
{
  return 1;
}
#else
// Let overload resolution pick this one instead.
int FullySpecializedFunction(int*)
{
  return 1;
}
#endif

int TestFullySpecializedFunction()
{
  int result = 1;
  int should_be_0 = FullySpecializedFunction(static_cast<float*>(0));
  if(should_be_0 != 0)
    {
    cerr << "FullySpecializedFunction<float*>() returned "
         << should_be_0 << ", not 0.\n";
    result = 0;
    }
  int should_be_1 = FullySpecializedFunction(static_cast<int*>(0));
  if(should_be_1 != 1)
    {
    cerr << "FullySpecializedFunction(int*) returned "
         << should_be_1 << ", not 1.\n";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test use of standard "bool" type and values.  */

#if !defined(VTK_CXX_SGI_6)
bool GetFalse()
{
  return false;
}

bool GetTrue()
{
  return true;
}

int TestBool()
{
  int result = 1;
  bool should_be_false = GetFalse();
  bool should_be_true = GetTrue();
  if(should_be_false)
    {
    cerr << "GetFalse() returned " << should_be_false << ", not false.\n";
    result = 0;
    }
  if(!should_be_true)
    {
    cerr << "GetTrue() returned " << should_be_true << ", not true.\n";
    result = 0;
    }
  return result;
}
#endif
//----------------------------------------------------------------------------

/* Test full template specialization of classes.  */

template <class T>
struct FullySpecializedClass
{
  static int Method() { return 0; }
  typedef T Type;
};

VTK_CLASS_TEMPLATE_SPECIALIZATION
struct FullySpecializedClass<float>
{
  static int Method() { return 1; }
  typedef int Type;
};

template <class T>
int TestFullySpecializedClassTrait(T*)
{
  typedef VTK_TYPENAME FullySpecializedClass<T>::Type Type;
  if(static_cast<Type>(3.1) == 3.1)
    {
    return 0;
    }
  return 1;
}

int TestFullySpecializedClass()
{
  int result = 1;
  int should_be_0 = FullySpecializedClass<int>::Method();
  if(should_be_0 != 0)
    {
    cerr << "FullySpecializedClass<int>::Method() returned "
         << should_be_0 << ", not 0.\n";
    result = 0;
    }
  int should_be_1 = FullySpecializedClass<float>::Method();
  if(should_be_1 != 1)
    {
    cerr << "FullySpecializedClass<float>::Method() returned "
         << should_be_1 << ", not 1.\n";
    result = 0;
    }
  if(!TestFullySpecializedClassTrait(static_cast<float*>(0)))
    {
    cerr << "Trait lookup of float didn't produce int.";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test if(int x = f()) style scoping.  */

int TestIfScopeHelper(int i)
{
  int result = 1;
  if(int x = i)
    {
    if(x != i)
      {
      cerr << "TestIfScope: x != " << i << "\n";
      result = 0;
      }
    }
  else
    {
    if(x != i)
      {
      cerr << "TestIfScope: x != " << i << "\n";
      result = 0;
      }
    }
  int x = result;
  return x;
}

int TestIfScope()
{
  int result = 1;
  if(!TestIfScopeHelper(1))
    {
    result = 0;
    }
  if(!TestIfScopeHelper(0))
    {
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test non-type template parameter.  */

template <int I>
struct NonTypeTemplate
{
  static int GetValue() { return I; }
};

int TestNonTypeTemplate()
{
  int result = 1;
  if(NonTypeTemplate<0>::GetValue() != 0)
    {
    cerr << "NonTypeTemplate<0>::GetValue() != 0\n";
    result = 0;
    }
  if(NonTypeTemplate<1>::GetValue() != 1)
    {
    cerr << "NonTypeTemplate<1>::GetValue() != 1\n";
    result = 0;
    }
  if(NonTypeTemplate<2>::GetValue() != 2)
    {
    cerr << "NonTypeTemplate<2>::GetValue() != 2\n";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test mixed type and non-type template arguments in a non-trival way.  */

template <class T, int N>
int TestMixedTypeTemplateFunction(T (*)[N])
{
  return N;
}

int TestMixedTypeTemplate()
{
  int x2[2];
  float x3[3];
  int result = 1;
  if(TestMixedTypeTemplateFunction(&x2) != 2)
    {
    cerr << "TestMixedTypeTemplateFunction(&x2) != 2\n";
    result = 0;
    }
  if(TestMixedTypeTemplateFunction(&x3) != 3)
    {
    cerr << "TestMixedTypeTemplateFunction(&x3) != 3\n";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

int TestBinaryWriting()
{
  int result = 1;
  // ios::binary does not exist on SGI and OSF cxx (DEC)
  // it failed to compile on these machines:
  // ct02_oc.crd IRIX64-6.5-CC-64
  // manifold IRIX64-6.5-CC-n32
  // kulu.crd IRIX64-6.5-CC-o32
  // a62.iue.tuwien.ac.at OSF1-V5.1-cxx
#if defined(VTK_CXX_SGI) || defined( __DECCXX_VER)
  ofstream fout_with_warning_C4701("TestCxxFeatures_TestBinaryWriting", ios::out );
#else
  ofstream fout_with_warning_C4701("TestCxxFeatures_TestBinaryWriting", ios::out | ios::binary);
#endif
  if(!fout_with_warning_C4701)
    {
    cerr << "Error opening TestCxxFeatures_TestBinaryWriting for binary writing.\n";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

class SafeBoolIdiomClass
{
private:
  struct SafeBoolDummy { void Dummy() {} };
  typedef void (SafeBoolDummy::* SafeBool)();
public:
  SafeBoolIdiomClass(int x): Value(x) {}
  operator SafeBool()
    {
    return this->Value? &SafeBoolDummy::Dummy : 0;
    }
  SafeBool operator !()
    {
    return this->Value? 0 : &SafeBoolDummy::Dummy;
    }
protected:
  int Value;
};

int TestSafeBoolIdiom()
{
  int result = 1;
  SafeBoolIdiomClass cTrue(1);
  SafeBoolIdiomClass cFalse(0);
  if(cTrue) {}
  else
    {
    cerr << "if(cTrue) evaluates to false.\n";
    result = 0;
    }
  if(!cTrue)
    {
    cerr << "if(!cTrue) evaluates to true.\n";
    result = 0;
    }
  if(cFalse)
    {
    cerr << "if(cFalse) evaluates to true.\n";
    result = 0;
    }
  if(!cFalse) {}
  else
    {
    cerr << "if(!cFalse) evaluates to false.\n";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

#define DO_TEST(x) \
  if(x()) { cout << "Passed: " #x "\n"; } \
  else { cout << "Failed: " #x "\n"; result = 1; }

int main()
{
  int result = 0;
  DO_TEST(TestFullySpecializedFunction);
#if !defined(VTK_CXX_SGI_6)
  DO_TEST(TestBool);
#endif
  DO_TEST(TestFullySpecializedClass);
  DO_TEST(TestIfScope);
  DO_TEST(TestNonTypeTemplate);
  DO_TEST(TestMixedTypeTemplate);
  DO_TEST(TestBinaryWriting);
  DO_TEST(TestSafeBoolIdiom);
  return result;
}
<|endoftext|>


<commit_before>// Scintilla source code edit control
// KeyMap.cxx  - defines a mapping between keystrokes and commands
// Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include "Platform.h"

#include "Scintilla.h"

#include "KeyMap.h"

KeyMap::KeyMap() : kmap(0), len(0), alloc(0) {
	for (int i = 0; MapDefault[i].key; i++) {
		AssignCmdKey(MapDefault[i].key,
			MapDefault[i].modifiers,
             		MapDefault[i].msg);
	}
}

KeyMap::~KeyMap() {
	Clear();
}

void KeyMap::Clear() {
	delete []kmap;
	kmap = 0;
	len = 0;
	alloc = 0;
}

void KeyMap::AssignCmdKey(int key, int modifiers, UINT msg) {
	if ((len+1) >= alloc) {
		KeyToCommand *ktcNew = new KeyToCommand[alloc + 5];
		if (!ktcNew)
			return;
		for (int k=0;k<len;k++)
			ktcNew[k] = kmap[k];
		alloc += 5;
		delete []kmap;
		kmap = ktcNew;
	}
	for (int keyIndex = 0; keyIndex < len; keyIndex++) {
		if ((key == kmap[keyIndex].key) && (modifiers == kmap[keyIndex].modifiers)) {
			kmap[keyIndex].msg = msg;
			return;
		}
	}
	kmap[len].key = key;
	kmap[len].modifiers = modifiers;
	kmap[len].msg = msg;
	len++;
}

UINT KeyMap::Find(int key, int modifiers) {
	for (int i=0; i < len; i++) {
		if ((key == kmap[i].key) && (modifiers == kmap[i].modifiers)) {
			return kmap[i].msg;
		}
	}
	return 0;
}

KeyToCommand KeyMap::MapDefault[] = {
    {VK_DOWN,		SCI_NORM,	SCI_LINEDOWN},
    {VK_DOWN,		SCI_SHIFT,	SCI_LINEDOWNEXTEND},
    {VK_DOWN,		SCI_CTRL,	SCI_LINESCROLLDOWN},
    {VK_UP,			SCI_NORM,	SCI_LINEUP},
    {VK_UP,			SCI_SHIFT,	SCI_LINEUPEXTEND},
    {VK_UP,			SCI_CTRL,	SCI_LINESCROLLUP},
    {VK_LEFT,		SCI_NORM,	SCI_CHARLEFT},
    {VK_LEFT,		SCI_SHIFT,	SCI_CHARLEFTEXTEND},
    {VK_LEFT,		SCI_CTRL,	SCI_WORDLEFT},
    {VK_LEFT,		SCI_CSHIFT,	SCI_WORDLEFTEXTEND},
    {VK_RIGHT,		SCI_NORM,	SCI_CHARRIGHT},
    {VK_RIGHT,		SCI_SHIFT,	SCI_CHARRIGHTEXTEND},
    {VK_RIGHT,		SCI_CTRL,	SCI_WORDRIGHT},
    {VK_RIGHT,		SCI_CSHIFT,	SCI_WORDRIGHTEXTEND},
    {VK_HOME, 		SCI_NORM, 	SCI_VCHOME},
    {VK_HOME, 		SCI_SHIFT, 	SCI_VCHOMEEXTEND},
    {VK_HOME, 		SCI_CTRL, 	SCI_DOCUMENTSTART},
    {VK_HOME, 		SCI_CSHIFT, 	SCI_DOCUMENTSTARTEXTEND},
    {VK_END,	 	SCI_NORM, 	SCI_LINEEND},
    {VK_END,	 	SCI_SHIFT, 	SCI_LINEENDEXTEND},
    {VK_END, 		SCI_CTRL, 	SCI_DOCUMENTEND},
    {VK_END, 		SCI_CSHIFT, 	SCI_DOCUMENTENDEXTEND},
    {VK_PRIOR,		SCI_NORM, 	SCI_PAGEUP},
    {VK_PRIOR,		SCI_SHIFT, 	SCI_PAGEUPEXTEND},
    {VK_NEXT, 		SCI_NORM, 	SCI_PAGEDOWN},
    {VK_NEXT, 		SCI_SHIFT, 	SCI_PAGEDOWNEXTEND},
    {VK_DELETE, 	SCI_NORM,	WM_CLEAR},
    {VK_DELETE, 	SCI_SHIFT,	WM_CUT},
    {VK_DELETE, 	SCI_CTRL,	SCI_DELWORDRIGHT},
    {VK_INSERT, 		SCI_NORM,	SCI_EDITTOGGLEOVERTYPE},
    {VK_INSERT, 		SCI_SHIFT,	WM_PASTE},
    {VK_INSERT, 		SCI_CTRL,	WM_COPY},
    {VK_ESCAPE,  	SCI_NORM,	SCI_CANCEL},
    {VK_BACK,		SCI_NORM, 	SCI_DELETEBACK},
    {VK_BACK,		SCI_SHIFT, 	SCI_DELETEBACK},
    {VK_BACK,		SCI_CTRL, 	SCI_DELWORDLEFT},
    {'Z', 			SCI_CTRL,	WM_UNDO},
    {'Y', 			SCI_CTRL,	SCI_REDO},
    {'X', 			SCI_CTRL,	WM_CUT},
    {'C', 			SCI_CTRL,	WM_COPY},
    {'V', 			SCI_CTRL,	WM_PASTE},
    {'A', 			SCI_CTRL,	SCI_SELECTALL},
    {VK_TAB,		SCI_NORM,	SCI_TAB},
    {VK_TAB,		SCI_SHIFT,	SCI_BACKTAB},
    {VK_RETURN, 	SCI_NORM,	SCI_NEWLINE},
    {VK_ADD, 		SCI_CTRL,	SCI_ZOOMIN},
    {VK_SUBTRACT,	SCI_CTRL,	SCI_ZOOMOUT},
    {VK_DIVIDE,	SCI_CTRL,	SCI_SETZOOM},
    //'L', 			SCI_CTRL,		SCI_FORMFEED,
    {'L', 			SCI_CTRL,	SCI_LINECUT},
    {'L', 			SCI_CSHIFT,	SCI_LINEDELETE},
    {'T', 			SCI_CTRL,	SCI_LINETRANSPOSE},
    {'U', 			SCI_CTRL,	SCI_LOWERCASE},
    {'U', 			SCI_CSHIFT,	SCI_UPPERCASE},
    {0,0,0},
};

<commit_msg>Added Alt+BackSpace as synonym for Undo.<commit_after>// Scintilla source code edit control
// KeyMap.cxx  - defines a mapping between keystrokes and commands
// Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include "Platform.h"

#include "Scintilla.h"

#include "KeyMap.h"

KeyMap::KeyMap() : kmap(0), len(0), alloc(0) {
	for (int i = 0; MapDefault[i].key; i++) {
		AssignCmdKey(MapDefault[i].key,
			MapDefault[i].modifiers,
             		MapDefault[i].msg);
	}
}

KeyMap::~KeyMap() {
	Clear();
}

void KeyMap::Clear() {
	delete []kmap;
	kmap = 0;
	len = 0;
	alloc = 0;
}

void KeyMap::AssignCmdKey(int key, int modifiers, UINT msg) {
	if ((len+1) >= alloc) {
		KeyToCommand *ktcNew = new KeyToCommand[alloc + 5];
		if (!ktcNew)
			return;
		for (int k=0;k<len;k++)
			ktcNew[k] = kmap[k];
		alloc += 5;
		delete []kmap;
		kmap = ktcNew;
	}
	for (int keyIndex = 0; keyIndex < len; keyIndex++) {
		if ((key == kmap[keyIndex].key) && (modifiers == kmap[keyIndex].modifiers)) {
			kmap[keyIndex].msg = msg;
			return;
		}
	}
	kmap[len].key = key;
	kmap[len].modifiers = modifiers;
	kmap[len].msg = msg;
	len++;
}

UINT KeyMap::Find(int key, int modifiers) {
	for (int i=0; i < len; i++) {
		if ((key == kmap[i].key) && (modifiers == kmap[i].modifiers)) {
			return kmap[i].msg;
		}
	}
	return 0;
}

KeyToCommand KeyMap::MapDefault[] = {
    {VK_DOWN,		SCI_NORM,	SCI_LINEDOWN},
    {VK_DOWN,		SCI_SHIFT,	SCI_LINEDOWNEXTEND},
    {VK_DOWN,		SCI_CTRL,	SCI_LINESCROLLDOWN},
    {VK_UP,			SCI_NORM,	SCI_LINEUP},
    {VK_UP,			SCI_SHIFT,	SCI_LINEUPEXTEND},
    {VK_UP,			SCI_CTRL,	SCI_LINESCROLLUP},
    {VK_LEFT,		SCI_NORM,	SCI_CHARLEFT},
    {VK_LEFT,		SCI_SHIFT,	SCI_CHARLEFTEXTEND},
    {VK_LEFT,		SCI_CTRL,	SCI_WORDLEFT},
    {VK_LEFT,		SCI_CSHIFT,	SCI_WORDLEFTEXTEND},
    {VK_RIGHT,		SCI_NORM,	SCI_CHARRIGHT},
    {VK_RIGHT,		SCI_SHIFT,	SCI_CHARRIGHTEXTEND},
    {VK_RIGHT,		SCI_CTRL,	SCI_WORDRIGHT},
    {VK_RIGHT,		SCI_CSHIFT,	SCI_WORDRIGHTEXTEND},
    {VK_HOME, 		SCI_NORM, 	SCI_VCHOME},
    {VK_HOME, 		SCI_SHIFT, 	SCI_VCHOMEEXTEND},
    {VK_HOME, 		SCI_CTRL, 	SCI_DOCUMENTSTART},
    {VK_HOME, 		SCI_CSHIFT, 	SCI_DOCUMENTSTARTEXTEND},
    {VK_END,	 	SCI_NORM, 	SCI_LINEEND},
    {VK_END,	 	SCI_SHIFT, 	SCI_LINEENDEXTEND},
    {VK_END, 		SCI_CTRL, 	SCI_DOCUMENTEND},
    {VK_END, 		SCI_CSHIFT, 	SCI_DOCUMENTENDEXTEND},
    {VK_PRIOR,		SCI_NORM, 	SCI_PAGEUP},
    {VK_PRIOR,		SCI_SHIFT, 	SCI_PAGEUPEXTEND},
    {VK_NEXT, 		SCI_NORM, 	SCI_PAGEDOWN},
    {VK_NEXT, 		SCI_SHIFT, 	SCI_PAGEDOWNEXTEND},
    {VK_DELETE, 	SCI_NORM,	WM_CLEAR},
    {VK_DELETE, 	SCI_SHIFT,	WM_CUT},
    {VK_DELETE, 	SCI_CTRL,	SCI_DELWORDRIGHT},
    {VK_INSERT, 		SCI_NORM,	SCI_EDITTOGGLEOVERTYPE},
    {VK_INSERT, 		SCI_SHIFT,	WM_PASTE},
    {VK_INSERT, 		SCI_CTRL,	WM_COPY},
    {VK_ESCAPE,  	SCI_NORM,	SCI_CANCEL},
    {VK_BACK,		SCI_NORM, 	SCI_DELETEBACK},
    {VK_BACK,		SCI_SHIFT, 	SCI_DELETEBACK},
    {VK_BACK,		SCI_CTRL, 	SCI_DELWORDLEFT},
    {VK_BACK, 		SCI_ALT,	WM_UNDO},
    {'Z', 			SCI_CTRL,	WM_UNDO},
    {'Y', 			SCI_CTRL,	SCI_REDO},
    {'X', 			SCI_CTRL,	WM_CUT},
    {'C', 			SCI_CTRL,	WM_COPY},
    {'V', 			SCI_CTRL,	WM_PASTE},
    {'A', 			SCI_CTRL,	SCI_SELECTALL},
    {VK_TAB,		SCI_NORM,	SCI_TAB},
    {VK_TAB,		SCI_SHIFT,	SCI_BACKTAB},
    {VK_RETURN, 	SCI_NORM,	SCI_NEWLINE},
    {VK_ADD, 		SCI_CTRL,	SCI_ZOOMIN},
    {VK_SUBTRACT,	SCI_CTRL,	SCI_ZOOMOUT},
    {VK_DIVIDE,	SCI_CTRL,	SCI_SETZOOM},
    //'L', 			SCI_CTRL,		SCI_FORMFEED,
    {'L', 			SCI_CTRL,	SCI_LINECUT},
    {'L', 			SCI_CSHIFT,	SCI_LINEDELETE},
    {'T', 			SCI_CTRL,	SCI_LINETRANSPOSE},
    {'U', 			SCI_CTRL,	SCI_LOWERCASE},
    {'U', 			SCI_CSHIFT,	SCI_UPPERCASE},
    {0,0,0},
};

<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexLua.cxx
 ** Lexer for Lua language.
 **
 ** Written by Paul Winwood.
 ** Folder by Alexey Yutkin.
 ** Modified by Marcos E. Wurzius
 **/

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <fcntl.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

inline bool isLuaOperator(char ch) {
	if (isalnum(ch))
		return false;
	// '.' left out as it is used to make up numbers
	if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
	        ch == '(' || ch == ')' || ch == '=' ||
	        ch == '{' || ch == '}' || ch == '~' ||
	        ch == '[' || ch == ']' || ch == ';' ||
	        ch == '<' || ch == '>' || ch == ',' ||
	        ch == '.' || ch == '^' || ch == '%' || ch == ':')
		return true;
	return false;
}

static void ColouriseLuaDoc(unsigned int startPos,
                            int length,
                            int initStyle,
                            WordList *keywordLists[],
                            Accessor &styler) {

	WordList &keywords = *keywordLists[0];
	WordList &keywords2 = *keywordLists[1];
	WordList &keywords3 = *keywordLists[2];
	WordList &keywords4 = *keywordLists[3];
	WordList &keywords5 = *keywordLists[4];
	WordList &keywords6 = *keywordLists[5];

	styler.StartAt(startPos);
	styler.GetLine(startPos);

	int state = initStyle;
	char chPrev = ' ';
	char chNext = styler[startPos];
	unsigned int lengthDoc = startPos + length;
	bool firstChar = true;

	/* Must initialize the literalString level, if we are inside such a string.
	 * Note: this isn't enough, because literal strings can be nested,
	 * we should go back to see at what level we are...
	 */
	int literalString = (initStyle == SCE_LUA_LITERALSTRING) ? 1 : 0;

	styler.StartSegment(startPos);
	for (unsigned int i = startPos; i <= lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if (styler.IsLeadByte(ch)) {
			chNext = styler.SafeGetCharAt(i + 2);
			chPrev = ' ';
			i += 1;
			continue;
		}

		if (state == SCE_LUA_STRINGEOL) {
			if (ch != '\r' && ch != '\n') {
				styler.ColourTo(i - 1, state);
				state = SCE_LUA_DEFAULT;
			}
		}

		if (state == SCE_LUA_DEFAULT) {
			if (ch == '-' && chNext == '-') {
				styler.ColourTo(i - 1, state);
				state = SCE_LUA_COMMENTLINE;
			} else if (ch == '[' && chNext == '[') {
				state = SCE_LUA_LITERALSTRING;
				literalString = 1;
			} else if (ch == '\"') {
				styler.ColourTo(i - 1, state);
				state = SCE_LUA_STRING;
			} else if (ch == '\'') {
				styler.ColourTo(i - 1, state);
				state = SCE_LUA_CHARACTER;
			} else if (ch == '$' && firstChar) {
				styler.ColourTo(i - 1, state);
				state = SCE_LUA_PREPROCESSOR;
			} else if (ch == '#' && firstChar) {	// Should be only on the first line of the file! Cannot be tested here
				styler.ColourTo(i - 1, state);
				state = SCE_LUA_COMMENTLINE;
			} else if (isLuaOperator(ch)) {
				styler.ColourTo(i - 1, state);
				styler.ColourTo(i, SCE_LUA_OPERATOR);
			} else if (isdigit(ch) || (ch == '.')) {
				styler.ColourTo(i - 1, state);
				state = SCE_LUA_NUMBER;
			} else if (iswordstart(ch)) {
				styler.ColourTo(i - 1, state);
				state = SCE_LUA_WORD;
			}
		} else {
			if (state == SCE_LUA_NUMBER) {
				if (!iswordchar(ch)) {
					styler.ColourTo(i - 1, SCE_LUA_NUMBER);
					state = SCE_LUA_DEFAULT;
				}
			} else if (state == SCE_LUA_WORD) {
				if (!iswordchar(ch) || (ch == '.')) {
					char s[100];
					unsigned int start = styler.GetStartSegment();
					unsigned int end = i - 1;

					for (unsigned int n = 0; n < end - start + 1 && n < 30; n++) {
						s[n] = styler[start + n];
						s[n + 1] = '\0';
					}

					char chAttr = SCE_LUA_IDENTIFIER;
					if (keywords.InList(s)) {
						chAttr = SCE_LUA_WORD;
					} else if (keywords2.InList(s)) {
						chAttr = SCE_LUA_WORD2;
					} else if (keywords3.InList(s)) {
						chAttr = SCE_LUA_WORD3 ;
					} else if (keywords4.InList(s)) {
						chAttr = SCE_LUA_WORD4 ;
					} else if (keywords5.InList(s)) {
						chAttr = SCE_LUA_WORD5 ;
					} else if (keywords6.InList(s)) {
						chAttr = SCE_LUA_WORD6 ;
					}
					styler.ColourTo(end, chAttr);
					state = SCE_LUA_DEFAULT;
				}
			} else if (state == SCE_LUA_LITERALSTRING) {
				if (ch == '[' && chNext == '[') {
					literalString++;
				} else if (ch == ']' && (chPrev == ']') && (--literalString == 0)) {
					styler.ColourTo(i, state);
					state = SCE_LUA_DEFAULT;
				}
			} else if (state == SCE_LUA_PREPROCESSOR) {
				if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) {
					styler.ColourTo(i - 1, state);
					state = SCE_LUA_DEFAULT;
				}
			} else if (state == SCE_LUA_COMMENTLINE) {
				if (ch == '\r' || ch == '\n') {
					styler.ColourTo(i - 1, state);
					state = SCE_LUA_DEFAULT;
				}
			} else if (state == SCE_LUA_STRING) {
				if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) {
					styler.ColourTo(i - 1, state);
					state = SCE_LUA_STRINGEOL;
				} else if (ch == '\\') {
					if (chNext == '\"' || chNext == '\\') {
						i++;
						ch = chNext;
						chNext = styler.SafeGetCharAt(i + 1);
					}
				} else if (ch == '\"') {
					styler.ColourTo(i, state);
					state = SCE_LUA_DEFAULT;
					i++;
					ch = chNext;
					chNext = styler.SafeGetCharAt(i + 1);
				}
			} else if (state == SCE_LUA_CHARACTER) {
				if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) {
					styler.ColourTo(i - 1, state);
					state = SCE_LUA_STRINGEOL;
				} else if (ch == '\\') {
					if (chNext == '\'' || chNext == '\\') {
						i++;
						ch = chNext;
						chNext = styler.SafeGetCharAt(i + 1);
					}
				} else if (ch == '\'') {
					styler.ColourTo(i, state);
					state = SCE_LUA_DEFAULT;
					i++;
					ch = chNext;
					chNext = styler.SafeGetCharAt(i + 1);
				}
			}

			if (state == SCE_LUA_DEFAULT) {
				if (ch == '-' && chNext == '-') {
					state = SCE_LUA_COMMENTLINE;
				} else if (ch == '[' && chNext == '[') {
					literalString = 1;
					state = SCE_LUA_LITERALSTRING;
				} else if (ch == '\"') {
					state = SCE_LUA_STRING;
				} else if (ch == '\'') {
					state = SCE_LUA_CHARACTER;
				} else if (ch == '$' && firstChar) {
					state = SCE_LUA_PREPROCESSOR;
				} else if (isdigit(ch) || (ch == '.')) {
					state = SCE_LUA_NUMBER;
				} else if (iswordstart(ch)) {
					state = SCE_LUA_WORD;
				} else if (isLuaOperator(ch)) {
					styler.ColourTo(i, SCE_LUA_OPERATOR);
				}
			}
		}
		chPrev = ch;
		firstChar = (ch == '\r' || ch == '\n');
	}
	styler.ColourTo(lengthDoc - 1, state);
}

static void FoldLuaDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[],
                       Accessor &styler) {
	unsigned int lengthDoc = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	int styleNext = styler.StyleAt(startPos);
	char s[10];
	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (style == SCE_LUA_WORD) {
			if ( ch == 'i' || ch == 'e' || ch == 't' || ch == 'd' || ch == 'f') {
				for (unsigned int j = 0; j < 8; j++) {
					if (!iswordchar(styler[i + j]))
						break;
					s[j] = styler[i + j];
					s[j + 1] = '\0';
				}

				if ((strcmp(s, "if") == 0) || (strcmp(s, "do") == 0)
				        || (strcmp(s, "function") == 0))
					levelCurrent++;
				if ((strcmp(s, "end") == 0) || (strcmp(s, "elseif") == 0))
					levelCurrent--;

			}
		} else if (style == SCE_LUA_OPERATOR) {
			if (ch == '{' || ch == '(')
				levelCurrent++;
			else if (ch == '}' || ch == ')')
				levelCurrent--;
		}

		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later

	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

LexerModule lmLua(SCLEX_LUA, ColouriseLuaDoc, "lua", FoldLuaDoc);
<commit_msg>Patch from Alexey to use StyleContext.<commit_after>// Scintilla source code edit control
/** @file LexLua.cxx
 ** Lexer for Lua language.
 **
 ** Written by Paul Winwood.
 ** Folder by Alexey Yutkin.
 ** Modified by Marcos E. Wurzius
 **/

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <fcntl.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

inline bool isLuaOperator(char ch) {
	if (isalnum(ch))
		return false;
	// '.' left out as it is used to make up numbers
	if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
		ch == '(' || ch == ')' || ch == '=' ||
		ch == '{' || ch == '}' || ch == '~' ||
		ch == '[' || ch == ']' || ch == ';' ||
		ch == '<' || ch == '>' || ch == ',' ||
		ch == '.' || ch == '^' || ch == '%' || ch == ':')
		return true;
	return false;
}

static void ColouriseLuaDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
                            Accessor &styler) {

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];
	WordList &keywords4 = *keywordlists[3];
	WordList &keywords5 = *keywordlists[4];
	WordList &keywords6 = *keywordlists[5];
	int literalString = 0;
	int literalStringFlag =0;

	// Do not leak onto next line
	if (initStyle == SCE_LUA_STRINGEOL)
		initStyle = SCE_LUA_DEFAULT;

	int chPrevNonWhite = ' ';
	int visibleChars = 0;

	StyleContext sc(startPos, length, initStyle, styler);
	if(startPos == 0 && sc.ch == '#') sc.SetState(SCE_LUA_COMMENTLINE);
	for (; sc.More(); sc.Forward()) {

		// Handle line continuation generically.
		if (sc.ch == '\\') {
			if (sc.Match("\\\n")) {
				sc.Forward();
				sc.Forward();
				continue;
			}
			if (sc.Match("\\\r\n")) {
				sc.Forward();
				sc.Forward();
				sc.Forward();
				continue;
			}
		}

		// Determine if the current state should terminate.
		if (sc.state == SCE_LUA_OPERATOR) {
			sc.SetState(SCE_LUA_DEFAULT);
		} else if (sc.state == SCE_LUA_NUMBER) {
			if (!IsAWordChar(sc.ch)) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_IDENTIFIER) {
			if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (keywords.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD);
				} else if (keywords2.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD2);
				} else if (keywords3.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD3);
				} else if (keywords4.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD4);
				} else if (keywords5.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD5);
				} else if (keywords6.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD6);
				}
				sc.SetState(SCE_LUA_DEFAULT);
			}

		} else if (sc.state == SCE_LUA_COMMENTLINE ) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_LUA_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_LUA_STRING) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\"') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
				visibleChars = 0;
			}

		} else if (sc.state == SCE_LUA_CHARACTER) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\'') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_LUA_LITERALSTRING) {
			if (sc.chPrev == '[' && sc.ch == '[' && literalStringFlag != 1) 	{
				literalString++;
				literalStringFlag = 1;
			}
			else if (sc.chPrev == ']' && sc.ch == ']' && literalStringFlag != 2 ) {
				if((--literalString == 1))
					sc.ForwardSetState(SCE_LUA_DEFAULT);
				literalStringFlag = 2;
			}
			else literalStringFlag = 0;
		}
		// Determine if a new state should be entered.
		if (sc.state == SCE_LUA_DEFAULT) {
			if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
					sc.SetState(SCE_LUA_NUMBER);
			} else if (IsAWordStart(sc.ch) || (sc.ch == '@')) {
					sc.SetState(SCE_LUA_IDENTIFIER);
			} else if (sc.ch == '\"') {
				sc.SetState(SCE_LUA_STRING);
			} else if (sc.ch == '\'') {
				sc.SetState(SCE_LUA_CHARACTER);
			} else if (sc.ch == '[' && sc.chNext == '[') {
				sc.SetState(SCE_LUA_LITERALSTRING);
				literalString = 1;
			} else if (sc.ch == '-' && sc.chNext == '-') {
				sc.SetState(SCE_LUA_COMMENTLINE);
			}  else if (isLuaOperator(static_cast<char>(sc.ch))) {
				sc.SetState(SCE_LUA_OPERATOR);
			}
		}

		if (sc.atLineEnd) {
			// Reset states to begining of colourise so no surprises
			// if different sets of lines lexed.
			chPrevNonWhite = ' ';
			visibleChars = 0;
		}
		if (!IsASpace(sc.ch)) {
			chPrevNonWhite = sc.ch;
			visibleChars++;
		}
	}
	sc.Complete();
}

static void FoldLuaDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[],
                       Accessor &styler) {
	unsigned int lengthDoc = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	int styleNext = styler.StyleAt(startPos);
	char s[10];
	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (style == SCE_LUA_WORD) {
			if ( ch == 'i' || ch == 'e' || ch == 't' || ch == 'd' || ch == 'f') {
				for (unsigned int j = 0; j < 8; j++) {
					if (!iswordchar(styler[i + j]))
						break;
					s[j] = styler[i + j];
					s[j + 1] = '\0';
				}

				if ((strcmp(s, "if") == 0) || (strcmp(s, "do") == 0)
					|| (strcmp(s, "function") == 0))
					levelCurrent++;
				if ((strcmp(s, "end") == 0) || (strcmp(s, "elseif") == 0))
					levelCurrent--;

			}
		}
		else if (style == SCE_LUA_OPERATOR)
		{
			if(ch == '{' || ch == '(')
				levelCurrent++;
			else if(ch == '}' || ch == ')')
				levelCurrent--;
		}

		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later

	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

LexerModule lmLua(SCLEX_LUA, ColouriseLuaDoc, "lua", FoldLuaDoc);
<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexSQL.cxx
 ** Lexer for SQL.
 **/
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static void classifyWordSQL(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) {
	char s[100];
	bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.');
	for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) {
		s[i] = static_cast<char>(toupper(styler[start + i]));
		s[i + 1] = '\0';
	}
	char chAttr = SCE_C_IDENTIFIER;
	if (wordIsNumber)
		chAttr = SCE_C_NUMBER;
	else {
		if (keywords.InList(s))
			chAttr = SCE_C_WORD;
	}
	styler.ColourTo(end, chAttr);
}

static void ColouriseSQLDoc(unsigned int startPos, int length,
                            int initStyle, WordList *keywordlists[], Accessor &styler) {

	WordList &keywords = *keywordlists[0];

	styler.StartAt(startPos);

	bool fold = styler.GetPropertyInt("fold") != 0;
	int lineCurrent = styler.GetLine(startPos);
	int spaceFlags = 0;

	int state = initStyle;
	char chPrev = ' ';
	char chNext = styler[startPos];
	styler.StartSegment(startPos);
	unsigned int lengthDoc = startPos + length;
	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
			int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags);
			int lev = indentCurrent;
			if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
				// Only non whitespace lines can be headers
				int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags);
				if (indentCurrent < (indentNext & ~SC_FOLDLEVELWHITEFLAG)) {
					lev |= SC_FOLDLEVELHEADERFLAG;
				}
			}
			if (fold) {
				styler.SetLevel(lineCurrent, lev);
			}
		}

		if (styler.IsLeadByte(ch)) {
			chNext = styler.SafeGetCharAt(i + 2);
			chPrev = ' ';
			i += 1;
			continue;
		}

		if (state == SCE_C_DEFAULT) {
			if (iswordstart(ch)) {
				styler.ColourTo(i - 1, state);
				state = SCE_C_WORD;
			} else if (ch == '/' && chNext == '*') {
				styler.ColourTo(i - 1, state);
				state = SCE_C_COMMENT;
			} else if (ch == '-' && chNext == '-') {
				styler.ColourTo(i - 1, state);
				state = SCE_C_COMMENTLINE;
			} else if (ch == '\'') {
				styler.ColourTo(i - 1, state);
				state = SCE_C_STRING;
			} else if (isoperator(ch)) {
				styler.ColourTo(i - 1, state);
				styler.ColourTo(i, SCE_C_OPERATOR);
			}
		} else if (state == SCE_C_WORD) {
			if (!iswordchar(ch)) {
				classifyWordSQL(styler.GetStartSegment(), i - 1, keywords, styler);
				state = SCE_C_DEFAULT;
				if (ch == '/' && chNext == '*') {
					state = SCE_C_COMMENT;
				} else if (ch == '-' && chNext == '-') {
					state = SCE_C_COMMENTLINE;
				} else if (ch == '\'') {
					state = SCE_C_STRING;
				} else if (isoperator(ch)) {
					styler.ColourTo(i, SCE_C_OPERATOR);
				}
			}
		} else {
			if (state == SCE_C_COMMENT) {
				if (ch == '/' && chPrev == '*') {
					if (((i > (styler.GetStartSegment() + 2)) || ((initStyle == SCE_C_COMMENT) &&
					    (styler.GetStartSegment() == startPos)))) {
						styler.ColourTo(i, state);
						state = SCE_C_DEFAULT;
					}
				}
			} else if (state == SCE_C_COMMENTLINE) {
				if (ch == '\r' || ch == '\n') {
					styler.ColourTo(i - 1, state);
					state = SCE_C_DEFAULT;
				}
			} else if (state == SCE_C_STRING) {
				if (ch == '\'') {
					if ( chNext == '\'' ) {
						i++;
					} else {
						styler.ColourTo(i, state);
						state = SCE_C_DEFAULT;
						i++;
					}
					ch = chNext;
					chNext = styler.SafeGetCharAt(i + 1);
				}
			}
			if (state == SCE_C_DEFAULT) {    // One of the above succeeded
				if (ch == '/' && chNext == '*') {
					state = SCE_C_COMMENT;
				} else if (ch == '-' && chNext == '-') {
					state = SCE_C_COMMENTLINE;
				} else if (ch == '\'') {
					state = SCE_C_STRING;
				} else if (iswordstart(ch)) {
					state = SCE_C_WORD;
				} else if (isoperator(ch)) {
					styler.ColourTo(i, SCE_C_OPERATOR);
				}
			}
		}
		chPrev = ch;
	}
	styler.ColourTo(lengthDoc - 1, state);
}

static const char * const sqlWordListDesc[] = {
	"Keywords",
	0
};

LexerModule lmSQL(SCLEX_SQL, ColouriseSQLDoc, "sql", 0, sqlWordListDesc);
<commit_msg>Patch from Hiroshi-Saito to allow strings to use ' delimiters.<commit_after>// Scintilla source code edit control
/** @file LexSQL.cxx
 ** Lexer for SQL.
 **/
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static void classifyWordSQL(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) {
	char s[100];
	bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.');
	for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) {
		s[i] = static_cast<char>(toupper(styler[start + i]));
		s[i + 1] = '\0';
	}
	char chAttr = SCE_C_IDENTIFIER;
	if (wordIsNumber)
		chAttr = SCE_C_NUMBER;
	else {
		if (keywords.InList(s))
			chAttr = SCE_C_WORD;
	}
	styler.ColourTo(end, chAttr);
}

static void ColouriseSQLDoc(unsigned int startPos, int length,
                            int initStyle, WordList *keywordlists[], Accessor &styler) {

	WordList &keywords = *keywordlists[0];

	styler.StartAt(startPos);

	bool fold = styler.GetPropertyInt("fold") != 0;
	int lineCurrent = styler.GetLine(startPos);
	int spaceFlags = 0;

	int state = initStyle;
	char chPrev = ' ';
	char chNext = styler[startPos];
	styler.StartSegment(startPos);
	unsigned int lengthDoc = startPos + length;
	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
			int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags);
			int lev = indentCurrent;
			if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
				// Only non whitespace lines can be headers
				int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags);
				if (indentCurrent < (indentNext & ~SC_FOLDLEVELWHITEFLAG)) {
					lev |= SC_FOLDLEVELHEADERFLAG;
				}
			}
			if (fold) {
				styler.SetLevel(lineCurrent, lev);
			}
		}

		if (styler.IsLeadByte(ch)) {
			chNext = styler.SafeGetCharAt(i + 2);
			chPrev = ' ';
			i += 1;
			continue;
		}

		if (state == SCE_C_DEFAULT) {
			if (iswordstart(ch)) {
				styler.ColourTo(i - 1, state);
				state = SCE_C_WORD;
			} else if (ch == '/' && chNext == '*') {
				styler.ColourTo(i - 1, state);
				state = SCE_C_COMMENT;
			} else if (ch == '-' && chNext == '-') {
				styler.ColourTo(i - 1, state);
				state = SCE_C_COMMENTLINE;
			} else if ((ch == '\'') || (ch == '"')) {
				styler.ColourTo(i - 1, state);
				state = SCE_C_STRING;
			} else if (isoperator(ch)) {
				styler.ColourTo(i - 1, state);
				styler.ColourTo(i, SCE_C_OPERATOR);
			}
		} else if (state == SCE_C_WORD) {
			if (!iswordchar(ch)) {
				classifyWordSQL(styler.GetStartSegment(), i - 1, keywords, styler);
				state = SCE_C_DEFAULT;
				if (ch == '/' && chNext == '*') {
					state = SCE_C_COMMENT;
				} else if (ch == '-' && chNext == '-') {
					state = SCE_C_COMMENTLINE;
				} else if ((ch == '\'') || (ch == '"'))  {
					state = SCE_C_STRING;
				} else if (isoperator(ch)) {
					styler.ColourTo(i, SCE_C_OPERATOR);
				}
			}
		} else {
			if (state == SCE_C_COMMENT) {
				if (ch == '/' && chPrev == '*') {
					if (((i > (styler.GetStartSegment() + 2)) || ((initStyle == SCE_C_COMMENT) &&
					    (styler.GetStartSegment() == startPos)))) {
						styler.ColourTo(i, state);
						state = SCE_C_DEFAULT;
					}
				}
			} else if (state == SCE_C_COMMENTLINE) {
				if (ch == '\r' || ch == '\n') {
					styler.ColourTo(i - 1, state);
					state = SCE_C_DEFAULT;
				}
			} else if (state == SCE_C_STRING) {
				if (ch == '\'') {
					if ( chNext == '\'' ) {
						i++;
					} else {
						styler.ColourTo(i, state);
						state = SCE_C_DEFAULT;
						i++;
					}
					ch = chNext;
					chNext = styler.SafeGetCharAt(i + 1);
				} else if (ch == '"') {
					if (chNext == '"') {
						i++;
					} else {
						styler.ColourTo(i, state);
						state = SCE_C_DEFAULT;
						i++;
					}
					ch = chNext;
					chNext = styler.SafeGetCharAt(i + 1);
				}
			}
			if (state == SCE_C_DEFAULT) {    // One of the above succeeded
				if (ch == '/' && chNext == '*') {
					state = SCE_C_COMMENT;
				} else if (ch == '-' && chNext == '-') {
					state = SCE_C_COMMENTLINE;
				} else if ((ch == '\'') || (ch == '"')) {
					state = SCE_C_STRING;
				} else if (iswordstart(ch)) {
					state = SCE_C_WORD;
				} else if (isoperator(ch)) {
					styler.ColourTo(i, SCE_C_OPERATOR);
				}
			}
		}
		chPrev = ch;
	}
	styler.ColourTo(lengthDoc - 1, state);
}

static const char * const sqlWordListDesc[] = {
	"Keywords",
	0
};

LexerModule lmSQL(SCLEX_SQL, ColouriseSQLDoc, "sql", 0, sqlWordListDesc);
<|endoftext|>


<commit_before>
#include <cstring>
#include <string>
#include <SFML/Config.hpp>

extern "C" {
	#include <libavutil/error.h>
}

/** Define portable import / export macros
 */
#if defined(SFML_SYSTEM_WINDOWS) && defined(_MSC_VER)
	#ifdef SFE_EXPORTS
		/** From DLL side, we must export
		 */
		#define SFE_API __declspec(dllexport)
	#else
		/** From client application side, we must import
		 */
		#define SFE_API __declspec(dllimport)
	#endif

	/** For Visual C++ compilers, we also need to turn off this annoying C4251 warning.
	 * You can read lots ot different things about it, but the point is the code will
	 * just work fine, and so the simplest way to get rid of this warning is to disable it
	 */
	#ifdef _MSC_VER
		#pragma warning(disable : 4251)
	#endif
#else
	#define SFE_API
#endif

#define CHECK(value, message) if (!(value)) throw std::runtime_error(message);
#define CHECK0(value, message) CHECK(value == 0, message)
#define ONCE(sequence)\
{ static bool __done = false; if (!__done) { { sequence; } __done = true; } }

#if defined(SFML_SYSTEM_WINDOWS)
	#ifdef av_err2str
	#undef av_err2str
	#endif

	namespace sfe {
		std::string ff_err2str(int code);
	}

	#define av_err2str sfe::ff_err2str
#endif

#ifndef LIBAVCODEC_VERSION
	typedef void *AVFormatContextRef;
	typedef void* AVCodecContextRef;
	typedef void* AVCodecRef;
	typedef void* AVPacketRef;
	typedef void* AVStreamRef;
	typedef void* AVFrameRef;
#else
	typedef AVFormatContext *AVFormatContextRef;
	typedef AVCodecContext* AVCodecContextRef;
	typedef AVCodec* AVCodecRef;
	typedef AVPacket* AVPacketRef;
	typedef AVStream* AVStreamRef;
	typedef AVFrame* AVFrameRef;
#endif
<commit_msg>Fix build error with missing stdexcept include<commit_after>
#include <cstring>
#include <string>
#include <stdexcept>
#include <SFML/Config.hpp>

extern "C" {
	#include <libavutil/error.h>
}

/** Define portable import / export macros
 */
#if defined(SFML_SYSTEM_WINDOWS) && defined(_MSC_VER)
	#ifdef SFE_EXPORTS
		/** From DLL side, we must export
		 */
		#define SFE_API __declspec(dllexport)
	#else
		/** From client application side, we must import
		 */
		#define SFE_API __declspec(dllimport)
	#endif

	/** For Visual C++ compilers, we also need to turn off this annoying C4251 warning.
	 * You can read lots ot different things about it, but the point is the code will
	 * just work fine, and so the simplest way to get rid of this warning is to disable it
	 */
	#ifdef _MSC_VER
		#pragma warning(disable : 4251)
	#endif
#else
	#define SFE_API
#endif

#define CHECK(value, message) if (!(value)) throw std::runtime_error(message);
#define CHECK0(value, message) CHECK(value == 0, message)
#define ONCE(sequence)\
{ static bool __done = false; if (!__done) { { sequence; } __done = true; } }

#if defined(SFML_SYSTEM_WINDOWS)
	#ifdef av_err2str
	#undef av_err2str
	#endif

	namespace sfe {
		std::string ff_err2str(int code);
	}

	#define av_err2str sfe::ff_err2str
#endif

#ifndef LIBAVCODEC_VERSION
	typedef void *AVFormatContextRef;
	typedef void* AVCodecContextRef;
	typedef void* AVCodecRef;
	typedef void* AVPacketRef;
	typedef void* AVStreamRef;
	typedef void* AVFrameRef;
#else
	typedef AVFormatContext *AVFormatContextRef;
	typedef AVCodecContext* AVCodecContextRef;
	typedef AVCodec* AVCodecRef;
	typedef AVPacket* AVPacketRef;
	typedef AVStream* AVStreamRef;
	typedef AVFrame* AVFrameRef;
#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Masayoshi Mizutani <mizutani@sfc.wide.ad.jp>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sstream>
#include <iostream>
#include <msgpack.hpp>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <math.h>
#include <unistd.h>
#include <errno.h>
#include <random>

#include "./fluent/emitter.hpp"
#include "./debug.h"

namespace fluent {
  // ----------------------------------------------------------------
  // Emitter
  Emitter::Emitter() {
  }

  Emitter::~Emitter() {
  }

  bool Emitter::emit(Message *msg) {
    debug(DBG, "emit %p", msg);
    bool rc = this->queue_.push(msg);
    return rc;
  }

  void Emitter::set_queue_limit(size_t limit) {
    this->queue_.set_limit(limit);
  }

  void* Emitter::run_thread(void *obj) {
    Emitter *emitter = static_cast<Emitter*>(obj);
    emitter->worker();
    return NULL;
  }

  void Emitter::start_worker() {
    ::pthread_create(&(this->th_), NULL, Emitter::run_thread, this);
  }
  void Emitter::stop_worker() {
    // ::pthread_cancel(this->th_);
    this->queue_.term();
    ::pthread_join(this->th_, nullptr);
  }

  // ----------------------------------------------------------------
  // InetEmitter
  const int InetEmitter::WAIT_MAX = 30 * 1000;

  InetEmitter::InetEmitter(const std::string &host, int port) :
    Emitter(), retry_limit_(0)
  {
    // Setup socket.
    std::stringstream ss;
    ss << port;
    Init(host, ss.str());
  }
  InetEmitter::InetEmitter(const std::string &host,
                           const std::string &port) :
    Emitter(), retry_limit_(0)
  {
    Init(host, port);
  }
  void InetEmitter::Init(const std::string &host,
						 const std::string &port) {
    // Setup random engine
    mt_rand = std::mt19937(random_device());
    rand_dist = std::uniform_int_distribution<int>(0, INT_MAX);

    // Setup socket.
    this->sock_ = new Socket(host, port);
    this->start_worker();

  }
  InetEmitter::~InetEmitter() {
    this->stop_worker();
    delete this->sock_;
  }

  bool InetEmitter::connect() {
    for (size_t i = 0; this->retry_limit_ == 0 || i < this->retry_limit_;
         i++) {

      if (this->queue_.is_term()) {
        // Going to shutdown.
        return false;
      }

      if (this->sock_->connect()) {
        debug(DBG, "connected");
        return true;
      }
      int wait_msec_max =
        static_cast<int>(pow(2, static_cast<double>(i)) * 1000);
      if (wait_msec_max > WAIT_MAX) {
        wait_msec_max = WAIT_MAX;
      }
      int wait_msec = rand_dist(mt_rand) % wait_msec_max;

      debug(DBG, "reconnect after %d msec...", wait_msec);
      usleep(wait_msec * 1000);
    }

    this->set_errmsg(this->sock_->errmsg());
    delete this->sock_;
    this->sock_ = nullptr;
    return false;
  }

  void InetEmitter::worker() {
    if (!this->sock_->is_connected()) {
      this->connect(); // TODO: handle failure of retry
    }

    Message *root;
    bool abort_loop = false;

    while (nullptr != (root = this->queue_.bulk_pop())) {
      for(Message *msg = root; msg; msg = msg->next()) {
        msgpack::sbuffer buf;
        msgpack::packer <msgpack::sbuffer> pk(&buf);
        msg->to_msgpack(&pk);

        debug(DBG, "sending msg %p", msg);
        while(!this->sock_->send(buf.data(), buf.size())) {
          debug(DBG, "socket error: %s", this->sock_->errmsg().c_str());
          // std::cerr << "socket error: " << this->sock_->errmsg() << std::endl;
          if (!this->connect()) {
            abort_loop = true;
            break;
          }
        }

        if (abort_loop) {
          break;
        }

        debug(false, "sent %p", msg);
      }
      delete root;
    }
  }

  // ----------------------------------------------------------------
  // FileEmitter
  FileEmitter::FileEmitter(const std::string &fname) :
    Emitter(), enabled_(false), opened_(false) {
    // Setup socket.

    this->fd_ = ::open(fname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644);
    if (this->fd_ < 0) {
      this->set_errmsg(strerror(errno));
    } else {
      this->opened_ = true;
      this->enabled_ = true;
      this->start_worker();
    }
  }
  FileEmitter::FileEmitter(int fd) : Emitter(), fd_(fd),
                                     enabled_(false), opened_(false) {
    if (fcntl(fd, F_GETFL) < 0 && errno == EBADF) {
      this->set_errmsg("Invalid file descriptor");
    } else {
      this->enabled_ = true;
      this->start_worker();
    }
  }

  FileEmitter::~FileEmitter() {
    this->stop_worker();
    if (this->enabled_ && this->opened_) {
      ::close(this->fd_);
    }
  }

  void FileEmitter::worker() {
    assert(this->enabled_);

    Message *root;
    while (nullptr != (root = this->queue_.bulk_pop())) {
      for(Message *msg = root; msg; msg = msg->next()) {
        msgpack::sbuffer buf;
        msgpack::packer <msgpack::sbuffer> pk(&buf);
        msg->to_msgpack(&pk);

        int rc = ::write(this->fd_, buf.data(), buf.size());
        if (rc < 0) {
          this->set_errmsg(strerror(errno));
        }
      }
      delete root;
    }
  }

  // ----------------------------------------------------------------
  // FileEmitter
  QueueEmitter::QueueEmitter(MsgQueue *q) : q_(q) {
  }
  QueueEmitter::~QueueEmitter() {
  }
  void QueueEmitter::worker() {
    // nothing to do.
  }
  bool QueueEmitter::emit(Message *msg) {
    return this->q_->push(msg);
  }

}
<commit_msg>skip file descriptor check on windows<commit_after>/*
 * Copyright (c) 2015 Masayoshi Mizutani <mizutani@sfc.wide.ad.jp>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sstream>
#include <iostream>
#include <msgpack.hpp>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <math.h>
#include <unistd.h>
#include <errno.h>
#include <random>

#include "./fluent/emitter.hpp"
#include "./debug.h"

namespace fluent {
  // ----------------------------------------------------------------
  // Emitter
  Emitter::Emitter() {
  }

  Emitter::~Emitter() {
  }

  bool Emitter::emit(Message *msg) {
    debug(DBG, "emit %p", msg);
    bool rc = this->queue_.push(msg);
    return rc;
  }

  void Emitter::set_queue_limit(size_t limit) {
    this->queue_.set_limit(limit);
  }

  void* Emitter::run_thread(void *obj) {
    Emitter *emitter = static_cast<Emitter*>(obj);
    emitter->worker();
    return NULL;
  }

  void Emitter::start_worker() {
    ::pthread_create(&(this->th_), NULL, Emitter::run_thread, this);
  }
  void Emitter::stop_worker() {
    // ::pthread_cancel(this->th_);
    this->queue_.term();
    ::pthread_join(this->th_, nullptr);
  }

  // ----------------------------------------------------------------
  // InetEmitter
  const int InetEmitter::WAIT_MAX = 30 * 1000;

  InetEmitter::InetEmitter(const std::string &host, int port) :
    Emitter(), retry_limit_(0)
  {
    // Setup socket.
    std::stringstream ss;
    ss << port;
    Init(host, ss.str());
  }
  InetEmitter::InetEmitter(const std::string &host,
                           const std::string &port) :
    Emitter(), retry_limit_(0)
  {
    Init(host, port);
  }
  void InetEmitter::Init(const std::string &host,
						 const std::string &port) {
    // Setup random engine
    mt_rand = std::mt19937(random_device());
    rand_dist = std::uniform_int_distribution<int>(0, INT_MAX);

    // Setup socket.
    this->sock_ = new Socket(host, port);
    this->start_worker();

  }
  InetEmitter::~InetEmitter() {
    this->stop_worker();
    delete this->sock_;
  }

  bool InetEmitter::connect() {
    for (size_t i = 0; this->retry_limit_ == 0 || i < this->retry_limit_;
         i++) {

      if (this->queue_.is_term()) {
        // Going to shutdown.
        return false;
      }

      if (this->sock_->connect()) {
        debug(DBG, "connected");
        return true;
      }
      int wait_msec_max =
        static_cast<int>(pow(2, static_cast<double>(i)) * 1000);
      if (wait_msec_max > WAIT_MAX) {
        wait_msec_max = WAIT_MAX;
      }
      int wait_msec = rand_dist(mt_rand) % wait_msec_max;

      debug(DBG, "reconnect after %d msec...", wait_msec);
      usleep(wait_msec * 1000);
    }

    this->set_errmsg(this->sock_->errmsg());
    delete this->sock_;
    this->sock_ = nullptr;
    return false;
  }

  void InetEmitter::worker() {
    if (!this->sock_->is_connected()) {
      this->connect(); // TODO: handle failure of retry
    }

    Message *root;
    bool abort_loop = false;

    while (nullptr != (root = this->queue_.bulk_pop())) {
      for(Message *msg = root; msg; msg = msg->next()) {
        msgpack::sbuffer buf;
        msgpack::packer <msgpack::sbuffer> pk(&buf);
        msg->to_msgpack(&pk);

        debug(DBG, "sending msg %p", msg);
        while(!this->sock_->send(buf.data(), buf.size())) {
          debug(DBG, "socket error: %s", this->sock_->errmsg().c_str());
          // std::cerr << "socket error: " << this->sock_->errmsg() << std::endl;
          if (!this->connect()) {
            abort_loop = true;
            break;
          }
        }

        if (abort_loop) {
          break;
        }

        debug(false, "sent %p", msg);
      }
      delete root;
    }
  }

  // ----------------------------------------------------------------
  // FileEmitter
  FileEmitter::FileEmitter(const std::string &fname) :
    Emitter(), enabled_(false), opened_(false) {
    // Setup socket.

    this->fd_ = ::open(fname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644);
    if (this->fd_ < 0) {
      this->set_errmsg(strerror(errno));
    } else {
      this->opened_ = true;
      this->enabled_ = true;
      this->start_worker();
    }
  }
  FileEmitter::FileEmitter(int fd) : Emitter(), fd_(fd),
                                     enabled_(false), opened_(false) {
#ifndef _WIN32
    if (fcntl(fd, F_GETFL) < 0 && errno == EBADF) {
      this->set_errmsg("Invalid file descriptor");
	} else
#endif
	{
      this->enabled_ = true;
      this->start_worker();
    }
  }

  FileEmitter::~FileEmitter() {
    this->stop_worker();
    if (this->enabled_ && this->opened_) {
      ::close(this->fd_);
    }
  }

  void FileEmitter::worker() {
    assert(this->enabled_);

    Message *root;
    while (nullptr != (root = this->queue_.bulk_pop())) {
      for(Message *msg = root; msg; msg = msg->next()) {
        msgpack::sbuffer buf;
        msgpack::packer <msgpack::sbuffer> pk(&buf);
        msg->to_msgpack(&pk);

        int rc = ::write(this->fd_, buf.data(), buf.size());
        if (rc < 0) {
          this->set_errmsg(strerror(errno));
        }
      }
      delete root;
    }
  }

  // ----------------------------------------------------------------
  // FileEmitter
  QueueEmitter::QueueEmitter(MsgQueue *q) : q_(q) {
  }
  QueueEmitter::~QueueEmitter() {
  }
  void QueueEmitter::worker() {
    // nothing to do.
  }
  bool QueueEmitter::emit(Message *msg) {
    return this->q_->push(msg);
  }

}
<|endoftext|>