<commit_before>#include <blockdb.h>

#include <blockindex.h>
#include <clientversion.h>
#include <pow/pow.h>
#include <primitives/block.h>
#include <streams.h>
#include <util/system.h>

extern RecursiveMutex cs_main;

FlatFileSeq BlockFileSeq() {
    return FlatFileSeq(gArgs.GetBlocksDirPath(), "blk",
                       gArgs.GetBoolArg("-fastprune", false)
                           ? 0x4000 /* 16kb */
                           : BLOCKFILE_CHUNK_SIZE);
}

FlatFileSeq UndoFileSeq() {
    return FlatFileSeq(gArgs.GetBlocksDirPath(), "rev", UNDOFILE_CHUNK_SIZE);
}

FILE *OpenBlockFile(const FlatFilePos &pos, bool fReadOnly) {
    return BlockFileSeq().Open(pos, fReadOnly);
}

/** Open an undo file (rev?????.dat) */
FILE *OpenUndoFile(const FlatFilePos &pos, bool fReadOnly) {
    return UndoFileSeq().Open(pos, fReadOnly);
}

fs::path GetBlockPosFilename(const FlatFilePos &pos) {
    return BlockFileSeq().FileName(pos);
}

bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos,
                       const Consensus::Params &params) {
    block.SetNull();

    // Open history file to read
    CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
    if (filein.IsNull()) {
        return error("ReadBlockFromDisk: OpenBlockFile failed for %s",
                     pos.ToString());
    }

    // Read block
    try {
        filein >> block;
    } catch (const std::exception &e) {
        return error("%s: Deserialize or I/O error - %s at %s", __func__,
                     e.what(), pos.ToString());
    }

    // Check the header
    if (!CheckProofOfWork(block.GetHash(), block.nBits, params)) {
        return error("ReadBlockFromDisk: Errors in block header at %s",
                     pos.ToString());
    }

    return true;
}

bool ReadBlockFromDisk(CBlock &block, const CBlockIndex *pindex,
                       const Consensus::Params &params) {
    FlatFilePos blockPos;
    {
        LOCK(cs_main);
        blockPos = pindex->GetBlockPos();
    }

    if (!ReadBlockFromDisk(block, blockPos, params)) {
        return false;
    }

    if (block.GetHash() != pindex->GetBlockHash()) {
        return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() "
                     "doesn't match index for %s at %s",
                     pindex->ToString(), pindex->GetBlockPos().ToString());
    }

    return true;
}
<commit_msg>add a copyright header in blockdb.cpp<commit_after>// Copyright (c) 2020-2022 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <blockdb.h>

#include <blockindex.h>
#include <clientversion.h>
#include <pow/pow.h>
#include <primitives/block.h>
#include <streams.h>
#include <util/system.h>

extern RecursiveMutex cs_main;

FlatFileSeq BlockFileSeq() {
    return FlatFileSeq(gArgs.GetBlocksDirPath(), "blk",
                       gArgs.GetBoolArg("-fastprune", false)
                           ? 0x4000 /* 16kb */
                           : BLOCKFILE_CHUNK_SIZE);
}

FlatFileSeq UndoFileSeq() {
    return FlatFileSeq(gArgs.GetBlocksDirPath(), "rev", UNDOFILE_CHUNK_SIZE);
}

FILE *OpenBlockFile(const FlatFilePos &pos, bool fReadOnly) {
    return BlockFileSeq().Open(pos, fReadOnly);
}

/** Open an undo file (rev?????.dat) */
FILE *OpenUndoFile(const FlatFilePos &pos, bool fReadOnly) {
    return UndoFileSeq().Open(pos, fReadOnly);
}

fs::path GetBlockPosFilename(const FlatFilePos &pos) {
    return BlockFileSeq().FileName(pos);
}

bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos,
                       const Consensus::Params &params) {
    block.SetNull();

    // Open history file to read
    CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
    if (filein.IsNull()) {
        return error("ReadBlockFromDisk: OpenBlockFile failed for %s",
                     pos.ToString());
    }

    // Read block
    try {
        filein >> block;
    } catch (const std::exception &e) {
        return error("%s: Deserialize or I/O error - %s at %s", __func__,
                     e.what(), pos.ToString());
    }

    // Check the header
    if (!CheckProofOfWork(block.GetHash(), block.nBits, params)) {
        return error("ReadBlockFromDisk: Errors in block header at %s",
                     pos.ToString());
    }

    return true;
}

bool ReadBlockFromDisk(CBlock &block, const CBlockIndex *pindex,
                       const Consensus::Params &params) {
    FlatFilePos blockPos;
    {
        LOCK(cs_main);
        blockPos = pindex->GetBlockPos();
    }

    if (!ReadBlockFromDisk(block, blockPos, params)) {
        return false;
    }

    if (block.GetHash() != pindex->GetBlockHash()) {
        return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() "
                     "doesn't match index for %s at %s",
                     pindex->ToString(), pindex->GetBlockPos().ToString());
    }

    return true;
}
<|endoftext|>


<commit_before>/*
 * Smithsonian Astrophysical Observatory, Cambridge, MA, USA
 * This code has been modified under the terms listed below and is made
 * available under the same terms.
 */

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

#include <math.h>
#include <float.h>
#include <stdlib.h>

#include "bltGraph.h"
#include "bltGrBind.h"
#include "bltGrElem.h"
#include "bltGrPen.h"

using namespace Blt;

// Class ElemValues

ElemValues::ElemValues()
{
  values_ =NULL;
  nValues_ =0;
  min_ =0;
  max_ =0;
}

ElemValues::~ElemValues()
{
  if (values_)
    delete [] values_;
}

void ElemValues::reset()
{
  if (values_)
    delete [] values_;
  values_ =NULL;
  nValues_ =0;
  min_ =0;
  max_ =0;
}

ElemValuesSource::ElemValuesSource(int nn) : ElemValues()
{
  nValues_ = nn;
  values_ = new double[nn];
}

ElemValuesSource::ElemValuesSource(int nn, double* vv) : ElemValues()
{
  nValues_ = nn;
  values_ = vv;
}

ElemValuesSource::~ElemValuesSource()
{
}

void ElemValuesSource::findRange()
{
  if (nValues_<1 || !values_)
    return;

  min_ = DBL_MAX;
  max_ = -DBL_MAX;
  for (int ii=0; ii<nValues_; ii++) {
    if (isfinite(values_[ii])) {
      if (values_[ii] < min_)
	min_ = values_[ii];
      if (values_[ii] > max_)
	max_ = values_[ii];
    }
  }
}

ElemValuesVector::ElemValuesVector(Element* ptr, const char* vecName)
  : ElemValues()
{
  elemPtr_ = ptr;
  Graph* graphPtr = elemPtr_->graphPtr_;
  source_ = Blt_AllocVectorId(graphPtr->interp_, vecName);
}

ElemValuesVector::~ElemValuesVector()
{
  freeSource();
}

int ElemValuesVector::getVector()
{
  Graph* graphPtr = elemPtr_->graphPtr_;

  Blt_Vector *vecPtr;
  if (Blt_GetVectorById(graphPtr->interp_, source_, &vecPtr) != TCL_OK)
    return TCL_ERROR;

  if (fetchValues(vecPtr) != TCL_OK) {
    freeSource();
    return TCL_ERROR;
  }

  Blt_SetVectorChangedProc(source_, VectorChangedProc, this);
  return TCL_OK;
}

int ElemValuesVector::fetchValues(Blt_Vector* vector)
{
  Graph* graphPtr = elemPtr_->graphPtr_;

  if (values_)
    delete [] values_;
  values_ = NULL;
  nValues_ = 0;
  min_ =0;
  max_ =0;

  int ss = Blt_VecLength(vector);
  if (!ss)
    return TCL_OK;

  double* array = new double[ss];
  if (!array) {
    Tcl_AppendResult(graphPtr->interp_, "can't allocate new vector", NULL);
    return TCL_ERROR;
  }

  memcpy(array, Blt_VecData(vector), ss*sizeof(double));
  values_ = array;
  nValues_ = Blt_VecLength(vector);
  min_ = Blt_VecMin(vector);
  max_ = Blt_VecMax(vector);

  return TCL_OK;
}

void ElemValuesVector::freeSource()
{
  if (source_) {
    Blt_SetVectorChangedProc(source_, NULL, NULL);
    Blt_FreeVectorId(source_);
    source_ = NULL;
  }
}

// Class Element

Element::Element(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr)
{
  graphPtr_ = graphPtr;
  name_ = dupstr(name);
  optionTable_ =NULL;
  ops_ =NULL;
  hashPtr_ = hPtr;

  row_ =0;
  col_ =0;
  activeIndices_ =NULL;
  nActiveIndices_ =0;
  xRange_ =0;
  yRange_ =0;
  active_ =0;
  labelActive_ =0;

  link =NULL;
}

Element::~Element()
{
  graphPtr_->bindTable_->deleteBindings(this);

  if (link)
    Blt_Chain_DeleteLink(graphPtr_->elements_.displayList, link);

  if (hashPtr_)
    Tcl_DeleteHashEntry(hashPtr_);

  if (name_)
    delete [] name_;

  if (activeIndices_)
    delete [] activeIndices_;

  Tk_FreeConfigOptions((char*)ops_, optionTable_, graphPtr_->tkwin_);
  free(ops_);
}

double Element::FindElemValuesMinimum(ElemValues* valuesPtr, double minLimit)
{
  double min = DBL_MAX;
  if (!valuesPtr)
    return min;

  for (int ii=0; ii<valuesPtr->nValues(); ii++) {
    double x = valuesPtr->values_[ii];
    // What do you do about negative values when using log
    // scale values seems like a grey area. Mirror.
    if (x < 0.0)
      x = -x;
    if ((x > minLimit) && (min > x))
      min = x;
  }
  if (min == DBL_MAX)
    min = minLimit;

  return min;
}

PenStyle** Element::StyleMap()
{
  ElementOptions* ops = (ElementOptions*)ops_;

  int nPoints = NUMBEROFPOINTS(ops);
  int nWeights = MIN(ops->w ? ops->w->nValues() : 0, nPoints);
  double* w = ops->w ? ops->w->values_ : NULL;
  Blt_ChainLink link = Blt_Chain_FirstLink(ops->stylePalette);
  PenStyle* stylePtr = (PenStyle*)Blt_Chain_GetValue(link);

  // Create a style mapping array (data point index to style),
  // initialized to the default style.
  PenStyle** dataToStyle = new PenStyle*[nPoints];
  for (int ii=0; ii<nPoints; ii++)
    dataToStyle[ii] = stylePtr;

  for (int ii=0; ii<nWeights; ii++) {
    for (link=Blt_Chain_LastLink(ops->stylePalette); link;
	 link=Blt_Chain_PrevLink(link)) {
      stylePtr = (PenStyle*)Blt_Chain_GetValue(link);

      if (stylePtr->weight.range > 0.0) {
	double norm = (w[ii] - stylePtr->weight.min) / stylePtr->weight.range;
	if (((norm - 1.0) <= DBL_EPSILON) &&
	    (((1.0 - norm) - 1.0) <= DBL_EPSILON)) {
	  dataToStyle[ii] = stylePtr;
	  break;
	}
      }
    }
  }

  return dataToStyle;
}

void Element::freeStylePalette(Blt_Chain stylePalette)
{
  // Skip the first slot. It contains the built-in "normal" pen of the element
  Blt_ChainLink link = Blt_Chain_FirstLink(stylePalette);
  if (link) {
    Blt_ChainLink next;
    for (link=Blt_Chain_NextLink(link); link; link=next) {
      next = Blt_Chain_NextLink(link);
      PenStyle *stylePtr = (PenStyle*)Blt_Chain_GetValue(link);
      Pen* penPtr = stylePtr->penPtr;
      if (penPtr) {
	penPtr->refCount_--;
	if (penPtr->refCount_ == 0)
	  delete penPtr;
      }
      Blt_Chain_DeleteLink(stylePalette, link);
    }
  }
}

<commit_msg>*** empty log message ***<commit_after>/*
 * Smithsonian Astrophysical Observatory, Cambridge, MA, USA
 * This code has been modified under the terms listed below and is made
 * available under the same terms.
 */

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

#include <math.h>
#include <float.h>
#include <stdlib.h>
#include <string.h>

#include "bltGraph.h"
#include "bltGrBind.h"
#include "bltGrElem.h"
#include "bltGrPen.h"

using namespace Blt;

// Class ElemValues

ElemValues::ElemValues()
{
  values_ =NULL;
  nValues_ =0;
  min_ =0;
  max_ =0;
}

ElemValues::~ElemValues()
{
  if (values_)
    delete [] values_;
}

void ElemValues::reset()
{
  if (values_)
    delete [] values_;
  values_ =NULL;
  nValues_ =0;
  min_ =0;
  max_ =0;
}

ElemValuesSource::ElemValuesSource(int nn) : ElemValues()
{
  nValues_ = nn;
  values_ = new double[nn];
}

ElemValuesSource::ElemValuesSource(int nn, double* vv) : ElemValues()
{
  nValues_ = nn;
  values_ = vv;
}

ElemValuesSource::~ElemValuesSource()
{
}

void ElemValuesSource::findRange()
{
  if (nValues_<1 || !values_)
    return;

  min_ = DBL_MAX;
  max_ = -DBL_MAX;
  for (int ii=0; ii<nValues_; ii++) {
    if (isfinite(values_[ii])) {
      if (values_[ii] < min_)
	min_ = values_[ii];
      if (values_[ii] > max_)
	max_ = values_[ii];
    }
  }
}

ElemValuesVector::ElemValuesVector(Element* ptr, const char* vecName)
  : ElemValues()
{
  elemPtr_ = ptr;
  Graph* graphPtr = elemPtr_->graphPtr_;
  source_ = Blt_AllocVectorId(graphPtr->interp_, vecName);
}

ElemValuesVector::~ElemValuesVector()
{
  freeSource();
}

int ElemValuesVector::getVector()
{
  Graph* graphPtr = elemPtr_->graphPtr_;

  Blt_Vector *vecPtr;
  if (Blt_GetVectorById(graphPtr->interp_, source_, &vecPtr) != TCL_OK)
    return TCL_ERROR;

  if (fetchValues(vecPtr) != TCL_OK) {
    freeSource();
    return TCL_ERROR;
  }

  Blt_SetVectorChangedProc(source_, VectorChangedProc, this);
  return TCL_OK;
}

int ElemValuesVector::fetchValues(Blt_Vector* vector)
{
  Graph* graphPtr = elemPtr_->graphPtr_;

  if (values_)
    delete [] values_;
  values_ = NULL;
  nValues_ = 0;
  min_ =0;
  max_ =0;

  int ss = Blt_VecLength(vector);
  if (!ss)
    return TCL_OK;

  double* array = new double[ss];
  if (!array) {
    Tcl_AppendResult(graphPtr->interp_, "can't allocate new vector", NULL);
    return TCL_ERROR;
  }

  memcpy(array, Blt_VecData(vector), ss*sizeof(double));
  values_ = array;
  nValues_ = Blt_VecLength(vector);
  min_ = Blt_VecMin(vector);
  max_ = Blt_VecMax(vector);

  return TCL_OK;
}

void ElemValuesVector::freeSource()
{
  if (source_) {
    Blt_SetVectorChangedProc(source_, NULL, NULL);
    Blt_FreeVectorId(source_);
    source_ = NULL;
  }
}

// Class Element

Element::Element(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr)
{
  graphPtr_ = graphPtr;
  name_ = dupstr(name);
  optionTable_ =NULL;
  ops_ =NULL;
  hashPtr_ = hPtr;

  row_ =0;
  col_ =0;
  activeIndices_ =NULL;
  nActiveIndices_ =0;
  xRange_ =0;
  yRange_ =0;
  active_ =0;
  labelActive_ =0;

  link =NULL;
}

Element::~Element()
{
  graphPtr_->bindTable_->deleteBindings(this);

  if (link)
    Blt_Chain_DeleteLink(graphPtr_->elements_.displayList, link);

  if (hashPtr_)
    Tcl_DeleteHashEntry(hashPtr_);

  if (name_)
    delete [] name_;

  if (activeIndices_)
    delete [] activeIndices_;

  Tk_FreeConfigOptions((char*)ops_, optionTable_, graphPtr_->tkwin_);
  free(ops_);
}

double Element::FindElemValuesMinimum(ElemValues* valuesPtr, double minLimit)
{
  double min = DBL_MAX;
  if (!valuesPtr)
    return min;

  for (int ii=0; ii<valuesPtr->nValues(); ii++) {
    double x = valuesPtr->values_[ii];
    // What do you do about negative values when using log
    // scale values seems like a grey area. Mirror.
    if (x < 0.0)
      x = -x;
    if ((x > minLimit) && (min > x))
      min = x;
  }
  if (min == DBL_MAX)
    min = minLimit;

  return min;
}

PenStyle** Element::StyleMap()
{
  ElementOptions* ops = (ElementOptions*)ops_;

  int nPoints = NUMBEROFPOINTS(ops);
  int nWeights = MIN(ops->w ? ops->w->nValues() : 0, nPoints);
  double* w = ops->w ? ops->w->values_ : NULL;
  Blt_ChainLink link = Blt_Chain_FirstLink(ops->stylePalette);
  PenStyle* stylePtr = (PenStyle*)Blt_Chain_GetValue(link);

  // Create a style mapping array (data point index to style),
  // initialized to the default style.
  PenStyle** dataToStyle = new PenStyle*[nPoints];
  for (int ii=0; ii<nPoints; ii++)
    dataToStyle[ii] = stylePtr;

  for (int ii=0; ii<nWeights; ii++) {
    for (link=Blt_Chain_LastLink(ops->stylePalette); link;
	 link=Blt_Chain_PrevLink(link)) {
      stylePtr = (PenStyle*)Blt_Chain_GetValue(link);

      if (stylePtr->weight.range > 0.0) {
	double norm = (w[ii] - stylePtr->weight.min) / stylePtr->weight.range;
	if (((norm - 1.0) <= DBL_EPSILON) &&
	    (((1.0 - norm) - 1.0) <= DBL_EPSILON)) {
	  dataToStyle[ii] = stylePtr;
	  break;
	}
      }
    }
  }

  return dataToStyle;
}

void Element::freeStylePalette(Blt_Chain stylePalette)
{
  // Skip the first slot. It contains the built-in "normal" pen of the element
  Blt_ChainLink link = Blt_Chain_FirstLink(stylePalette);
  if (link) {
    Blt_ChainLink next;
    for (link=Blt_Chain_NextLink(link); link; link=next) {
      next = Blt_Chain_NextLink(link);
      PenStyle *stylePtr = (PenStyle*)Blt_Chain_GetValue(link);
      Pen* penPtr = stylePtr->penPtr;
      if (penPtr) {
	penPtr->refCount_--;
	if (penPtr->refCount_ == 0)
	  delete penPtr;
      }
      Blt_Chain_DeleteLink(stylePalette, link);
    }
  }
}

<|endoftext|>


<commit_before>#include "stdafx.h"
#include <d3d9.h>

// Mod loader
#include <SADXModLoader.h>
#include <Trampoline.h>

// Local
#include "d3d.h"
#include "datapointers.h"
#include "fog.h"
#include "globals.h"
#include "lantern.h"

enum RenderFlags
{
	EnvironmentMap   = 0x1,
	ConstantMaterial = 0x2,
	OffsetMaterial   = 0x4,
	RenderFlags_8    = 0x8,
	RenderFlags_10   = 0x10,
};

static Trampoline* CharSel_LoadA_t          = nullptr;
static Trampoline* Direct3D_ParseMaterial_t = nullptr;
static Trampoline* GoToNextLevel_t          = nullptr;
static Trampoline* IncrementAct_t           = nullptr;
static Trampoline* LoadLevelFiles_t         = nullptr;
static Trampoline* SetLevelAndAct_t         = nullptr;
static Trampoline* SetTimeOfDay_t           = nullptr;
static Trampoline* DrawLandTable_t          = nullptr;

DataArray(PaletteLight, LightPaletteData, 0x00903E88, 256);
DataArray(StageLightData, CurrentStageLights, 0x03ABD9F8, 4);

DataPointer(EntityData1*, Camera_Data1, 0x03B2CBB0);
DataPointer(NJS_COLOR, EntityVertexColor, 0x03D0848C);
DataPointer(NJS_COLOR, LandTableVertexColor, 0x03D08494);
DataPointer(PaletteLight, LSPalette, 0x03ABDAF0);
DataPointer(Uint32, LastRenderFlags, 0x03D08498);

static void DisplayLightDirection()
{
#ifdef _DEBUG
	using namespace globals;

	auto player = CharObj1Ptrs[0];
	if (player == nullptr)
		return;

	NJS_POINT3 points[2] = {
		player->Position,
		{}
	};

	int colors[2] = {};

	LineInfo info = {
		points, colors, 0, 2
	};

	points[1] = points[0];
	points[1].x += light_dir.x * 10.0f;
	colors[0] = colors[1] = 0xFFFF0000;
	DrawLineList(&info, 1, 0);

	points[1] = points[0];
	points[1].y += light_dir.y * 10.0f;
	colors[0] = colors[1] = 0xFF00FF00;
	DrawLineList(&info, 1, 0);

	points[1] = points[0];
	points[1].z += light_dir.z * 10.0f;
	colors[0] = colors[1] = 0xFF0000FF;
	DrawLineList(&info, 1, 0);

	points[1] = points[0];
	points[1].x += light_dir.x * 10.0f;
	points[1].y += light_dir.y * 10.0f;
	points[1].z += light_dir.z * 10.0f;
	colors[0] = colors[1] = 0xFFFFFF00;
	DrawLineList(&info, 1, 0);
#endif
}

static void SetMaterialParameters(const D3DMATERIAL9& material)
{
	using namespace d3d;

	if (!UsePalette() || effect == nullptr)
		return;

	// This will need to be re-evaluated for chunk models.
	//D3DMATERIALCOLORSOURCE colorsource;
	//device->GetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, (DWORD*)&colorsource);
	//effect->SetInt(param::DiffuseSource, colorsource);
	effect->SetVector(param::MaterialDiffuse, (D3DXVECTOR4*)&material.Diffuse);
}

static void __cdecl CorrectMaterial_r()
{
	using namespace d3d;
	D3DMATERIAL9 material; // [sp+8h] [bp-44h]@1

	device->GetMaterial(&material);
	material.Power = LSPalette.SP_pow;

	material.Ambient.r  /= 255.0f;
	material.Ambient.g  /= 255.0f;
	material.Ambient.b  /= 255.0f;
	material.Ambient.a  /= 255.0f;
	material.Diffuse.r  /= 255.0f;
	material.Diffuse.g  /= 255.0f;
	material.Diffuse.b  /= 255.0f;
	material.Diffuse.a  /= 255.0f;
	material.Specular.r /= 255.0f;
	material.Specular.g /= 255.0f;
	material.Specular.b /= 255.0f;
	material.Specular.a /= 255.0f;

	SetMaterialParameters(material);
	device->SetMaterial(&material);
}

static Uint32 last_flags = 0;
static Uint32 last_texid = 0xFFFFFFFF;
static NJS_TEXLIST* last_texlist = nullptr;

static void __fastcall Direct3D_ParseMaterial_r(NJS_MATERIAL* material)
{
	using namespace d3d;

	TARGET_DYNAMIC(Direct3D_ParseMaterial)(material);

	if (effect == nullptr)
		return;

	do_effect = false;

	auto pad = ControllerPointers[0];
	if (!UsePalette() || pad && pad->HeldButtons & Buttons_Z)
		return;

	Uint32 flags = material->attrflags;
	Uint32 texid = material->attr_texId & 0xFFFF;

	if (_nj_control_3d_flag_ & NJD_CONTROL_3D_CONSTANT_ATTR)
	{
		flags = _nj_constant_attr_or_ | _nj_constant_attr_and_ & flags;
	}

	globals::light = (flags & NJD_FLAG_IGNORE_LIGHT) == 0;

	if ((last_flags & NJD_FLAG_USE_ENV) != (flags & NJD_FLAG_USE_ENV))
	{
		effect->SetBool(param::EnvironmentMapped, (flags & NJD_FLAG_USE_ENV) != 0);
	}

	if ((last_flags & NJD_FLAG_USE_ALPHA) != (flags & NJD_FLAG_USE_ALPHA))
	{
		effect->SetBool(param::AlphaEnabled, (flags & NJD_FLAG_USE_ALPHA) != 0);
	}

	if (!globals::no_specular)
	{
		SetPaletteLights(globals::light_type, flags);
	}

	bool new_texture = Direct3D_CurrentTexList != last_texlist || texid != last_texid;
	if (new_texture)
	{
		last_texlist = Direct3D_CurrentTexList;

		bool use_texture = (flags & NJD_FLAG_USE_TEXTURE) != 0;
		effect->SetBool(param::TextureEnabled, use_texture);

		if (use_texture)
		{
			last_texid = texid;

			auto textures = Direct3D_CurrentTexList->textures;
			NJS_TEXMEMLIST* texmem = textures ? (NJS_TEXMEMLIST*)textures[texid].texaddr : nullptr;
			if (texmem != nullptr)
			{
				auto texture = (Direct3DTexture8*)texmem->texinfo.texsurface.pSurface;
				if (texture != nullptr)
				{
					effect->SetTexture(param::BaseTexture, texture->GetProxyInterface());
				}
			}
		}
		else if ((last_flags & NJD_FLAG_USE_TEXTURE) != (flags & NJD_FLAG_USE_TEXTURE))
		{
			effect->SetTexture(param::BaseTexture, nullptr);
		}

		D3DMATERIAL9 mat;
		device->GetMaterial(&mat);
		SetMaterialParameters(mat);
	}

	last_flags = flags;

	do_effect = true;
}

static void __cdecl CharSel_LoadA_r()
{
	auto original = TARGET_DYNAMIC(CharSel_LoadA);

	NJS_VECTOR dir = { 1.0f, -1.0f, -1.0f };

	njUnitVector(&dir);
	UpdateLightDirections(dir);

	LoadLanternPalette(LevelIDs_SkyDeck, 0);

	globals::last_level = CurrentLevel;
	globals::last_act = CurrentAct;

	original();
}

static void __cdecl SetLevelAndAct_r(Uint8 level, Uint8 act)
{
	TARGET_DYNAMIC(SetLevelAndAct)(level, act);
	LoadLanternFiles();
}

static void __cdecl GoToNextLevel_r()
{
	TARGET_DYNAMIC(GoToNextLevel)();
	LoadLanternFiles();
}

static void __cdecl IncrementAct_r(int amount)
{
	TARGET_DYNAMIC(IncrementAct)(amount);

	if (amount != 0)
	{
		LoadLanternFiles();
	}
}

static void __cdecl SetTimeOfDay_r(Sint8 time)
{
	TARGET_DYNAMIC(SetTimeOfDay)(time);
	LoadLanternFiles();
}

static void __cdecl LoadLevelFiles_r()
{
	TARGET_DYNAMIC(LoadLevelFiles)();
	LoadLanternFiles();
}

static void __cdecl DrawLandTable_r()
{
	auto flag = _nj_control_3d_flag_;
	auto or = _nj_constant_attr_or_;

	_nj_control_3d_flag_ |= NJD_CONTROL_3D_CONSTANT_ATTR;
	_nj_constant_attr_or_ |= NJD_FLAG_IGNORE_SPECULAR;

	TARGET_DYNAMIC(DrawLandTable)();

	_nj_control_3d_flag_ = flag;
	_nj_constant_attr_or_ = or;
}

extern "C"
{
	EXPORT ModInfo SADXModInfo = { ModLoaderVer };
	EXPORT void __cdecl Init(const char *path)
	{
		auto handle = GetModuleHandle(L"d3d9.dll");
		if (handle == nullptr)
		{
			MessageBoxA(WindowHandle, "Unable to detect Direct3D 9 DLL. The mod will not function.",
				"D3D9 not loaded", MB_OK | MB_ICONERROR);
			return;
		}

		globals::system = path;
		globals::system.append("\\system\\");

		d3d::InitTrampolines();
		CharSel_LoadA_t          = new Trampoline(0x00512BC0, 0x00512BC6, CharSel_LoadA_r);
		Direct3D_ParseMaterial_t = new Trampoline(0x00784850, 0x00784858, Direct3D_ParseMaterial_r);
		GoToNextLevel_t          = new Trampoline(0x00414610, 0x00414616, GoToNextLevel_r);
		IncrementAct_t           = new Trampoline(0x004146E0, 0x004146E5, IncrementAct_r);
		LoadLevelFiles_t         = new Trampoline(0x00422AD0, 0x00422AD8, LoadLevelFiles_r);
		SetLevelAndAct_t         = new Trampoline(0x00414570, 0x00414576, SetLevelAndAct_r);
		SetTimeOfDay_t           = new Trampoline(0x00412C00, 0x00412C05, SetTimeOfDay_r);
		DrawLandTable_t          = new Trampoline(0x0043A6A0, 0x0043A6A8, DrawLandTable_r);

		// Correcting a function call since they're relative
		WriteCall(IncrementAct_t->Target(), (void*)0x00424830);

		// Material callback hijack
		WriteJump((void*)0x0040A340, CorrectMaterial_r);
	}

	EXPORT void __cdecl OnFrame()
	{
		auto pad = ControllerPointers[0];
		if (pad)
		{
			auto pressed = pad->PressedButtons;
			if (pressed & Buttons_C)
			{
				d3d::LoadShader();
				SetFogParameters();
			}

			if (pressed & Buttons_Left)
			{
				LoadLanternPalette(globals::system + "diffuse test.bin");
			}
			else if (pressed & Buttons_Right)
			{
				LoadLanternPalette(globals::system + "specular test.bin");
			}
		}

		if (d3d::effect == nullptr)
			return;

		DisplayLightDirection();
	}

	EXPORT void __cdecl OnRenderDeviceLost()
	{
		if (d3d::effect != nullptr)
		{
			d3d::effect->OnLostDevice();
			d3d::UpdateParameterHandles();
		}
	}

	EXPORT void __cdecl OnRenderDeviceReset()
	{
		if (d3d::effect != nullptr)
		{
			d3d::effect->OnResetDevice();
			d3d::UpdateParameterHandles();
			SetFogParameters();
		}
	}
}
<commit_msg>this is what I get for trying to be efficient<commit_after>#include "stdafx.h"
#include <d3d9.h>

// Mod loader
#include <SADXModLoader.h>
#include <Trampoline.h>

// Local
#include "d3d.h"
#include "datapointers.h"
#include "fog.h"
#include "globals.h"
#include "lantern.h"

enum RenderFlags
{
	EnvironmentMap   = 0x1,
	ConstantMaterial = 0x2,
	OffsetMaterial   = 0x4,
	RenderFlags_8    = 0x8,
	RenderFlags_10   = 0x10,
};

static Trampoline* CharSel_LoadA_t          = nullptr;
static Trampoline* Direct3D_ParseMaterial_t = nullptr;
static Trampoline* GoToNextLevel_t          = nullptr;
static Trampoline* IncrementAct_t           = nullptr;
static Trampoline* LoadLevelFiles_t         = nullptr;
static Trampoline* SetLevelAndAct_t         = nullptr;
static Trampoline* SetTimeOfDay_t           = nullptr;
static Trampoline* DrawLandTable_t          = nullptr;

DataArray(PaletteLight, LightPaletteData, 0x00903E88, 256);
DataArray(StageLightData, CurrentStageLights, 0x03ABD9F8, 4);

DataPointer(EntityData1*, Camera_Data1, 0x03B2CBB0);
DataPointer(NJS_COLOR, EntityVertexColor, 0x03D0848C);
DataPointer(NJS_COLOR, LandTableVertexColor, 0x03D08494);
DataPointer(PaletteLight, LSPalette, 0x03ABDAF0);
DataPointer(Uint32, LastRenderFlags, 0x03D08498);

static void DisplayLightDirection()
{
#ifdef _DEBUG
	using namespace globals;

	auto player = CharObj1Ptrs[0];
	if (player == nullptr)
		return;

	NJS_POINT3 points[2] = {
		player->Position,
		{}
	};

	int colors[2] = {};

	LineInfo info = {
		points, colors, 0, 2
	};

	points[1] = points[0];
	points[1].x += light_dir.x * 10.0f;
	colors[0] = colors[1] = 0xFFFF0000;
	DrawLineList(&info, 1, 0);

	points[1] = points[0];
	points[1].y += light_dir.y * 10.0f;
	colors[0] = colors[1] = 0xFF00FF00;
	DrawLineList(&info, 1, 0);

	points[1] = points[0];
	points[1].z += light_dir.z * 10.0f;
	colors[0] = colors[1] = 0xFF0000FF;
	DrawLineList(&info, 1, 0);

	points[1] = points[0];
	points[1].x += light_dir.x * 10.0f;
	points[1].y += light_dir.y * 10.0f;
	points[1].z += light_dir.z * 10.0f;
	colors[0] = colors[1] = 0xFFFFFF00;
	DrawLineList(&info, 1, 0);
#endif
}

static void SetMaterialParameters(const D3DMATERIAL9& material)
{
	using namespace d3d;

	if (!UsePalette() || effect == nullptr)
		return;

	// This will need to be re-evaluated for chunk models.
	//D3DMATERIALCOLORSOURCE colorsource;
	//device->GetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, (DWORD*)&colorsource);
	//effect->SetInt(param::DiffuseSource, colorsource);
	effect->SetVector(param::MaterialDiffuse, (D3DXVECTOR4*)&material.Diffuse);
}

static void __cdecl CorrectMaterial_r()
{
	using namespace d3d;
	D3DMATERIAL9 material; // [sp+8h] [bp-44h]@1

	device->GetMaterial(&material);
	material.Power = LSPalette.SP_pow;

	material.Ambient.r  /= 255.0f;
	material.Ambient.g  /= 255.0f;
	material.Ambient.b  /= 255.0f;
	material.Ambient.a  /= 255.0f;
	material.Diffuse.r  /= 255.0f;
	material.Diffuse.g  /= 255.0f;
	material.Diffuse.b  /= 255.0f;
	material.Diffuse.a  /= 255.0f;
	material.Specular.r /= 255.0f;
	material.Specular.g /= 255.0f;
	material.Specular.b /= 255.0f;
	material.Specular.a /= 255.0f;

	SetMaterialParameters(material);
	device->SetMaterial(&material);
}

static Uint32 last_flags = 0;
static Uint32 last_texid = 0xFFFFFFFF;
static NJS_TEXLIST* last_texlist = nullptr;

static void __fastcall Direct3D_ParseMaterial_r(NJS_MATERIAL* material)
{
	using namespace d3d;

	TARGET_DYNAMIC(Direct3D_ParseMaterial)(material);

	if (effect == nullptr)
		return;

	do_effect = false;

	auto pad = ControllerPointers[0];
	if (!UsePalette() || pad && pad->HeldButtons & Buttons_Z)
		return;

	Uint32 flags = material->attrflags;
	Uint32 texid = material->attr_texId & 0xFFFF;
	bool use_texture = (flags & NJD_FLAG_USE_TEXTURE) != 0;

	if (_nj_control_3d_flag_ & NJD_CONTROL_3D_CONSTANT_ATTR)
	{
		flags = _nj_constant_attr_or_ | _nj_constant_attr_and_ & flags;
	}

	globals::light = (flags & NJD_FLAG_IGNORE_LIGHT) == 0;

	if (!globals::no_specular)
	{
		SetPaletteLights(globals::light_type, flags);
	}

	if ((last_flags & NJD_FLAG_USE_ENV) != (flags & NJD_FLAG_USE_ENV))
	{
		effect->SetBool(param::EnvironmentMapped, (flags & NJD_FLAG_USE_ENV) != 0);
	}

	if ((last_flags & NJD_FLAG_USE_ALPHA) != (flags & NJD_FLAG_USE_ALPHA))
	{
		effect->SetBool(param::AlphaEnabled, (flags & NJD_FLAG_USE_ALPHA) != 0);
	}

	if ((last_flags & NJD_FLAG_USE_TEXTURE) != (flags & NJD_FLAG_USE_TEXTURE))
	{
		effect->SetBool(param::TextureEnabled, use_texture);
	}

	if (use_texture && (Direct3D_CurrentTexList != last_texlist || texid != last_texid))
	{
		auto textures = Direct3D_CurrentTexList->textures;
		NJS_TEXMEMLIST* texmem = textures ? (NJS_TEXMEMLIST*)textures[texid].texaddr : nullptr;
		if (texmem != nullptr)
		{
			auto texture = (Direct3DTexture8*)texmem->texinfo.texsurface.pSurface;
			if (texture != nullptr)
			{
				last_texlist = Direct3D_CurrentTexList;
				last_texid = texid;
				effect->SetTexture(param::BaseTexture, texture->GetProxyInterface());
			}
		}
	}

	D3DMATERIAL9 mat;
	device->GetMaterial(&mat);
	SetMaterialParameters(mat);

	last_flags = flags;
	do_effect = true;
}

static void __cdecl CharSel_LoadA_r()
{
	auto original = TARGET_DYNAMIC(CharSel_LoadA);

	NJS_VECTOR dir = { 1.0f, -1.0f, -1.0f };

	njUnitVector(&dir);
	UpdateLightDirections(dir);

	LoadLanternPalette(LevelIDs_SkyDeck, 0);

	globals::last_level = CurrentLevel;
	globals::last_act = CurrentAct;

	original();
}

static void __cdecl SetLevelAndAct_r(Uint8 level, Uint8 act)
{
	TARGET_DYNAMIC(SetLevelAndAct)(level, act);
	LoadLanternFiles();
}

static void __cdecl GoToNextLevel_r()
{
	TARGET_DYNAMIC(GoToNextLevel)();
	LoadLanternFiles();
}

static void __cdecl IncrementAct_r(int amount)
{
	TARGET_DYNAMIC(IncrementAct)(amount);

	if (amount != 0)
	{
		LoadLanternFiles();
	}
}

static void __cdecl SetTimeOfDay_r(Sint8 time)
{
	TARGET_DYNAMIC(SetTimeOfDay)(time);
	LoadLanternFiles();
}

static void __cdecl LoadLevelFiles_r()
{
	TARGET_DYNAMIC(LoadLevelFiles)();
	LoadLanternFiles();
}

static void __cdecl DrawLandTable_r()
{
	auto flag = _nj_control_3d_flag_;
	auto or = _nj_constant_attr_or_;

	_nj_control_3d_flag_ |= NJD_CONTROL_3D_CONSTANT_ATTR;
	_nj_constant_attr_or_ |= NJD_FLAG_IGNORE_SPECULAR;

	TARGET_DYNAMIC(DrawLandTable)();

	_nj_control_3d_flag_ = flag;
	_nj_constant_attr_or_ = or;
}

extern "C"
{
	EXPORT ModInfo SADXModInfo = { ModLoaderVer };
	EXPORT void __cdecl Init(const char *path)
	{
		auto handle = GetModuleHandle(L"d3d9.dll");
		if (handle == nullptr)
		{
			MessageBoxA(WindowHandle, "Unable to detect Direct3D 9 DLL. The mod will not function.",
				"D3D9 not loaded", MB_OK | MB_ICONERROR);
			return;
		}

		globals::system = path;
		globals::system.append("\\system\\");

		d3d::InitTrampolines();
		CharSel_LoadA_t          = new Trampoline(0x00512BC0, 0x00512BC6, CharSel_LoadA_r);
		Direct3D_ParseMaterial_t = new Trampoline(0x00784850, 0x00784858, Direct3D_ParseMaterial_r);
		GoToNextLevel_t          = new Trampoline(0x00414610, 0x00414616, GoToNextLevel_r);
		IncrementAct_t           = new Trampoline(0x004146E0, 0x004146E5, IncrementAct_r);
		LoadLevelFiles_t         = new Trampoline(0x00422AD0, 0x00422AD8, LoadLevelFiles_r);
		SetLevelAndAct_t         = new Trampoline(0x00414570, 0x00414576, SetLevelAndAct_r);
		SetTimeOfDay_t           = new Trampoline(0x00412C00, 0x00412C05, SetTimeOfDay_r);
		DrawLandTable_t          = new Trampoline(0x0043A6A0, 0x0043A6A8, DrawLandTable_r);

		// Correcting a function call since they're relative
		WriteCall(IncrementAct_t->Target(), (void*)0x00424830);

		// Material callback hijack
		WriteJump((void*)0x0040A340, CorrectMaterial_r);
	}

	EXPORT void __cdecl OnFrame()
	{
		auto pad = ControllerPointers[0];
		if (pad)
		{
			auto pressed = pad->PressedButtons;
			if (pressed & Buttons_C)
			{
				d3d::LoadShader();
				SetFogParameters();
			}

			if (pressed & Buttons_Left)
			{
				LoadLanternPalette(globals::system + "diffuse test.bin");
			}
			else if (pressed & Buttons_Right)
			{
				LoadLanternPalette(globals::system + "specular test.bin");
			}
		}

		if (d3d::effect == nullptr)
			return;

		DisplayLightDirection();
	}

	EXPORT void __cdecl OnRenderDeviceLost()
	{
		if (d3d::effect != nullptr)
		{
			d3d::effect->OnLostDevice();
			d3d::UpdateParameterHandles();
		}
	}

	EXPORT void __cdecl OnRenderDeviceReset()
	{
		if (d3d::effect != nullptr)
		{
			d3d::effect->OnResetDevice();
			d3d::UpdateParameterHandles();
			SetFogParameters();
		}
	}
}
<|endoftext|>


<commit_before>#ifndef __RRD_PROXY_HH__
#define __RRD_PROXY_HH__

#include "common.hh"
#include "Message.hh"

#include <zmq.h>
#include <msgpack.hpp>

#include <cstring>
#include <cstdio>
#include <cassert>

#include <string>
#include <stdexcept>

#include <iostream>

/**
 * handles proxying updates to whisper RRD files on disk
 * this runs in a separate thread and subscribes for all messages
 * received by the main monitor thread. It manages creation, update,
 * and deletion of RRD files for each virtual host.  This is really
 * a poor workaround for using either (a) the RRDtool C-style interface
 * or (b) combination of Whisper/Carbon (Carbon accepts updates via a BSD
 * socket and handles creation automatically).
 *
 * Be warned: There are a lot of inefficiencies here!
 * This is mostly to cut down on the number of dependencies we need.
 * Alternatively, we could:
 *    - install Carbon and use it
 *    - use RRDtool (which has a C interface) instead of Whisper, but
 *      this complicates the Python code integrated with the Dashboard
 *    - embed the Python interpreter, and make Whisper calls directly
 *      (but this requires Python development headers/libraries)
 *
 * This uses popen() as a crappy alternative.  Whisper updates are managed
 * via a python script that reads commands via stdin.
 */

class WhisperRRDProxy
{
public:
    WhisperRRDProxy(
        void * zmq_context,
        const std::string & basepath)
        : m_context(zmq_context),
          m_basepath(basepath),
          m_shutdown(false),
          m_updater_path(basepath + "/utils/whisper_updater.sh"),
          m_rrd_data_path(basepath + "/monitor_data"),
          m_updater(NULL)
    { }

    virtual ~WhisperRRDProxy()
    {
        if(m_updater)
            pclose(m_updater);
    }

    void terminate()
    { m_shutdown = true; }

    void run()
    {
        std::string cmd = m_updater_path + " --data-dir " + m_rrd_data_path;

        m_updater = popen(cmd.c_str(), "w");
        if(!m_updater)
        {
            perror("popen");
            throw std::runtime_error(
                "WhisperRRDProxy: unable to create pipe to child process!");
        }

        run_proxy_loop();
    }

protected:
    void run_proxy_loop()
    {
        void * sock = zmq_socket(m_context, ZMQ_SUB);
        assert(sock);

        const char * mon_filter = "monitor.servers.";
        zmq_setsockopt(sock, ZMQ_SUBSCRIBE, mon_filter, strlen(mon_filter));
        const char * term_filter = "monitor.term_instance";
        zmq_setsockopt(sock, ZMQ_SUBSCRIBE, term_filter, strlen(term_filter));

        zmq_connect(sock, "inproc://monitor");

        zmq_pollitem_t pollitems = { sock, 0, ZMQ_POLLIN, 0 };

        while(!m_shutdown)
        {
            int rc = zmq_poll(&pollitems, 1, 100);
            if(rc > 0)
            {
                // receive the next message from the ZMQ side
                Message next;
                next.receive(sock);

                msgpack::unpacked msg;
                msgpack::unpack(&msg, next.data, next.data_len);

                AggregateDomainStats agg;
                msg.get().convert(&agg);

                std::list<std::string> updates = get_whisper_updates(agg);
                for(std::list<std::string>::const_iterator it = updates.begin();
                    it != updates.end();
                    ++it)
                {
                    fprintf(m_updater, "%s\n", it->c_str());
                    fflush(m_updater);
                }
            }
        }

        zmq_close(&sock);
    }

    void * m_context;
    std::string m_basepath;
    std::string m_updater_path;
    std::string m_rrd_data_path;
    bool m_shutdown;
    FILE * m_updater;
};

#endif

<commit_msg>hopefully fixed term_instance processing in WhisperUpdater<commit_after>#ifndef __RRD_PROXY_HH__
#define __RRD_PROXY_HH__

#include "common.hh"
#include "Message.hh"

#include <zmq.h>
#include <msgpack.hpp>

#include <cstring>
#include <cstdio>
#include <cassert>

#include <string>
#include <stdexcept>

#include <iostream>

/**
 * handles proxying updates to whisper RRD files on disk
 * this runs in a separate thread and subscribes for all messages
 * received by the main monitor thread. It manages creation, update,
 * and deletion of RRD files for each virtual host.  This is really
 * a poor workaround for using either (a) the RRDtool C-style interface
 * or (b) combination of Whisper/Carbon (Carbon accepts updates via a BSD
 * socket and handles creation automatically).
 *
 * Be warned: There are a lot of inefficiencies here!
 * This is mostly to cut down on the number of dependencies we need.
 * Alternatively, we could:
 *    - install Carbon and use it
 *    - use RRDtool (which has a C interface) instead of Whisper, but
 *      this complicates the Python code integrated with the Dashboard
 *    - embed the Python interpreter, and make Whisper calls directly
 *      (but this requires Python development headers/libraries)
 *
 * This uses popen() as a crappy alternative.  Whisper updates are managed
 * via a python script that reads commands via stdin.
 */

class WhisperRRDProxy
{
public:
    WhisperRRDProxy(
        void * zmq_context,
        const std::string & basepath)
        : m_context(zmq_context),
          m_basepath(basepath),
          m_shutdown(false),
          m_updater_path(basepath + "/utils/whisper_updater.sh"),
          m_rrd_data_path(basepath + "/monitor_data"),
          m_updater(NULL)
    { }

    virtual ~WhisperRRDProxy()
    {
        if(m_updater)
            pclose(m_updater);
    }

    void terminate()
    { m_shutdown = true; }

    void run()
    {
        std::string cmd = m_updater_path + " --data-dir " + m_rrd_data_path;

        m_updater = popen(cmd.c_str(), "w");
        if(!m_updater)
        {
            perror("popen");
            throw std::runtime_error(
                "WhisperRRDProxy: unable to create pipe to child process!");
        }

        run_proxy_loop();
    }

protected:
    void run_proxy_loop()
    {
        void * sock = zmq_socket(m_context, ZMQ_SUB);
        assert(sock);

        const char * mon_filter = "monitor.servers.";
        zmq_setsockopt(sock, ZMQ_SUBSCRIBE, mon_filter, strlen(mon_filter));
        const char * term_filter = "monitor.term_instance";
        zmq_setsockopt(sock, ZMQ_SUBSCRIBE, term_filter, strlen(term_filter));

        zmq_connect(sock, "inproc://monitor");

        zmq_pollitem_t pollitems = { sock, 0, ZMQ_POLLIN, 0 };

        while(!m_shutdown)
        {
            int rc = zmq_poll(&pollitems, 1, 100);
            if(rc > 0)
            {
                // receive the next message from the ZMQ side
                Message next;
                next.receive(sock);

                msgpack::unpacked msg;
                msgpack::unpack(&msg, next.data, next.data_len);

                if(next.key == "monitor.term_instance")
                {
                    std::string which_instance;
                    msg.get().convert(&which_instance);

                    fprintf(
                        m_updater,
                        "%s %s\n",
                        next.key.c_str(), which_instance.c_str());
                }
                else
                {
                    AggregateDomainStats agg;
                    msg.get().convert(&agg);

                    std::list<std::string> updates = get_whisper_updates(agg);
                    for(std::list<std::string>::const_iterator it = updates.begin();
                        it != updates.end();
                        ++it)
                    {
                        fprintf(m_updater, "%s\n", it->c_str());
                        fflush(m_updater);
                    }
                }
            }
        }

        zmq_close(&sock);
    }

    void * m_context;
    std::string m_basepath;
    std::string m_updater_path;
    std::string m_rrd_data_path;
    bool m_shutdown;
    FILE * m_updater;
};

#endif

<|endoftext|>


<commit_before>// Copyright (c) 2019 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided 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
// COPYRIGHT HOLDER 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 <cstdio>
#include <functional>
#include <iostream>
#include "chunk.h"
#include "scanner.h"
#include "compiler.h"

namespace lox {

enum class Precedence {
  NONE,
  ASSIGNMENT, // =
  OR, // or
  AND, // and
  EQUALITY, // == !=
  COMPARISON, // < <= > >=
  TERM, // + -
  FACTOR, // * /
  UNARY, // ! - +
  CALL, // . () []
  PRIMARY
};

struct ParseRule {
  std::function<void ()> prefix;
  std::function<void ()> infix;
  Precedence precedence;
};

class Parser
  : private UnCopyable, public std::enable_shared_from_this<Parser> {
  Chunk& compiling_chunk_;
  Scanner& scan_;
  Token prev_; // previous token
  Token curr_; // current token
  bool had_error_{};
  bool panic_mode_{};

  void error(const std::string& message) {
    error_at(prev_, message);
  }

  void error_at_current(const std::string& message) {
    error_at(curr_, message);
  }

  void error_at(const Token& tok, const std::string& message) {
    if (panic_mode_)
      return;
    panic_mode_ = true;

    std::cerr << "line(" << tok.get_lineno() << "): ERROR: ";
    if (tok.get_kind() == TokenKind::TK_EOF) {
      std::cerr << "at end";
    }
    else if (tok.get_kind() == TokenKind::TK_ERROR) {
      // nothing
    }
    else {
      std::cerr << "at " << tok.get_literal();
    }
    std::cerr << ": " << message << std::endl;

    had_error_ = true;
  }

  std::uint8_t make_constant(const Value& value) {
    int constant = compiling_chunk_.add_constant(value);
    if (constant > UINT8_MAX) {
      error("too many constants in one chunk ...");
      return 0;
    }
    return static_cast<std::uint8_t>(constant);
  }

  void emit_byte(std::uint8_t byte) {
    compiling_chunk_.write(byte, prev_.get_lineno());
  }

  void emit_bytes(std::uint8_t byte1, std::uint8_t byte2) {
    emit_byte(byte1);
    emit_byte(byte2);
  }

  void emit_return(void) {
    emit_byte(OpCode::OP_RETURN);
  }

  void emit_constant(const Value& value) {
    emit_bytes(OpCode::OP_CONSTANT, make_constant(value));
  }

  void parse_precedence(Precedence prec) {
    advance();
    auto prefix_rule = get_rule(prev_.get_kind()).prefix;
    if (prefix_rule == nullptr) {
      error("expect expression ...");
      return;
    }
    prefix_rule();

    while (prec <= get_rule(curr_.get_kind()).precedence) {
      advance();
      auto infix_rule = get_rule(prev_.get_kind()).infix;
      infix_rule();
    }
  }

  ParseRule& get_rule(TokenKind kind) {
#define BFN(fn) std::bind(&Parser::fn, this)

    static ParseRule rules[] = {
      {nullptr, nullptr, Precedence::NONE}, // TK_ERROR
      {nullptr, nullptr, Precedence::NONE}, // TK_EOF
      {nullptr, nullptr, Precedence::NONE}, // TK_UNKNOWN
      {nullptr, nullptr, Precedence::NONE}, // TK_IDENTIFIER
      {BFN(numeric), nullptr, Precedence::NONE}, // TK_NUMERICCONST
      {nullptr, nullptr, Precedence::NONE}, // TK_STRINGLITERAL
      {BFN(grouping), nullptr, Precedence::CALL}, // TK_LPAREN
      {nullptr, nullptr, Precedence::NONE}, // TK_RPAREN
      {nullptr, nullptr, Precedence::NONE}, // TK_LBRACE
      {nullptr, nullptr, Precedence::NONE}, // TK_RBRACE
      {nullptr, nullptr, Precedence::NONE}, // TK_COMMA
      {nullptr, nullptr, Precedence::CALL}, // TK_DOT
      {nullptr, nullptr, Precedence::NONE}, // TK_SEMI
      {nullptr, BFN(binary), Precedence::TERM}, // TK_PLUS
      {BFN(unary), BFN(binary), Precedence::TERM}, // TK_MINUS
      {nullptr, BFN(binary), Precedence::FACTOR}, // TK_STAR
      {nullptr, BFN(binary), Precedence::FACTOR}, // TK_SLASH
      {nullptr, nullptr, Precedence::NONE}, // TK_BANG
      {nullptr, nullptr, Precedence::EQUALITY}, // TK_BANGEQUAL
      {nullptr, nullptr, Precedence::NONE}, // TK_EQUAL
      {nullptr, nullptr, Precedence::EQUALITY}, // TK_EQUALEQUAL
      {nullptr, nullptr, Precedence::COMPARISON}, // TK_GREATER
      {nullptr, nullptr, Precedence::COMPARISON}, // TK_GREATEREQUAL
      {nullptr, nullptr, Precedence::COMPARISON}, // TK_LESS
      {nullptr, nullptr, Precedence::COMPARISON}, // TK_LESSEQUAL
      {nullptr, nullptr, Precedence::AND}, // KW_AND
      {nullptr, nullptr, Precedence::NONE}, // KW_CLASS
      {nullptr, nullptr, Precedence::NONE}, // KW_ELSE
      {nullptr, nullptr, Precedence::NONE}, // KW_FLASE
      {nullptr, nullptr, Precedence::NONE}, // KW_FOR
      {nullptr, nullptr, Precedence::NONE}, // KW_FUN
      {nullptr, nullptr, Precedence::NONE}, // KW_IF
      {nullptr, nullptr, Precedence::NONE}, // KW_NIL
      {nullptr, nullptr, Precedence::OR}, // KW_OR
      {nullptr, nullptr, Precedence::NONE}, // KW_PRINT
      {nullptr, nullptr, Precedence::NONE}, // KW_RETURN
      {nullptr, nullptr, Precedence::NONE}, // KW_SUPER
      {nullptr, nullptr, Precedence::NONE}, // KW_THIS
      {nullptr, nullptr, Precedence::NONE}, // KW_TRUE
      {nullptr, nullptr, Precedence::NONE}, // KW_VAR
      {nullptr, nullptr, Precedence::NONE}, // KW_WHILE
      {nullptr, nullptr, Precedence::NONE}, // NUM_TOKENS
    };

    return rules[static_cast<int>(kind)];
#undef BFN
  }
public:
  Parser(Chunk& c, Scanner& s) : compiling_chunk_(c), scan_(s) {}
  bool had_error(void) const { return had_error_; }

  void advance(void) {
    prev_ = curr_;

    for (;;) {
      curr_ = scan_.scan_token();
      if (curr_.get_kind() != TokenKind::TK_ERROR)
        break;

      error_at_current(curr_.get_literal());
    }
  }

  void consume(TokenKind kind, const std::string& message) {
    if (curr_.get_kind() == kind) {
      advance();
      return;
    }
    error_at_current(message);
  }

  void end_compiler(void) {
    emit_return();
#if defined(DEBUG_PRINT_CODE)
    if (!had_error_) {
      compiling_chunk_.disassemble("code");
    }
#endif
  }

  void expression(void) {
    // expression     -> assignment ;
    // assignment     -> ( call "." )? IDENTIFILER "=" assignment | logic_or ;
    // logic_or       -> logic_and ( "or" logic_and )* ;
    // logic_and      -> equality ( "and" equality )* ;
    // equality       -> comparison ( ( "!=" | "==" ) comparison )* ;
    // comparison     -> addition ( ( ">" | ">=" | "<" | "<=" ) addition )* ;
    // addition       -> multiplication ( ( "-" | "+" ) multiplication )* ;
    // multiplication -> unary ( ( "*" | "/" | "%" ) unary )* ;
    // unary          -> ( "!" | "-" ) unary | call ;
    // call           -> primary ( "(" arguments? ")" | "." IDENTIFILER )* ;
    // primary        -> "true" | "false" | "nil" | "this"
    //                | NUMERIC | STRING | IDENTIFILER | "(" expression ")"
    //                | "super" "." IDENTIFILER ;
    //
    // arguments      -> expression ( "," expression )* ;

    parse_precedence(Precedence::ASSIGNMENT);
  }

  void binary(void) {
    // remeber the operator
    TokenKind oper_kind = prev_.get_kind();

    // compile the right operand
    auto rule = get_rule(oper_kind);
    parse_precedence(static_cast<Precedence>(static_cast<int>(rule.precedence) + 1));

    // emit the operator instruction
    switch (oper_kind) {
    case TokenKind::TK_PLUS: emit_byte(OpCode::OP_ADD); break;
    case TokenKind::TK_MINUS: emit_byte(OpCode::OP_SUBTRACT); break;
    case TokenKind::TK_STAR: emit_byte(OpCode::OP_MULTIPLY); break;
    case TokenKind::TK_SLASH: emit_byte(OpCode::OP_DIVIDE); break;
    default:
      return; // unreachable
    }
  }

  void numeric(void) {
    // numeric -> NUMERIC ;

    double v = prev_.as_numeric();
    emit_constant(v);
  }

  void grouping(void) {
    // grouping -> "(" expression ")" ;

    expression();
    consume(TokenKind::TK_RPAREN, "expect `)` after expression ...");
  }

  void unary(void) {
    // unary -> ( "-" | "!" ) expression ;

    TokenKind oper_kind = prev_.get_kind();
    // compile the operand
    parse_precedence(Precedence::UNARY);
    // emit the operator instruction
    switch (oper_kind) {
    case TokenKind::TK_MINUS:
      emit_byte(OpCode::OP_NEGATIVE); break;
    default:
      return; // unreachable
    }
  }
};

bool Compiler::compile(Chunk& chunk, const std::string& source_bytes) {
  Scanner s(source_bytes);

  // int lineno = -1;
  // for (;;) {
  //   Token token = s.scan_token();
  //   if (token.get_lineno() != lineno) {
  //     fprintf(stdout, "%4d ", token.get_lineno());
  //     lineno = token.get_lineno();
  //   }
  //   else {
  //     std::cout << "   | ";
  //   }
  //   fprintf(stdout, "%2d %-16s `%s`\n",
  //       token.get_kind(),
  //       get_token_name(token.get_kind()), token.get_literal().c_str());
  //   if (token.get_kind() == TokenKind::TK_EOF)
  //     break;
  // }

  auto p = std::make_shared<Parser>(chunk, s);
  p->advance();
  p->expression();
  p->consume(TokenKind::TK_EOF, "expect end of expression ...");
  p->end_compiler();

  return !p->had_error();
}

}
<commit_msg>:bug: fix(precedence): fixed bug of precedence<commit_after>// Copyright (c) 2019 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided 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
// COPYRIGHT HOLDER 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 <cstdio>
#include <functional>
#include <iostream>
#include "chunk.h"
#include "scanner.h"
#include "compiler.h"

namespace lox {

enum class Precedence {
  NONE,
  ASSIGNMENT, // =
  OR, // or
  AND, // and
  EQUALITY, // == !=
  COMPARISON, // < <= > >=
  TERM, // + -
  FACTOR, // * /
  UNARY, // ! - +
  CALL, // . () []
  PRIMARY
};

class Parser;
using ParserPtr = std::shared_ptr<Parser>;

struct ParseRule {
  std::function<void (const ParserPtr&)> prefix;
  std::function<void (const ParserPtr&)> infix;
  Precedence precedence;
};

class Parser
  : private UnCopyable, public std::enable_shared_from_this<Parser> {
  Chunk& compiling_chunk_;
  Scanner& scan_;
  Token prev_; // previous token
  Token curr_; // current token
  bool had_error_{};
  bool panic_mode_{};

  void error(const std::string& message) {
    error_at(prev_, message);
  }

  void error_at_current(const std::string& message) {
    error_at(curr_, message);
  }

  void error_at(const Token& tok, const std::string& message) {
    if (panic_mode_)
      return;
    panic_mode_ = true;

    std::cerr << "line(" << tok.get_lineno() << "): ERROR: ";
    if (tok.get_kind() == TokenKind::TK_EOF) {
      std::cerr << "at end";
    }
    else if (tok.get_kind() == TokenKind::TK_ERROR) {
      // nothing
    }
    else {
      std::cerr << "at " << tok.get_literal();
    }
    std::cerr << ": " << message << std::endl;

    had_error_ = true;
  }

  std::uint8_t make_constant(const Value& value) {
    int constant = compiling_chunk_.add_constant(value);
    if (constant > UINT8_MAX) {
      error("too many constants in one chunk ...");
      return 0;
    }
    return static_cast<std::uint8_t>(constant);
  }

  void emit_byte(std::uint8_t byte) {
    compiling_chunk_.write(byte, prev_.get_lineno());
  }

  void emit_bytes(std::uint8_t byte1, std::uint8_t byte2) {
    emit_byte(byte1);
    emit_byte(byte2);
  }

  void emit_return(void) {
    emit_byte(OpCode::OP_RETURN);
  }

  void emit_constant(const Value& value) {
    emit_bytes(OpCode::OP_CONSTANT, make_constant(value));
  }

  void parse_precedence(Precedence prec) {
    advance();
    auto prefix_rule = get_rule(prev_.get_kind()).prefix;
    if (prefix_rule == nullptr) {
      error("expect expression ...");
      return;
    }
    prefix_rule(shared_from_this());

    while (prec <= get_rule(curr_.get_kind()).precedence) {
      advance();
      auto infix_rule = get_rule(prev_.get_kind()).infix;
      infix_rule(shared_from_this());
    }
  }

  ParseRule& get_rule(TokenKind kind) {
    auto numeric_fn = [](const ParserPtr& p) { p->numeric(); };
    auto grouping_fn = [](const ParserPtr& p) { p->grouping(); };
    auto binary_fn = [](const ParserPtr& p) { p->binary(); };
    auto unary_fn = [](const ParserPtr& p) { p->unary(); };

    static ParseRule rules[] = {
      {nullptr, nullptr, Precedence::NONE}, // TK_ERROR
      {nullptr, nullptr, Precedence::NONE}, // TK_EOF
      {nullptr, nullptr, Precedence::NONE}, // TK_UNKNOWN
      {nullptr, nullptr, Precedence::NONE}, // TK_IDENTIFIER
      {numeric_fn, nullptr, Precedence::NONE}, // TK_NUMERICCONST
      {nullptr, nullptr, Precedence::NONE}, // TK_STRINGLITERAL
      {grouping_fn, nullptr, Precedence::CALL}, // TK_LPAREN
      {nullptr, nullptr, Precedence::NONE}, // TK_RPAREN
      {nullptr, nullptr, Precedence::NONE}, // TK_LBRACE
      {nullptr, nullptr, Precedence::NONE}, // TK_RBRACE
      {nullptr, nullptr, Precedence::NONE}, // TK_COMMA
      {nullptr, nullptr, Precedence::CALL}, // TK_DOT
      {nullptr, nullptr, Precedence::NONE}, // TK_SEMI
      {nullptr, binary_fn, Precedence::TERM}, // TK_PLUS
      {unary_fn, binary_fn, Precedence::TERM}, // TK_MINUS
      {nullptr, binary_fn, Precedence::FACTOR}, // TK_STAR
      {nullptr, binary_fn, Precedence::FACTOR}, // TK_SLASH
      {nullptr, nullptr, Precedence::NONE}, // TK_BANG
      {nullptr, nullptr, Precedence::EQUALITY}, // TK_BANGEQUAL
      {nullptr, nullptr, Precedence::NONE}, // TK_EQUAL
      {nullptr, nullptr, Precedence::EQUALITY}, // TK_EQUALEQUAL
      {nullptr, nullptr, Precedence::COMPARISON}, // TK_GREATER
      {nullptr, nullptr, Precedence::COMPARISON}, // TK_GREATEREQUAL
      {nullptr, nullptr, Precedence::COMPARISON}, // TK_LESS
      {nullptr, nullptr, Precedence::COMPARISON}, // TK_LESSEQUAL
      {nullptr, nullptr, Precedence::AND}, // KW_AND
      {nullptr, nullptr, Precedence::NONE}, // KW_CLASS
      {nullptr, nullptr, Precedence::NONE}, // KW_ELSE
      {nullptr, nullptr, Precedence::NONE}, // KW_FLASE
      {nullptr, nullptr, Precedence::NONE}, // KW_FOR
      {nullptr, nullptr, Precedence::NONE}, // KW_FUN
      {nullptr, nullptr, Precedence::NONE}, // KW_IF
      {nullptr, nullptr, Precedence::NONE}, // KW_NIL
      {nullptr, nullptr, Precedence::OR}, // KW_OR
      {nullptr, nullptr, Precedence::NONE}, // KW_PRINT
      {nullptr, nullptr, Precedence::NONE}, // KW_RETURN
      {nullptr, nullptr, Precedence::NONE}, // KW_SUPER
      {nullptr, nullptr, Precedence::NONE}, // KW_THIS
      {nullptr, nullptr, Precedence::NONE}, // KW_TRUE
      {nullptr, nullptr, Precedence::NONE}, // KW_VAR
      {nullptr, nullptr, Precedence::NONE}, // KW_WHILE
      {nullptr, nullptr, Precedence::NONE}, // NUM_TOKENS
    };

    return rules[static_cast<int>(kind)];
  }
public:
  Parser(Chunk& c, Scanner& s) : compiling_chunk_(c), scan_(s) {}
  bool had_error(void) const { return had_error_; }

  void advance(void) {
    prev_ = curr_;

    for (;;) {
      curr_ = scan_.scan_token();
      if (curr_.get_kind() != TokenKind::TK_ERROR)
        break;

      error_at_current(curr_.get_literal());
    }
  }

  void consume(TokenKind kind, const std::string& message) {
    if (curr_.get_kind() == kind) {
      advance();
      return;
    }
    error_at_current(message);
  }

  void end_compiler(void) {
    emit_return();
#if defined(DEBUG_PRINT_CODE)
    if (!had_error_) {
      compiling_chunk_.disassemble("code");
    }
#endif
  }

  void expression(void) {
    // expression     -> assignment ;
    // assignment     -> ( call "." )? IDENTIFILER "=" assignment | logic_or ;
    // logic_or       -> logic_and ( "or" logic_and )* ;
    // logic_and      -> equality ( "and" equality )* ;
    // equality       -> comparison ( ( "!=" | "==" ) comparison )* ;
    // comparison     -> addition ( ( ">" | ">=" | "<" | "<=" ) addition )* ;
    // addition       -> multiplication ( ( "-" | "+" ) multiplication )* ;
    // multiplication -> unary ( ( "*" | "/" | "%" ) unary )* ;
    // unary          -> ( "!" | "-" ) unary | call ;
    // call           -> primary ( "(" arguments? ")" | "." IDENTIFILER )* ;
    // primary        -> "true" | "false" | "nil" | "this"
    //                | NUMERIC | STRING | IDENTIFILER | "(" expression ")"
    //                | "super" "." IDENTIFILER ;
    //
    // arguments      -> expression ( "," expression )* ;

    parse_precedence(Precedence::ASSIGNMENT);
  }

  void binary(void) {
    // remeber the operator
    TokenKind oper_kind = prev_.get_kind();

    // compile the right operand
    auto rule = get_rule(oper_kind);
    parse_precedence(static_cast<Precedence>(static_cast<int>(rule.precedence) + 1));

    // emit the operator instruction
    switch (oper_kind) {
    case TokenKind::TK_PLUS: emit_byte(OpCode::OP_ADD); break;
    case TokenKind::TK_MINUS: emit_byte(OpCode::OP_SUBTRACT); break;
    case TokenKind::TK_STAR: emit_byte(OpCode::OP_MULTIPLY); break;
    case TokenKind::TK_SLASH: emit_byte(OpCode::OP_DIVIDE); break;
    default:
      return; // unreachable
    }
  }

  void numeric(void) {
    // numeric -> NUMERIC ;

    double v = prev_.as_numeric();
    emit_constant(v);
  }

  void grouping(void) {
    // grouping -> "(" expression ")" ;

    expression();
    consume(TokenKind::TK_RPAREN, "expect `)` after expression ...");
  }

  void unary(void) {
    // unary -> ( "-" | "!" ) expression ;

    TokenKind oper_kind = prev_.get_kind();
    // compile the operand
    parse_precedence(Precedence::UNARY);
    // emit the operator instruction
    switch (oper_kind) {
    case TokenKind::TK_MINUS:
      emit_byte(OpCode::OP_NEGATIVE); break;
    default:
      return; // unreachable
    }
  }
};

bool Compiler::compile(Chunk& chunk, const std::string& source_bytes) {
  Scanner s(source_bytes);

  // int lineno = -1;
  // for (;;) {
  //   Token token = s.scan_token();
  //   if (token.get_lineno() != lineno) {
  //     fprintf(stdout, "%4d ", token.get_lineno());
  //     lineno = token.get_lineno();
  //   }
  //   else {
  //     std::cout << "   | ";
  //   }
  //   fprintf(stdout, "%2d %-16s `%s`\n",
  //       token.get_kind(),
  //       get_token_name(token.get_kind()), token.get_literal().c_str());
  //   if (token.get_kind() == TokenKind::TK_EOF)
  //     break;
  // }

  auto p = std::make_shared<Parser>(chunk, s);
  p->advance();
  p->expression();
  p->consume(TokenKind::TK_EOF, "expect end of expression ...");
  p->end_compiler();

  return !p->had_error();
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2016 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided 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
// COPYRIGHT HOLDER 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 <time.h>
#include <iostream>
#include "../basic/TStringPiece.h"
#include "../basic/TTimestamp.h"
#include "../basic/TCurrentThread.h"
#include "../basic/TMutex.h"

#define UNUSED_PARAM(arg) (void)arg

void tyr_test_StringArg(void) {
  std::cout << "\n#################### StringArg ####################\n";
  std::string std_str("std::string('tyr test StringArg')");
  const char* c_str = "raw c-types string('tyr test StringArg')";

  tyr::basic::StringArg s1(c_str);
  std::cout << "StringArg with raw c-types string => " << s1.c_str() << std::endl;

  tyr::basic::StringArg s2(std_str);
  std::cout << "StringArg with std::string => " << s2.c_str() << std::endl;
  tyr::basic::StringArg s3(std_str.c_str());
  std::cout << "StringArg with std::string.c_str() => " << s3.c_str() << std::endl;
  tyr::basic::StringArg s4(std_str.data());
  std::cout << "StringArg with std::string.data() => " << s4.c_str() << std::endl;
}

static void tyr_show_StringPiece(const tyr::basic::StringPiece& s, const char* name = "StringPiece") {
  const char* output = "(null)";
  if (static_cast<bool>(s))
    output = s.data();
  std::cout << "object(`" << name << "`) tyr::basic::StringPiece is: @{\n\t\t"
    << "@data: " << output << "\n\t\t"
    << "@size: " << s.size() << "\n\t\t"
    << "@empty: " << s.empty() << "\n\t\t"
    << "@begin: " << (void*)s.begin() << "\n\t\t"
    << "@end: " << (void*)s.end() << "\n\t"
    << "}\n\t"
    << "@as_string: " << s.as_string() << std::endl;
}

void tyr_test_StringPiece(void) {
  std::cout << "\n#################### StringPiece ####################\n";
  const char* cstr = "raw c-types string<tyr test StringPiece>";
  size_t cstr_len = strlen(cstr);
  const byte_t* bstr = reinterpret_cast<const byte_t*>("raw byte-types string<tyr test StringPiece>");
  std::string std_str("std::string<tyr test StringPiece>");
  char buf[] = "memory buffer<tyr test StringPiece>";
  size_t buf_len = sizeof(buf);

  tyr::basic::StringPiece s1;
  tyr_show_StringPiece(s1, "StringPiece.s1");
  s1.set(cstr);
  tyr_show_StringPiece(s1, "StringPiece.s1");
  s1.set(cstr, cstr_len);
  tyr_show_StringPiece(s1, "StringPiece.s1");
  s1.set(buf, buf_len);
  tyr_show_StringPiece(s1, "StringPiece.s1");
  s1.remove_prefix(10);
  tyr_show_StringPiece(s1, "StringPiece.s1");
  s1.remove_suffix(5);
  tyr_show_StringPiece(s1, "StringPiece.s1");
  std::cout << "@s1(" << s1 << ") starts_with<fer>: " << s1.starts_with("fer") << std::endl;
  s1.clear();
  tyr_show_StringPiece(s1, "StringPiece.s1");

  tyr::basic::StringPiece s2(bstr);
  tyr_show_StringPiece(s2, "StringPiece.s2");
  tyr::basic::StringPiece s3(std_str);
  tyr_show_StringPiece(s3, "StringPiece.s3");

  std::cout << "s2 compare with s3 -"
    << " @==: " << (s2 == s3)
    << " @<: " << (s2 < s3)
    << " @<=: " << (s2 <= s3)
    << " @>: " << (s2 > s3)
    << " @>=: " << (s2 >= s3) << std::endl;

  std::string s;
  s2.copy_to_string(&s);
  std::cout << "with copy_to_string @s: " << s << std::endl;
  s3.copy_to_string(&s);
  std::cout << "with copy_to_string @s: " << s << std::endl;
}

static void tyr_show_Timestamp(tyr::basic::Timestamp t, const char* name = "Timestamp") {
  std::cout << "object(`" << name << "`) tyr::basic::Timestamp is: @{\n\t\t"
    << "@is_valid: " << t.is_valid() << "\n\t\t"
    << "@msec_since_epoch: " << t.msec_since_epoch() << "\n\t\t"
    << "@sec_since_epoch: " << t.sec_since_epoch() << "\n\t\t"
    << "@to_string: " << t.to_string() << "\n\t\t"
    << "@to_formatted_string(true): " << t.to_formatted_string() << "\n\t"
    << "}" << std::endl;
}

void tyr_test_Timestamp(void) {
  std::cout << "\n#################### Timestamp ####################\n";
  using namespace tyr::basic;

  Timestamp t1;
  tyr_show_Timestamp(t1, "Timestamp.t1");

  Timestamp t2(time(nullptr) * Timestamp::kMicroSecondsPerSecond);
  tyr_show_Timestamp(t2, "Timestamp.t2");

  t1.swap(t2);
  tyr_show_Timestamp(t1, "Timestamp.t1.after.swap");
  tyr_show_Timestamp(t2, "Timestamp.t2.after.swap");

  tyr_show_Timestamp(Timestamp::now(), "Timestamp.now");
  tyr_show_Timestamp(Timestamp::invalid(), "Timestamp.invalid");
  tyr_show_Timestamp(Timestamp::from_unix_time(time(nullptr)), "Timestamp.from_unix_time");
  tyr_show_Timestamp(Timestamp::from_unix_time(time(nullptr), 100), "Timestamp.from_unix_time.2");

  Timestamp t3(Timestamp::from_unix_time(time(nullptr)));
  Timestamp t4(Timestamp::from_unix_time(time(nullptr), 100));
  tyr_show_Timestamp(t3, "Timestamp.t3");
  tyr_show_Timestamp(t4, "Timestamp.t4");
  std::cout << "@t3 == @now: " << (t3 == Timestamp::now()) << std::endl;
  std::cout << "@t3 < @t4: " << (t3 < t4) << std::endl;
  std::cout << "time_difference(t4 - t3) = " << time_difference(t4, t3) << std::endl;
  tyr_show_Timestamp(add_time(t3, 5), "Timestamp.add_time.(now + 5s)");
}

void tyr_test_CurrentThread(void) {
  std::cout << "\n#################### CurrentThread ####################\n";
  using namespace tyr::basic;

  CurrentThread::cached_tid();

  std::cout << "namespace CurrentThread functions: @{\n\t\t"
    << "@tid: " << CurrentThread::tid() << "\n\t\t"
    << "@tid_string: " << CurrentThread::tid_string() << "\n\t\t"
    << "@tid_string_length: " << CurrentThread::tid_string_length() << "\n\t\t"
    << "@name: " << CurrentThread::name() << "\n\t\t"
    << "@is_main_thread: " << CurrentThread::is_main_thread() << "\n\t"
    << "}" << std::endl;

  tyr_show_Timestamp(Timestamp::now(), "CurrentThread.begin");
  CurrentThread::sleep_usec(1010);
  tyr_show_Timestamp(Timestamp::now(), "CurrentThread.end");
}

int main(int argc, char* argv[]) {
  UNUSED_PARAM(argc);
  UNUSED_PARAM(argv);

  tyr_test_StringArg();
  tyr_test_StringPiece();
  tyr_test_Timestamp();
  tyr_test_CurrentThread();

  return 0;
}
<commit_msg>chore(test): add test about Date module<commit_after>// Copyright (c) 2016 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided 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
// COPYRIGHT HOLDER 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 <time.h>
#include <iostream>
#include "../basic/TStringPiece.h"
#include "../basic/TTimestamp.h"
#include "../basic/TCurrentThread.h"
#include "../basic/TDate.h"
#include "../basic/TMutex.h"

#define UNUSED_PARAM(arg) (void)arg

void tyr_test_StringArg(void) {
  std::cout << "\n#################### StringArg ####################\n";
  std::string std_str("std::string('tyr test StringArg')");
  const char* c_str = "raw c-types string('tyr test StringArg')";

  tyr::basic::StringArg s1(c_str);
  std::cout << "StringArg with raw c-types string => " << s1.c_str() << std::endl;

  tyr::basic::StringArg s2(std_str);
  std::cout << "StringArg with std::string => " << s2.c_str() << std::endl;
  tyr::basic::StringArg s3(std_str.c_str());
  std::cout << "StringArg with std::string.c_str() => " << s3.c_str() << std::endl;
  tyr::basic::StringArg s4(std_str.data());
  std::cout << "StringArg with std::string.data() => " << s4.c_str() << std::endl;
}

static void tyr_show_StringPiece(const tyr::basic::StringPiece& s, const char* name = "StringPiece") {
  const char* output = "(null)";
  if (static_cast<bool>(s))
    output = s.data();
  std::cout << "object(`" << name << "`) tyr::basic::StringPiece is: @{\n\t\t"
    << "@data: " << output << "\n\t\t"
    << "@size: " << s.size() << "\n\t\t"
    << "@empty: " << s.empty() << "\n\t\t"
    << "@begin: " << (void*)s.begin() << "\n\t\t"
    << "@end: " << (void*)s.end() << "\n\t"
    << "}\n\t"
    << "@as_string: " << s.as_string() << std::endl;
}

void tyr_test_StringPiece(void) {
  std::cout << "\n#################### StringPiece ####################\n";
  const char* cstr = "raw c-types string<tyr test StringPiece>";
  size_t cstr_len = strlen(cstr);
  const byte_t* bstr = reinterpret_cast<const byte_t*>("raw byte-types string<tyr test StringPiece>");
  std::string std_str("std::string<tyr test StringPiece>");
  char buf[] = "memory buffer<tyr test StringPiece>";
  size_t buf_len = sizeof(buf);

  tyr::basic::StringPiece s1;
  tyr_show_StringPiece(s1, "StringPiece.s1");
  s1.set(cstr);
  tyr_show_StringPiece(s1, "StringPiece.s1");
  s1.set(cstr, cstr_len);
  tyr_show_StringPiece(s1, "StringPiece.s1");
  s1.set(buf, buf_len);
  tyr_show_StringPiece(s1, "StringPiece.s1");
  s1.remove_prefix(10);
  tyr_show_StringPiece(s1, "StringPiece.s1");
  s1.remove_suffix(5);
  tyr_show_StringPiece(s1, "StringPiece.s1");
  std::cout << "@s1(" << s1 << ") starts_with<fer>: " << s1.starts_with("fer") << std::endl;
  s1.clear();
  tyr_show_StringPiece(s1, "StringPiece.s1");

  tyr::basic::StringPiece s2(bstr);
  tyr_show_StringPiece(s2, "StringPiece.s2");
  tyr::basic::StringPiece s3(std_str);
  tyr_show_StringPiece(s3, "StringPiece.s3");

  std::cout << "s2 compare with s3 -"
    << " @==: " << (s2 == s3)
    << " @<: " << (s2 < s3)
    << " @<=: " << (s2 <= s3)
    << " @>: " << (s2 > s3)
    << " @>=: " << (s2 >= s3) << std::endl;

  std::string s;
  s2.copy_to_string(&s);
  std::cout << "with copy_to_string @s: " << s << std::endl;
  s3.copy_to_string(&s);
  std::cout << "with copy_to_string @s: " << s << std::endl;
}

static void tyr_show_Timestamp(tyr::basic::Timestamp t, const char* name = "Timestamp") {
  std::cout << "object(`" << name << "`) tyr::basic::Timestamp is: @{\n\t\t"
    << "@is_valid: " << t.is_valid() << "\n\t\t"
    << "@msec_since_epoch: " << t.msec_since_epoch() << "\n\t\t"
    << "@sec_since_epoch: " << t.sec_since_epoch() << "\n\t\t"
    << "@to_string: " << t.to_string() << "\n\t\t"
    << "@to_formatted_string(true): " << t.to_formatted_string() << "\n\t"
    << "}" << std::endl;
}

void tyr_test_Timestamp(void) {
  std::cout << "\n#################### Timestamp ####################\n";
  using namespace tyr::basic;

  Timestamp t1;
  tyr_show_Timestamp(t1, "Timestamp.t1");

  Timestamp t2(time(nullptr) * Timestamp::kMicroSecondsPerSecond);
  tyr_show_Timestamp(t2, "Timestamp.t2");

  t1.swap(t2);
  tyr_show_Timestamp(t1, "Timestamp.t1.after.swap");
  tyr_show_Timestamp(t2, "Timestamp.t2.after.swap");

  tyr_show_Timestamp(Timestamp::now(), "Timestamp.now");
  tyr_show_Timestamp(Timestamp::invalid(), "Timestamp.invalid");
  tyr_show_Timestamp(Timestamp::from_unix_time(time(nullptr)), "Timestamp.from_unix_time");
  tyr_show_Timestamp(Timestamp::from_unix_time(time(nullptr), 100), "Timestamp.from_unix_time.2");

  Timestamp t3(Timestamp::from_unix_time(time(nullptr)));
  Timestamp t4(Timestamp::from_unix_time(time(nullptr), 100));
  tyr_show_Timestamp(t3, "Timestamp.t3");
  tyr_show_Timestamp(t4, "Timestamp.t4");
  std::cout << "@t3 == @now: " << (t3 == Timestamp::now()) << std::endl;
  std::cout << "@t3 < @t4: " << (t3 < t4) << std::endl;
  std::cout << "time_difference(t4 - t3) = " << time_difference(t4, t3) << std::endl;
  tyr_show_Timestamp(add_time(t3, 5), "Timestamp.add_time.(now + 5s)");
}

void tyr_test_CurrentThread(void) {
  std::cout << "\n#################### CurrentThread ####################\n";
  using namespace tyr::basic;

  CurrentThread::cached_tid();

  std::cout << "namespace CurrentThread functions: @{\n\t\t"
    << "@tid: " << CurrentThread::tid() << "\n\t\t"
    << "@tid_string: " << CurrentThread::tid_string() << "\n\t\t"
    << "@tid_string_length: " << CurrentThread::tid_string_length() << "\n\t\t"
    << "@name: " << CurrentThread::name() << "\n\t\t"
    << "@is_main_thread: " << CurrentThread::is_main_thread() << "\n\t"
    << "}" << std::endl;

  tyr_show_Timestamp(Timestamp::now(), "CurrentThread.begin");
  CurrentThread::sleep_usec(1010);
  tyr_show_Timestamp(Timestamp::now(), "CurrentThread.end");
}

static void tyr_show_Date(tyr::basic::Date d, const char* name = "Date") {
  std::cout << "object(`" << name << "`): @{\n\t\t"
    << "@is_valid: " << d.is_valid() << "\n\t\t"
    << "@year: " << d.year() << "\n\t\t"
    << "@month: " << d.month() << "\n\t\t"
    << "@day: " << d.day() << "\n\t\t"
    << "@weekday: " << d.weekday() << "\n\t\t"
    << "@epoch_day: " << d.epoch_day() << "\n\t\t"
    << "@iso_string: " << d.to_iso_string() << "\n\t"
    << "}" << std::endl;
}

void tyr_test_Date(void) {
  std::cout << "\n#################### Date ####################\n";
  using namespace tyr::basic;

  Date d1;
  tyr_show_Date(d1, "Date.d1");
  Date d2(2457600);
  tyr_show_Date(d2, "Date.d2");
  Date d3(2016, 10, 14);
  tyr_show_Date(d3, "Date.d3");
  d2.swap(d3);
  tyr_show_Date(d2, "Date.d2.after.swap");
  tyr_show_Date(d3, "Date.d3.after.swap");

  time_t current_time = time(nullptr);
  struct tm* now = localtime(&current_time);
  Date d4(*now);
  tyr_show_Date(d4, "Date.d4");

  Date::DateTuple dt = d4.get_date();
  std::cout << "(`Date.d4`) @DateTuple {@year: "
    << dt.year << ", @month: " << dt.month << ", @day: " << dt.day << "}" << std::endl;
  std::cout << "@d3 == @d4: " << (d3 == d4) << ", @d3 < @d4: " << (d3 < d4) << std::endl;
}

int main(int argc, char* argv[]) {
  UNUSED_PARAM(argc);
  UNUSED_PARAM(argv);

  tyr_test_StringArg();
  tyr_test_StringPiece();
  tyr_test_Timestamp();
  tyr_test_CurrentThread();
  tyr_test_Date();

  return 0;
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#if !defined(XALAN_KEYTABLE_HEADER_GUARD)
#define XALAN_KEYTABLE_HEADER_GUARD

/**
 * $Id$
 *
 * $State$
 *
 * @author Myriam Midy (Myriam_Midy @lotus.com
 */

// Base include file.  Must be first.
#include "XSLTDefinitions.hpp"

#include <map>
#include <vector>

#include <PlatformSupport/DOMStringHelper.hpp>

#include <XPath/MutableNodeRefList.hpp>
#include <XPath/XalanQNameByReference.hpp>

class KeyDeclaration;
class NodeRefListBase;
class PrefixResolver;
class StylesheetExecutionContext;
class XalanElement;
class XalanNode;

/**
 * Table of element keys, keyed by document node.  An instance of this
 * class is keyed by a Document node that should be matched with the
 * root of the current context.  It contains a table of name mappings
 * to tables that contain mappings of identifier values to nodes.
 */
class KeyTable
{
public:

#if defined(XALAN_NO_NAMESPACES)
	typedef vector<KeyDeclaration>			KeyDeclarationVectorType;

	typedef map<XalanDOMString,
				MutableNodeRefList,
				less<XalanDOMString> >		NodeListMapType;

	typedef map<XalanQNameByReference,
				NodeListMapType,
				less<XalanDOMString> >		KeysMapType;
#else
	typedef std::vector<KeyDeclaration>		KeyDeclarationVectorType;

	typedef std::map<XalanDOMString,
					 MutableNodeRefList>	NodeListMapType;

	typedef std::map<XalanQNameByReference,
					 NodeListMapType>		KeysMapType;
#endif

	/**
	 * Build a keys table.
	 *
	 * @param doc              owner document key (normally the same as
	 *                         startNode)
	 * @param startNode        node to start iterating from to build the keys
	 *                         index
	 * @param nscontext        stylesheet's namespace context
	 * @param keyDeclarations  stylesheet's xsl:key declarations
	 * @param executionContext current execution context
	 */
	KeyTable(
			XalanNode*							doc,
			XalanNode*							startNode,
			const PrefixResolver&				resolver,
			const KeyDeclarationVectorType&		keyDeclarations,
			StylesheetExecutionContext&			executionContext);

	virtual
	~KeyTable();

	/**
	 * Given a valid element key, return the corresponding node list. If the
	 * name was not declared with xsl:key, this will return null, the
	 * identifier is not found, it will return an empty node set, otherwise it
	 * will return a nodeset of nodes.
	 *
	 * @param name name of the key, which must match the 'name' attribute on
	 *             xsl:key
	 * @param ref  value that must match the value found by the 'match'
	 *             attribute on xsl:key
	 * @return		pointer to nodeset for key
	 */
	const NodeRefListBase&
	getNodeSetByKey(
				  const XalanQName&			qname,
				  const XalanDOMString&		ref) const;

	/**
	 * Retrieve the document key.  This table should only be used with contexts
	 * whose Document root matches this key.
	 *
	 * @return Node for document
	 */
	const XalanNode*
	getDocKey() const
	{
		return m_docKey;
	}

private:

	/**
	 * Helper function to add a node to the list if not found.
	 *
	 * @param theNodeList the node list.
	 * @param theNode the node to add.
	 */
	static void
	addIfNotFound(
			MutableNodeRefList&		theNodeList,
			XalanNode*				theNode);

	static void
	processKeyDeclaration(
			KeysMapType&					theKeys,
			const KeyDeclaration&			kd,
			XalanNode*						testNode,
			const PrefixResolver&			resolver,
			StylesheetExecutionContext&		executionContext);

	/**
	 * The document key.  This table should only be used with contexts
	 * whose Document roots match this key.
	 */
	const XalanNode*	m_docKey;

	/**
	 * Table of element keys.  The table will be built on demand,
	 * when a key is requested, or set by the XMLParserLiaison or
	 * the caller.  The table is:
	 * a) keyed by name,
	 * b) each with a value of a hashtable, keyed by the value returned by
	 *    the use attribute,
	 * c) each with a value that is a nodelist.
	 * Thus, for a given key or keyref, look up hashtable by name,
	 * look up the nodelist by the given reference.
	 */

	KeysMapType							m_keys;

	static const MutableNodeRefList		s_dummyList;
};

#endif	// XALAN_KEYTABLE_HEADER_GUARD
<commit_msg>Fixed typedef of map.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#if !defined(XALAN_KEYTABLE_HEADER_GUARD)
#define XALAN_KEYTABLE_HEADER_GUARD

/**
 * $Id$
 *
 * $State$
 *
 * @author Myriam Midy (Myriam_Midy @lotus.com
 */

// Base include file.  Must be first.
#include "XSLTDefinitions.hpp"

#include <map>
#include <vector>

#include <PlatformSupport/DOMStringHelper.hpp>

#include <XPath/MutableNodeRefList.hpp>
#include <XPath/XalanQNameByReference.hpp>

class KeyDeclaration;
class NodeRefListBase;
class PrefixResolver;
class StylesheetExecutionContext;
class XalanElement;
class XalanNode;

/**
 * Table of element keys, keyed by document node.  An instance of this
 * class is keyed by a Document node that should be matched with the
 * root of the current context.  It contains a table of name mappings
 * to tables that contain mappings of identifier values to nodes.
 */
class KeyTable
{
public:

#if defined(XALAN_NO_NAMESPACES)
	typedef vector<KeyDeclaration>			KeyDeclarationVectorType;

	typedef map<XalanDOMString,
				MutableNodeRefList,
				less<XalanDOMString> >		NodeListMapType;

	typedef map<XalanQNameByReference,
				NodeListMapType,
				less<XalanQNameByReference> >	KeysMapType;
#else
	typedef std::vector<KeyDeclaration>		KeyDeclarationVectorType;

	typedef std::map<XalanDOMString,
					 MutableNodeRefList>	NodeListMapType;

	typedef std::map<XalanQNameByReference,
					 NodeListMapType>		KeysMapType;
#endif

	/**
	 * Build a keys table.
	 *
	 * @param doc              owner document key (normally the same as
	 *                         startNode)
	 * @param startNode        node to start iterating from to build the keys
	 *                         index
	 * @param nscontext        stylesheet's namespace context
	 * @param keyDeclarations  stylesheet's xsl:key declarations
	 * @param executionContext current execution context
	 */
	KeyTable(
			XalanNode*							doc,
			XalanNode*							startNode,
			const PrefixResolver&				resolver,
			const KeyDeclarationVectorType&		keyDeclarations,
			StylesheetExecutionContext&			executionContext);

	virtual
	~KeyTable();

	/**
	 * Given a valid element key, return the corresponding node list. If the
	 * name was not declared with xsl:key, this will return null, the
	 * identifier is not found, it will return an empty node set, otherwise it
	 * will return a nodeset of nodes.
	 *
	 * @param name name of the key, which must match the 'name' attribute on
	 *             xsl:key
	 * @param ref  value that must match the value found by the 'match'
	 *             attribute on xsl:key
	 * @return		pointer to nodeset for key
	 */
	const NodeRefListBase&
	getNodeSetByKey(
				  const XalanQName&			qname,
				  const XalanDOMString&		ref) const;

	/**
	 * Retrieve the document key.  This table should only be used with contexts
	 * whose Document root matches this key.
	 *
	 * @return Node for document
	 */
	const XalanNode*
	getDocKey() const
	{
		return m_docKey;
	}

private:

	/**
	 * Helper function to add a node to the list if not found.
	 *
	 * @param theNodeList the node list.
	 * @param theNode the node to add.
	 */
	static void
	addIfNotFound(
			MutableNodeRefList&		theNodeList,
			XalanNode*				theNode);

	static void
	processKeyDeclaration(
			KeysMapType&					theKeys,
			const KeyDeclaration&			kd,
			XalanNode*						testNode,
			const PrefixResolver&			resolver,
			StylesheetExecutionContext&		executionContext);

	/**
	 * The document key.  This table should only be used with contexts
	 * whose Document roots match this key.
	 */
	const XalanNode*	m_docKey;

	/**
	 * Table of element keys.  The table will be built on demand,
	 * when a key is requested, or set by the XMLParserLiaison or
	 * the caller.  The table is:
	 * a) keyed by name,
	 * b) each with a value of a hashtable, keyed by the value returned by
	 *    the use attribute,
	 * c) each with a value that is a nodelist.
	 * Thus, for a given key or keyref, look up hashtable by name,
	 * look up the nodelist by the given reference.
	 */

	KeysMapType							m_keys;

	static const MutableNodeRefList		s_dummyList;
};

#endif	// XALAN_KEYTABLE_HEADER_GUARD
<|endoftext|>


<commit_before>#include <Rcpp.h>
#include "XlsxWorkSheet.h"
using namespace Rcpp;

// [[Rcpp::export]]
void xlsx_cells(std::string path, int sheet = 0) {
  return XlsxWorkSheet(path, sheet).printCells();
}

// [[Rcpp::export]]
IntegerVector xlsx_dim(std::string path, int sheet = 0) {
  XlsxWorkSheet ws(path, sheet);
  return IntegerVector::create(ws.nrow(), ws.ncol());
}

// [[Rcpp::export]]
IntegerVector parse_ref(std::string ref) {
  std::pair<int,int> parsed = parseRef(ref.c_str());

  return IntegerVector::create(parsed.first, parsed.second);
}

// [[Rcpp::export]]
CharacterVector xlsx_col_types(std::string path, int sheet = 0,
                               std::string na = "", int nskip = 0,
                               int n = 100) {

  XlsxWorkSheet ws(path, sheet);
  std::vector<CellType> types = ws.colTypes(na, nskip, n);

  CharacterVector out(types.size());
  for (size_t i = 0; i < types.size(); ++i) {
    out[i] = cellTypeDesc(types[i]);
  }

  return out;
}

// [[Rcpp::export]]
CharacterVector xlsx_col_names(std::string path, int sheet = 0, int nskip = 0) {
  return XlsxWorkSheet(path, sheet).colNames(nskip);
}

// [[Rcpp::export]]
List read_xlsx_(std::string path, int sheet, RObject col_names,
                RObject col_types, std::string na, int nskip = 0) {

  XlsxWorkSheet ws(path, sheet);

  // Standardise column names --------------------------------------------------
  CharacterVector colNames;
  bool sheetHasColumnNames = false;
  switch(TYPEOF(col_names)) {
  case CHARSXP:
    colNames = as<CharacterVector>(col_names);
    break;
  case LGLSXP:
  {
    sheetHasColumnNames = as<bool>(col_names);
    if (sheetHasColumnNames) {
      colNames = ws.colNames(nskip);
    } else {
      int p = ws.ncol();
      colNames = CharacterVector(p);
      for (int j = 0; j < p; ++j) {
        colNames[j] = tfm::format("X%i", j);
      }
    }
    break;
  }
  default:
    Rcpp::stop("`col_names` must be a logical or character vector");
  }

  // Standardise column types --------------------------------------------------
  std::vector<CellType> colTypes;
  switch(TYPEOF(col_types)) {
  case NILSXP:
    colTypes = ws.colTypes(na, nskip, 100, sheetHasColumnNames);
    break;
  case STRSXP:
    colTypes = cellTypes(as<CharacterVector>(col_types));
    break;
  default:
    Rcpp::stop("`col_types` must be a character vector or NULL");
  }

  return ws.readCols(colNames, colTypes, na, nskip + sheetHasColumnNames);
}
<commit_msg>Character vector is STRSXP not CHARSXP<commit_after>#include <Rcpp.h>
#include "XlsxWorkSheet.h"
using namespace Rcpp;

// [[Rcpp::export]]
void xlsx_cells(std::string path, int sheet = 0) {
  return XlsxWorkSheet(path, sheet).printCells();
}

// [[Rcpp::export]]
IntegerVector xlsx_dim(std::string path, int sheet = 0) {
  XlsxWorkSheet ws(path, sheet);
  return IntegerVector::create(ws.nrow(), ws.ncol());
}

// [[Rcpp::export]]
IntegerVector parse_ref(std::string ref) {
  std::pair<int,int> parsed = parseRef(ref.c_str());

  return IntegerVector::create(parsed.first, parsed.second);
}

// [[Rcpp::export]]
CharacterVector xlsx_col_types(std::string path, int sheet = 0,
                               std::string na = "", int nskip = 0,
                               int n = 100) {

  XlsxWorkSheet ws(path, sheet);
  std::vector<CellType> types = ws.colTypes(na, nskip, n);

  CharacterVector out(types.size());
  for (size_t i = 0; i < types.size(); ++i) {
    out[i] = cellTypeDesc(types[i]);
  }

  return out;
}

// [[Rcpp::export]]
CharacterVector xlsx_col_names(std::string path, int sheet = 0, int nskip = 0) {
  return XlsxWorkSheet(path, sheet).colNames(nskip);
}

// [[Rcpp::export]]
List read_xlsx_(std::string path, int sheet, RObject col_names,
                RObject col_types, std::string na, int nskip = 0) {

  XlsxWorkSheet ws(path, sheet);

  // Standardise column names --------------------------------------------------
  CharacterVector colNames;
  bool sheetHasColumnNames = false;
  switch(TYPEOF(col_names)) {
  case STRSXP:
    colNames = as<CharacterVector>(col_names);
    break;
  case LGLSXP:
  {
    sheetHasColumnNames = as<bool>(col_names);
    if (sheetHasColumnNames) {
      colNames = ws.colNames(nskip);
    } else {
      int p = ws.ncol();
      colNames = CharacterVector(p);
      for (int j = 0; j < p; ++j) {
        colNames[j] = tfm::format("X%i", j);
      }
    }
    break;
  }
  default:
    Rcpp::stop("`col_names` must be a logical or character vector");
  }

  // Standardise column types --------------------------------------------------
  std::vector<CellType> colTypes;
  switch(TYPEOF(col_types)) {
  case NILSXP:
    colTypes = ws.colTypes(na, nskip, 100, sheetHasColumnNames);
    break;
  case STRSXP:
    colTypes = cellTypes(as<CharacterVector>(col_types));
    break;
  default:
    Rcpp::stop("`col_types` must be a character vector or NULL");
  }

  return ws.readCols(colNames, colTypes, na, nskip + sheetHasColumnNames);
}
<|endoftext|>