<commit_before> /*
 *  Copyright 2016-2019 by the individuals mentioned in the source code history
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include "omxFitFunction.h"
#include "Compute.h"
#include "EnableWarnings.h"

struct ssMLFitState : omxFitFunction {
	int verbose;
	bool returnRowLikelihoods;
	bool populateRowDiagnostics;
	omxMatrix *cov;
	omxMatrix *smallRow;
	omxMatrix *contRow;
	omxMatrix *rowLikelihoods;
	omxMatrix *RCX;
	omxMatrix* otherRowwiseValues;

	virtual ~ssMLFitState();
	virtual void init();
	virtual void compute(int ffcompute, FitContext *fc);
	virtual void populateAttr(SEXP algebra);
};

void ssMLFitState::populateAttr(SEXP algebra)
{
	ssMLFitState *argStruct = this;

	if(argStruct->populateRowDiagnostics){
		SEXP rowLikelihoodsExt;
		SEXP rowObsExt;
		SEXP rowDistExt;
		omxMatrix *rowLikelihoodsInt = argStruct->rowLikelihoods;
		omxMatrix *otherRowwiseValuesInt = argStruct->otherRowwiseValues;
		Rf_protect(rowLikelihoodsExt = Rf_allocVector(REALSXP, rowLikelihoodsInt->rows));
		Rf_protect(rowObsExt = Rf_allocVector(REALSXP, rowLikelihoodsInt->rows));
		Rf_protect(rowDistExt = Rf_allocVector(REALSXP, rowLikelihoodsInt->rows));
		for(int row = 0; row < rowLikelihoodsInt->rows; row++) {
			REAL(rowLikelihoodsExt)[row] = omxMatrixElement(rowLikelihoodsInt, row, 0);
			REAL(rowDistExt)[row] = omxMatrixElement(otherRowwiseValuesInt, row, 0);
			REAL(rowObsExt)[row] = omxMatrixElement(otherRowwiseValuesInt, row, 1);
		}
		Rf_setAttrib(algebra, Rf_install("likelihoods"), rowLikelihoodsExt);
		Rf_setAttrib(algebra, Rf_install("rowDist"), rowDistExt);
		Rf_setAttrib(algebra, Rf_install("rowObs"), rowObsExt);
	}
}

void ssMLFitState::compute(int want, FitContext *fc)
{
	if (want & (FF_COMPUTE_INITIAL_FIT | FF_COMPUTE_PREOPTIMIZE)) return;

	auto *oo = this;
	ssMLFitState *state = this;
	auto dataColumns	= expectation->getDataColumns();
	omxData *data = expectation->data;
	int rowcount = data->rows;

	Eigen::VectorXi contRemove(cov->cols);

	for (int row=0; row < rowcount; ++row) {
		mxLogSetCurrentRow(row);

		omxDataRow(data, row, dataColumns, smallRow);
		if (verbose >= 2) {
			mxLog("row %d", row);
			omxPrint(smallRow, "row");
		}

		omxSetExpectationComponent(expectation, "y", smallRow);

		expectation->loadDefVars(row);
		if(row == 0){
			omxSetExpectationComponent(expectation, "Reset", NULL);
		}

		omxExpectationCompute(fc, expectation, NULL);

		int numCont = 0;
		for(int j = 0; j < dataColumns.size(); j++) {
			if (omxDataElementMissing(data, row, dataColumns[j])) {
				contRemove[j] = 1;
			} else {
				contRemove[j] = 0;
				++numCont;
			}
		}
		omxSetMatrixElement(otherRowwiseValues, row, 1, numCont); // set second column to number of observed variables
		if (!numCont) {
			omxSetMatrixElement(rowLikelihoods, row, 0, 1.0);
			omxSetMatrixElement(otherRowwiseValues, row, 0, NA_REAL); // set first column to NA
			continue;
		}

		omxMatrix *smallMeans = omxGetExpectationComponent(expectation, "means");
		omxRemoveElements(smallMeans, contRemove.data());
		omxMatrix *smallCov = omxGetExpectationComponent(expectation, "inverse");
		if(OMX_DEBUG_ROWS(row)) { omxPrint(smallCov, "Inverse of Local Covariance Matrix in state space model"); }
		//Get covInfo from state space expectation
		int info = (int) omxGetExpectationComponent(expectation, "covInfo")->data[0];
		if(info!=0) {
			EigenMatrixAdaptor Ecov(smallCov);
			if (Ecov.rows() > 50) {
				if (fc) fc->recordIterationError("%s: expected covariance matrix is "
								 "not positive-definite in data row %d",
								 oo->name(), row);
			} else {
				std::string empty = std::string("");
				std::string buf = mxStringifyMatrix("covariance", Ecov, empty);
				if (fc) fc->recordIterationError("%s: expected covariance matrix is "
								 "not positive-definite in data row %d; Details:\n%s",
								 oo->name(), row, buf.c_str());
			}
			omxSetMatrixElement(oo->matrix, 0, 0, NA_REAL);
			return;
		}

		double determinant = *omxGetExpectationComponent(expectation, "determinant")->data;
		if(OMX_DEBUG_ROWS(row)) { mxLog("0.5*log(det(Cov)) is: %3.3f", determinant);}

		omxCopyMatrix(contRow, smallRow);
		omxRemoveElements(contRow, contRemove.data()); 	// Reduce the row to just continuous.
		if (verbose >= 2) {
			omxPrint(contRow, "contRow");
			omxPrint(smallMeans, "smallMeans");
		}
		omxDAXPY(-1.0, smallMeans, contRow);

		/* Calculate Row Likelihood */
		/* Mathematically: (2*pi)^cols * 1/sqrt(determinant(ExpectedCov)) * (dataRow %*% (solve(ExpectedCov)) %*% t(dataRow))^(1/2) */
		omxDSYMV(1.0, smallCov, contRow, 0, RCX);
		double Q = omxDDOT(contRow, RCX);
		if (verbose >= 2) {
			EigenMatrixAdaptor EsmallCov(smallCov);
			EsmallCov.derived() = EsmallCov.selfadjointView<Eigen::Upper>();
			mxPrintMat("smallcov", EsmallCov);
			omxPrint(contRow, "contRow");
			mxLog("Q=%f", Q);
		}
		omxSetMatrixElement(otherRowwiseValues, row, 0, Q);

		double rowLikelihood = pow(2 * M_PI, -.5 * numCont) * (1.0/exp(determinant)) * exp(-.5 * Q);

		omxSetMatrixElement(rowLikelihoods, row, 0, rowLikelihood);
	}

	if (!state->returnRowLikelihoods) {
		double sum = 0.0;
		// floating-point addition is not associative,
		// so we serialized the following reduction operation.
		for(int i = 0; i < data->rows; i++) {
			double prob = omxVectorElement(state->rowLikelihoods, i);
			//mxLog("[%d] %g", i, -2.0 * log(prob));
			sum += log(prob);
		}
		if(OMX_DEBUG) {mxLog("%s: total likelihood is %3.3f", oo->name(), sum);}
		omxSetMatrixElement(oo->matrix, 0, 0, -2.0 * sum);
	} else {
		omxCopyMatrix(oo->matrix, state->rowLikelihoods);
	}
}

ssMLFitState::~ssMLFitState()
{
	ssMLFitState *state = this;
	omxFreeMatrix(state->smallRow);
	omxFreeMatrix(state->contRow);
	omxFreeMatrix(state->rowLikelihoods);
	omxFreeMatrix(state->RCX);
	omxFreeMatrix(state->otherRowwiseValues);
}

omxFitFunction *ssMLFitInit()
{ return new ssMLFitState; }

void ssMLFitState::init()
{
	auto *oo = this;
	auto *state = this;

	oo->openmpUser = false;
	oo->canDuplicate = true;

	ProtectedSEXP Rverbose(R_do_slot(rObj, Rf_install("verbose")));
	verbose = Rf_asInteger(Rverbose);

	state->returnRowLikelihoods = Rf_asInteger(R_do_slot(oo->rObj, Rf_install("vector")));
	units = returnRowLikelihoods? FIT_UNITS_PROBABILITY : FIT_UNITS_MINUS2LL;

	state->populateRowDiagnostics = Rf_asInteger(R_do_slot(oo->rObj, Rf_install("rowDiagnostics")));

	auto *data = expectation->data;
	if (data->hasWeight() || data->hasFreq()) {
		mxThrow("%s: row frequencies or weights provided in '%s' are not supported",
			 expectation->name, data->name);
	}

	omxState *currentState = oo->matrix->currentState;
	state->rowLikelihoods = omxInitMatrix(data->rows, 1, TRUE, currentState);
	state->otherRowwiseValues = omxInitMatrix(data->rows, 2, TRUE, currentState);
	state->cov = omxGetExpectationComponent(expectation, "cov");

	int covCols = state->cov->cols;
	state->smallRow = omxInitMatrix(1, covCols, TRUE, currentState);
	state->contRow = omxInitMatrix(covCols, 1, TRUE, currentState);
	state->RCX = omxInitMatrix(1, covCols, TRUE, currentState);
}
<commit_msg>Fix conformability issues (try#2)<commit_after> /*
 *  Copyright 2016-2019 by the individuals mentioned in the source code history
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include "omxFitFunction.h"
#include "Compute.h"
#include "EnableWarnings.h"

struct ssMLFitState : omxFitFunction {
	int verbose;
	bool returnRowLikelihoods;
	bool populateRowDiagnostics;
	omxMatrix *cov;
	omxMatrix *smallRow;
	omxMatrix *contRow;
	omxMatrix *rowLikelihoods;
	omxMatrix* otherRowwiseValues;

	virtual ~ssMLFitState();
	virtual void init();
	virtual void compute(int ffcompute, FitContext *fc);
	virtual void populateAttr(SEXP algebra);
};

void ssMLFitState::populateAttr(SEXP algebra)
{
	ssMLFitState *argStruct = this;

	if(argStruct->populateRowDiagnostics){
		SEXP rowLikelihoodsExt;
		SEXP rowObsExt;
		SEXP rowDistExt;
		omxMatrix *rowLikelihoodsInt = argStruct->rowLikelihoods;
		omxMatrix *otherRowwiseValuesInt = argStruct->otherRowwiseValues;
		Rf_protect(rowLikelihoodsExt = Rf_allocVector(REALSXP, rowLikelihoodsInt->rows));
		Rf_protect(rowObsExt = Rf_allocVector(REALSXP, rowLikelihoodsInt->rows));
		Rf_protect(rowDistExt = Rf_allocVector(REALSXP, rowLikelihoodsInt->rows));
		for(int row = 0; row < rowLikelihoodsInt->rows; row++) {
			REAL(rowLikelihoodsExt)[row] = omxMatrixElement(rowLikelihoodsInt, row, 0);
			REAL(rowDistExt)[row] = omxMatrixElement(otherRowwiseValuesInt, row, 0);
			REAL(rowObsExt)[row] = omxMatrixElement(otherRowwiseValuesInt, row, 1);
		}
		Rf_setAttrib(algebra, Rf_install("likelihoods"), rowLikelihoodsExt);
		Rf_setAttrib(algebra, Rf_install("rowDist"), rowDistExt);
		Rf_setAttrib(algebra, Rf_install("rowObs"), rowObsExt);
	}
}

void ssMLFitState::compute(int want, FitContext *fc)
{
	if (want & (FF_COMPUTE_INITIAL_FIT | FF_COMPUTE_PREOPTIMIZE)) return;

	auto *oo = this;
	ssMLFitState *state = this;
	auto dataColumns	= expectation->getDataColumns();
	omxData *data = expectation->data;
	int rowcount = data->rows;

	Eigen::VectorXi contRemove(cov->cols);

	for (int row=0; row < rowcount; ++row) {
		mxLogSetCurrentRow(row);

		omxDataRow(data, row, dataColumns, smallRow);
		if (verbose >= 2) {
			mxLog("row %d", row);
			omxPrint(smallRow, "row");
		}

		omxSetExpectationComponent(expectation, "y", smallRow);

		expectation->loadDefVars(row);
		if(row == 0){
			omxSetExpectationComponent(expectation, "Reset", NULL);
		}

		omxExpectationCompute(fc, expectation, NULL);

		int numCont = 0;
		for(int j = 0; j < dataColumns.size(); j++) {
			if (omxDataElementMissing(data, row, dataColumns[j])) {
				contRemove[j] = 1;
			} else {
				contRemove[j] = 0;
				++numCont;
			}
		}
		omxSetMatrixElement(otherRowwiseValues, row, 1, numCont); // set second column to number of observed variables
		if (!numCont) {
			omxSetMatrixElement(rowLikelihoods, row, 0, 1.0);
			omxSetMatrixElement(otherRowwiseValues, row, 0, NA_REAL); // set first column to NA
			continue;
		}

		omxMatrix *smallMeans = omxGetExpectationComponent(expectation, "means");
		omxRemoveElements(smallMeans, contRemove.data());
		omxMatrix *smallCov = omxGetExpectationComponent(expectation, "inverse");
		if(OMX_DEBUG_ROWS(row)) { omxPrint(smallCov, "Inverse of Local Covariance Matrix in state space model"); }
		//Get covInfo from state space expectation
		int info = (int) omxGetExpectationComponent(expectation, "covInfo")->data[0];
		if(info!=0) {
			EigenMatrixAdaptor Ecov(smallCov);
			if (Ecov.rows() > 50) {
				if (fc) fc->recordIterationError("%s: expected covariance matrix is "
								 "not positive-definite in data row %d",
								 oo->name(), row);
			} else {
				std::string empty = std::string("");
				std::string buf = mxStringifyMatrix("covariance", Ecov, empty);
				if (fc) fc->recordIterationError("%s: expected covariance matrix is "
								 "not positive-definite in data row %d; Details:\n%s",
								 oo->name(), row, buf.c_str());
			}
			omxSetMatrixElement(oo->matrix, 0, 0, NA_REAL);
			return;
		}

		double determinant = *omxGetExpectationComponent(expectation, "determinant")->data;
		if(OMX_DEBUG_ROWS(row)) { mxLog("0.5*log(det(Cov)) is: %3.3f", determinant);}

		omxCopyMatrix(contRow, smallRow);
		omxRemoveElements(contRow, contRemove.data()); 	// Reduce the row to just continuous.
		if (verbose >= 2) {
			omxPrint(contRow, "contRow");
			omxPrint(smallMeans, "smallMeans");
		}
		omxDAXPY(-1.0, smallMeans, contRow);

		/* Calculate Row Likelihood */
		/* Mathematically: (2*pi)^cols * 1/sqrt(determinant(ExpectedCov)) * (dataRow %*% (solve(ExpectedCov)) %*% t(dataRow))^(1/2) */
		double Q;
		{
			EigenMatrixAdaptor EsmallCov(smallCov);
			EigenVectorAdaptor EcontRow(contRow);
			Q = EcontRow.transpose() * EsmallCov.selfadjointView<Eigen::Upper>() * EcontRow;
		}
		if (verbose >= 2) {
			EigenMatrixAdaptor EsmallCov(smallCov);
			EsmallCov.derived() = EsmallCov.selfadjointView<Eigen::Upper>();
			mxPrintMat("smallcov", EsmallCov);
			omxPrint(contRow, "contRow");
			mxLog("Q=%f", Q);
		}
		omxSetMatrixElement(otherRowwiseValues, row, 0, Q);

		double rowLikelihood = pow(2 * M_PI, -.5 * numCont) * (1.0/exp(determinant)) * exp(-.5 * Q);

		omxSetMatrixElement(rowLikelihoods, row, 0, rowLikelihood);
	}

	if (!state->returnRowLikelihoods) {
		double sum = 0.0;
		// floating-point addition is not associative,
		// so we serialized the following reduction operation.
		for(int i = 0; i < data->rows; i++) {
			double prob = omxVectorElement(state->rowLikelihoods, i);
			//mxLog("[%d] %g", i, -2.0 * log(prob));
			sum += log(prob);
		}
		if(OMX_DEBUG) {mxLog("%s: total likelihood is %3.3f", oo->name(), sum);}
		omxSetMatrixElement(oo->matrix, 0, 0, -2.0 * sum);
	} else {
		omxCopyMatrix(oo->matrix, state->rowLikelihoods);
	}
}

ssMLFitState::~ssMLFitState()
{
	ssMLFitState *state = this;
	omxFreeMatrix(state->smallRow);
	omxFreeMatrix(state->contRow);
	omxFreeMatrix(state->rowLikelihoods);
	omxFreeMatrix(state->otherRowwiseValues);
}

omxFitFunction *ssMLFitInit()
{ return new ssMLFitState; }

void ssMLFitState::init()
{
	auto *oo = this;
	auto *state = this;

	oo->openmpUser = false;
	oo->canDuplicate = true;

	ProtectedSEXP Rverbose(R_do_slot(rObj, Rf_install("verbose")));
	verbose = Rf_asInteger(Rverbose);

	state->returnRowLikelihoods = Rf_asInteger(R_do_slot(oo->rObj, Rf_install("vector")));
	units = returnRowLikelihoods? FIT_UNITS_PROBABILITY : FIT_UNITS_MINUS2LL;

	state->populateRowDiagnostics = Rf_asInteger(R_do_slot(oo->rObj, Rf_install("rowDiagnostics")));

	auto *data = expectation->data;
	if (data->hasWeight() || data->hasFreq()) {
		mxThrow("%s: row frequencies or weights provided in '%s' are not supported",
			 expectation->name, data->name);
	}

	omxState *currentState = oo->matrix->currentState;
	state->rowLikelihoods = omxInitMatrix(data->rows, 1, TRUE, currentState);
	state->otherRowwiseValues = omxInitMatrix(data->rows, 2, TRUE, currentState);
	state->cov = omxGetExpectationComponent(expectation, "cov");

	int covCols = state->cov->cols;
	state->smallRow = omxInitMatrix(1, covCols, TRUE, currentState);
	state->contRow = omxInitMatrix(covCols, 1, TRUE, currentState);
}
<|endoftext|>


<commit_before>/* <x0/StackTrace.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 * http://www.xzero.ws/
 *
 * (c) 2009-2010 Christian Parpart <trapni@gentoo.org>
 */

#include <x0/StackTrace.h>
#include <x0/NativeSymbol.h>
#include <boost/lexical_cast.hpp>
#include <execinfo.h>
#include <cxxabi.h>
#include <dlfcn.h>
#include <strings.h>

namespace x0 {

StackTrace::StackTrace(int numSkipFrames, int numMaxFrames)
{
	skip_ = 1 + numSkipFrames;
	//buffer_.resize(numSkipFrames + numMaxFrames);
	addresses_ = new void *[skip_ + numMaxFrames];
	count_ = backtrace(addresses_, skip_ + numMaxFrames);
}

StackTrace::~StackTrace()
{
	delete[] addresses_;
}

void StackTrace::generate(bool verbose)
{
	if (!symbols_.empty())
		return;

	for (int i = 0; i < count_; ++i)
	{
		void *address = addresses_[skip_ + i];

		buffer_.push_back('[');
		buffer_.push_back(i);
		buffer_.push_back("] ");

		std::size_t begin = buffer_.size();
		buffer_.reserve(buffer_.size() + 512);

		buffer_ << NativeSymbol(address/*, verbose*/);

		std::size_t count = buffer_.size() - begin;
		symbols_.push_back(buffer_.ref(begin, count));

		buffer_.push_back("\n");
	}
}

/** retrieves the number of frames captured. */
int StackTrace::length() const
{
	return count_;
}

/** retrieves the frame information of a frame at given index. */
const BufferRef& StackTrace::at(int index) const
{
	return symbols_[index];
}

/** retrieves full stack trace information (of all captured frames). */
const char *StackTrace::c_str() const
{
	const_cast<StackTrace *>(this)->generate(true);

	return const_cast<StackTrace *>(this)->buffer_.c_str();
}

} // namespace x0
<commit_msg>[base] StackTrace: fixes looping over all frames, which exceeded by skip_ number of frames.<commit_after>/* <x0/StackTrace.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 * http://www.xzero.ws/
 *
 * (c) 2009-2010 Christian Parpart <trapni@gentoo.org>
 */

#include <x0/StackTrace.h>
#include <x0/NativeSymbol.h>
#include <boost/lexical_cast.hpp>
#include <execinfo.h>
#include <cxxabi.h>
#include <dlfcn.h>
#include <strings.h>

namespace x0 {

StackTrace::StackTrace(int numSkipFrames, int numMaxFrames)
{
	skip_ = 1 + numSkipFrames;
	//buffer_.resize(numSkipFrames + numMaxFrames);
	addresses_ = new void *[skip_ + numMaxFrames];
	count_ = backtrace(addresses_, skip_ + numMaxFrames);
}

StackTrace::~StackTrace()
{
	delete[] addresses_;
}

void StackTrace::generate(bool verbose)
{
	if (!symbols_.empty())
		return;

	for (int i = skip_; i < count_; ++i) {
		void *address = addresses_[i];

		buffer_.push_back('[');
		buffer_.push_back(i - skip_);
		buffer_.push_back("] ");

		std::size_t begin = buffer_.size();
		buffer_.reserve(buffer_.size() + 512);

		buffer_ << NativeSymbol(address/*, verbose*/);

		std::size_t count = buffer_.size() - begin;
		symbols_.push_back(buffer_.ref(begin, count));

		buffer_.push_back("\n");
	}
}

/** retrieves the number of frames captured. */
int StackTrace::length() const
{
	return count_;
}

/** retrieves the frame information of a frame at given index. */
const BufferRef& StackTrace::at(int index) const
{
	return symbols_[index];
}

/** retrieves full stack trace information (of all captured frames). */
const char *StackTrace::c_str() const
{
	const_cast<StackTrace *>(this)->generate(true);

	return const_cast<StackTrace *>(this)->buffer_.c_str();
}

} // namespace x0
<|endoftext|>


<commit_before>/**
 * @file exopanelsnapshotflickr.cpp
 * @brief Provides the UI for uploading a snapshot to Flickr.
 *
 * $LicenseInfo:firstyear=2012&license=viewerlgpl$
 * Copyright (C) 2012 Katharine Berry
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llcombobox.h"
#include "llsidetraypanelcontainer.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"

#include "llfloatersnapshot.h" // FIXME: replace with a snapshot storage model
#include "llpanelsnapshot.h"
#include "llviewercontrol.h" // gSavedSettings
#include "llviewerwindow.h"
#include "llagent.h"
#include "llviewerregion.h"
#include "llslurl.h"
#include "llnotificationsutil.h"

#include "exoflickr.h"
#include "exoflickrauth.h"

class exoPanelSnapshotFlickr
:	public LLPanelSnapshot
{
	LOG_CLASS(exoPanelSnapshotFlickr);

public:
	exoPanelSnapshotFlickr();
	/*virtual*/ BOOL postBuild();
	/*virtual*/ void onOpen(const LLSD& key);

private:
	/*virtual*/ std::string getWidthSpinnerName() const		{ return "flickr_snapshot_width"; }
	/*virtual*/ std::string getHeightSpinnerName() const	{ return "flickr_snapshot_height"; }
	/*virtual*/ std::string getAspectRatioCBName() const	{ return "flickr_keep_aspect_check"; }
	/*virtual*/ std::string getImageSizeComboName() const	{ return "flickr_size_combo"; }
	/*virtual*/ std::string getImageSizePanelName() const	{ return "flickr_image_size_lp"; }
	/*virtual*/ LLFloaterSnapshot::ESnapshotFormat getImageFormat() const;
	// <FS:TS> Firestorm-specific changes for temp upload and parm saving fixes
	/*virtual*/ std::string getTempUploadCBName() const		{ return LLStringUtil::null; }
	/*virtual*/ std::string getImageSizeControlName() const	{ return "LastSnapshotToFlickrResolution"; }
	// </FS:TS>
	/*virtual*/ void updateControls(const LLSD& info);

	void onFormatComboCommit(LLUICtrl* ctrl);
	void onQualitySliderCommit(LLUICtrl* ctrl);
	void onRatingComboCommit(LLUICtrl *ctrl);
	void onUpload();
	void swapTab(S32 btn_idx);
	void flickrAuthResponse(bool success, const LLSD& response);
	void uploadCallback(bool success, const LLSD& response);
};

static LLRegisterPanelClassWrapper<exoPanelSnapshotFlickr> panel_class("exopanelsnapshotflickr");

void exoPanelSnapshotFlickr::onOpen(const LLSD& key)
{
	// If the snapshot type isn't JPEG or PNG we have to refresh
	LLFloaterSnapshot::ESnapshotFormat fmt = (LLFloaterSnapshot::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat");
	if(fmt != LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG && fmt != LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG)
	{
		LLFloaterSnapshot::getInstance()->notify(LLSD().with("image-format-change", true));
	}
	LLPanelSnapshot::onOpen(key);

	// Reauthorise if necessary.
	LLFloaterSnapshot::getInstance()->notify(LLSD().with("set-working", true));
	new exoFlickrAuth(boost::bind(&exoPanelSnapshotFlickr::flickrAuthResponse, this, _1, _2));
}

exoPanelSnapshotFlickr::exoPanelSnapshotFlickr()
{
	mCommitCallbackRegistrar.add("Flickr.Upload",	boost::bind(&exoPanelSnapshotFlickr::onUpload,	this));
	// <FS:TS> Removed because we use a tab container instead of buttons
	// mCommitCallbackRegistrar.add("Flickr.Cancel",	boost::bind(&exoPanelSnapshotFlickr::cancel,	this));
	// mCommitCallbackRegistrar.add("Flickr.Metadata",	boost::bind(&exoPanelSnapshotFlickr::swapTab,	this, 0));
	// mCommitCallbackRegistrar.add("Flickr.Settings",	boost::bind(&exoPanelSnapshotFlickr::swapTab,	this, 1));
	// </FS:TS>
}

void exoPanelSnapshotFlickr::flickrAuthResponse(bool success, const LLSD& response)
{
	if(!success)
	{
		// Complain about failed auth here.
		LL_WARNS("Flickr") << "Flickr authentication failed." << LL_ENDL;
		cancel();
	}
	else
	{
		LLFloaterSnapshot::getInstance()->notify(LLSD().with("set-ready", true));
	}
}

// <FS:TS> Removed because we use a tab container
//void exoPanelSnapshotFlickr::swapTab(S32 which)
//{
//	LLButton *buttons[2] = {
//		getChild<LLButton>("metadata_btn"),
//		getChild<LLButton>("settings_btn"),
//	};
//
//	LLButton* clicked_btn = buttons[which];
//	LLButton* other_btn = buttons[!which];
//	LLSideTrayPanelContainer* container =
//		getChild<LLSideTrayPanelContainer>("flickr_panel_container");
//
//	container->selectTab(clicked_btn->getToggleState() ? which : !which);
//	other_btn->toggleState();
//}
// </FS:TS>

BOOL exoPanelSnapshotFlickr::postBuild()
{
	getChild<LLUICtrl>("title_form")->setFocus(TRUE);
	getChild<LLUICtrl>("image_quality_slider")->setCommitCallback(boost::bind(&exoPanelSnapshotFlickr::onQualitySliderCommit, this, _1));
	getChild<LLUICtrl>("flickr_format_combo")->setCommitCallback(boost::bind(&exoPanelSnapshotFlickr::onFormatComboCommit, this, _1));
	getChild<LLUICtrl>("rating_combo")->setCommitCallback(boost::bind(&exoPanelSnapshotFlickr::onRatingComboCommit, this, _1));
	// <FS:TS> Removed because we use a tab container instead of buttons
	//getChild<LLButton>("metadata_btn")->setToggleState(TRUE);
	// </FS:TS>

	return LLPanelSnapshot::postBuild();
}

// virtual
void exoPanelSnapshotFlickr::updateControls(const LLSD& info)
{
	LLFloaterSnapshot::ESnapshotFormat fmt = (LLFloaterSnapshot::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat");
	getChild<LLComboBox>("local_format_combo")->selectNthItem((S32) fmt);

	const bool show_quality_ctrls = (fmt == LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
	getChild<LLUICtrl>("image_quality_slider")->setVisible(show_quality_ctrls);
	getChild<LLUICtrl>("image_quality_level")->setVisible(show_quality_ctrls);

	getChild<LLUICtrl>("image_quality_slider")->setValue(gSavedSettings.getS32("SnapshotQuality"));
	updateImageQualityLevel();

	const bool have_snapshot = info.has("have-snapshot") ? info["have-snapshot"].asBoolean() : true;
	getChild<LLUICtrl>("upload_btn")->setEnabled(have_snapshot);

	getChild<LLUICtrl>("rating_combo")->setValue(gSavedSettings.getS32("ExodusFlickrLastRating"));
}

void exoPanelSnapshotFlickr::onQualitySliderCommit(LLUICtrl* ctrl)
{
	updateImageQualityLevel();

	LLSliderCtrl* slider = (LLSliderCtrl*)ctrl;
	S32 quality_val = llfloor((F32)slider->getValue().asReal());
	LLSD info;
	info["image-quality-change"] = quality_val;
	LLFloaterSnapshot::getInstance()->notify(info);
}

void exoPanelSnapshotFlickr::onFormatComboCommit(LLUICtrl* ctrl)
{
	LLFloaterSnapshot::getInstance()->notify(LLSD().with("image-format-change", true));
}

void exoPanelSnapshotFlickr::onRatingComboCommit(LLUICtrl* ctrl)
{
	gSavedSettings.setS32("ExodusFlickrLastRating", ctrl->getValue().asInteger());
}

void exoPanelSnapshotFlickr::onUpload()
{
	// Build metadata params
	LLSD params;
	params["title"] = getChild<LLUICtrl>("title_form")->getValue();
	params["safety_level"] = getChild<LLUICtrl>("rating_combo")->getValue();
	std::ostringstream tags;
	std::ostringstream description;
	tags << getChild<LLUICtrl>("tags_form")->getValue().asString();
	description << getChild<LLUICtrl>("description_form")->getValue().asString();

	// Deal with location inclusion, if necessary.
	if(getChild<LLUICtrl>("location_check")->getValue().asBoolean())
	{
		// Work out our position.
		LLVector3d global = gAgent.getPositionGlobal();
		LLViewerRegion* region = gAgent.getRegion();
		if(region)
		{
			LLVector3 region_pos = region->getPosRegionFromGlobal(global);
			std::string region_name = region->getName();
			tags << " \"secondlife:region=" << region_name << "\"";
			tags << " secondlife:x=" << llround(region_pos[VX]);
			tags << " secondlife:y=" << llround(region_pos[VY]);
			tags << " secondlife:z=" << llround(region_pos[VZ]);

			if(gSavedSettings.getBOOL("ExodusFlickrIncludeSLURL"))
			{
				LLSLURL url(region_name, region_pos);
				if((int)description.tellp() != 0)
				{
					description << "\n\n";
				}
				description << "<a href='" << url.getSLURLString() << "'>";
				description << "Taken at " << region_name << " (";
				description << llround(region_pos[VX]) << ", ";
				description << llround(region_pos[VY]) << ", ";
				description << llround(region_pos[VZ]) << ")";
				description << "";
			}
		}
		else
		{
			tags << " \"secondlife:region=(unknown)\"";
		}
		tags << " secondlife:global_x=" << global[VX];
		tags << " secondlife:global_y=" << global[VY];
		tags << " secondlife:global_z=" << global[VZ];
	}

	params["tags"] = tags.str();
	params["description"] = description.str();
	exoFlickr::uploadPhoto(params, LLFloaterSnapshot::getImageData(), boost::bind(&exoPanelSnapshotFlickr::uploadCallback, this, _1, _2));

	gViewerWindow->playSnapshotAnimAndSound();

	LLFloaterSnapshot::postSave();
}

void exoPanelSnapshotFlickr::uploadCallback(bool success, const LLSD& response)
{
	LLSD args;
	if(success && response["stat"].asString() == "ok")
	{
		args["ID"] = response["photoid"];
		LLNotificationsUtil::add("ExodusFlickrUploadComplete", args);
		LLFloaterSnapshot::getInstance()->notify(LLSD().with("set-finished", LLSD().with("ok", true).with("msg", "flickr")));
	}
	else
	{
		LLFloaterSnapshot::getInstance()->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "flickr")));
	}
}

// virtual
LLFloaterSnapshot::ESnapshotFormat exoPanelSnapshotFlickr::getImageFormat() const
{
	std::string id = getChild<LLComboBox>("flickr_format_combo")->getValue().asString();
	if(id == "JPEG")
	{
		return LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG;
	}
	// Default to PNG if we get something we don't understand (or PNG).
	return LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG;
}
<commit_msg>Flickr uploader now includes parcel name.<commit_after>/**
 * @file exopanelsnapshotflickr.cpp
 * @brief Provides the UI for uploading a snapshot to Flickr.
 *
 * $LicenseInfo:firstyear=2012&license=viewerlgpl$
 * Copyright (C) 2012 Katharine Berry
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llcombobox.h"
#include "llsidetraypanelcontainer.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"

#include "llfloatersnapshot.h" // FIXME: replace with a snapshot storage model
#include "llpanelsnapshot.h"
#include "llviewercontrol.h" // gSavedSettings
#include "llviewerwindow.h"
#include "llagent.h"
#include "llviewerregion.h"
#include "llslurl.h"
#include "llnotificationsutil.h"
#include "llviewerparcelmgr.h"

#include <algorithm>

#include "exoflickr.h"
#include "exoflickrauth.h"

class exoPanelSnapshotFlickr
:	public LLPanelSnapshot
{
	LOG_CLASS(exoPanelSnapshotFlickr);

public:
	exoPanelSnapshotFlickr();
	/*virtual*/ BOOL postBuild();
	/*virtual*/ void onOpen(const LLSD& key);

private:
	/*virtual*/ std::string getWidthSpinnerName() const		{ return "flickr_snapshot_width"; }
	/*virtual*/ std::string getHeightSpinnerName() const	{ return "flickr_snapshot_height"; }
	/*virtual*/ std::string getAspectRatioCBName() const	{ return "flickr_keep_aspect_check"; }
	/*virtual*/ std::string getImageSizeComboName() const	{ return "flickr_size_combo"; }
	/*virtual*/ std::string getImageSizePanelName() const	{ return "flickr_image_size_lp"; }
	/*virtual*/ LLFloaterSnapshot::ESnapshotFormat getImageFormat() const;
	// <FS:TS> Firestorm-specific changes for temp upload and parm saving fixes
	/*virtual*/ std::string getTempUploadCBName() const		{ return LLStringUtil::null; }
	/*virtual*/ std::string getImageSizeControlName() const	{ return "LastSnapshotToFlickrResolution"; }
	// </FS:TS>
	/*virtual*/ void updateControls(const LLSD& info);

	void onFormatComboCommit(LLUICtrl* ctrl);
	void onQualitySliderCommit(LLUICtrl* ctrl);
	void onRatingComboCommit(LLUICtrl *ctrl);
	void onUpload();
	void swapTab(S32 btn_idx);
	void flickrAuthResponse(bool success, const LLSD& response);
	void uploadCallback(bool success, const LLSD& response);
};

static LLRegisterPanelClassWrapper<exoPanelSnapshotFlickr> panel_class("exopanelsnapshotflickr");

void exoPanelSnapshotFlickr::onOpen(const LLSD& key)
{
	// If the snapshot type isn't JPEG or PNG we have to refresh
	LLFloaterSnapshot::ESnapshotFormat fmt = (LLFloaterSnapshot::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat");
	if(fmt != LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG && fmt != LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG)
	{
		LLFloaterSnapshot::getInstance()->notify(LLSD().with("image-format-change", true));
	}
	LLPanelSnapshot::onOpen(key);

	// Reauthorise if necessary.
	LLFloaterSnapshot::getInstance()->notify(LLSD().with("set-working", true));
	new exoFlickrAuth(boost::bind(&exoPanelSnapshotFlickr::flickrAuthResponse, this, _1, _2));
}

exoPanelSnapshotFlickr::exoPanelSnapshotFlickr()
{
	mCommitCallbackRegistrar.add("Flickr.Upload",	boost::bind(&exoPanelSnapshotFlickr::onUpload,	this));
	// <FS:TS> Removed because we use a tab container instead of buttons
	// mCommitCallbackRegistrar.add("Flickr.Cancel",	boost::bind(&exoPanelSnapshotFlickr::cancel,	this));
	// mCommitCallbackRegistrar.add("Flickr.Metadata",	boost::bind(&exoPanelSnapshotFlickr::swapTab,	this, 0));
	// mCommitCallbackRegistrar.add("Flickr.Settings",	boost::bind(&exoPanelSnapshotFlickr::swapTab,	this, 1));
	// </FS:TS>
}

void exoPanelSnapshotFlickr::flickrAuthResponse(bool success, const LLSD& response)
{
	if(!success)
	{
		// Complain about failed auth here.
		LL_WARNS("Flickr") << "Flickr authentication failed." << LL_ENDL;
		cancel();
	}
	else
	{
		LLFloaterSnapshot::getInstance()->notify(LLSD().with("set-ready", true));
	}
}

// <FS:TS> Removed because we use a tab container
//void exoPanelSnapshotFlickr::swapTab(S32 which)
//{
//	LLButton *buttons[2] = {
//		getChild<LLButton>("metadata_btn"),
//		getChild<LLButton>("settings_btn"),
//	};
//
//	LLButton* clicked_btn = buttons[which];
//	LLButton* other_btn = buttons[!which];
//	LLSideTrayPanelContainer* container =
//		getChild<LLSideTrayPanelContainer>("flickr_panel_container");
//
//	container->selectTab(clicked_btn->getToggleState() ? which : !which);
//	other_btn->toggleState();
//}
// </FS:TS>

BOOL exoPanelSnapshotFlickr::postBuild()
{
	getChild<LLUICtrl>("title_form")->setFocus(TRUE);
	getChild<LLUICtrl>("image_quality_slider")->setCommitCallback(boost::bind(&exoPanelSnapshotFlickr::onQualitySliderCommit, this, _1));
	getChild<LLUICtrl>("flickr_format_combo")->setCommitCallback(boost::bind(&exoPanelSnapshotFlickr::onFormatComboCommit, this, _1));
	getChild<LLUICtrl>("rating_combo")->setCommitCallback(boost::bind(&exoPanelSnapshotFlickr::onRatingComboCommit, this, _1));
	// <FS:TS> Removed because we use a tab container instead of buttons
	//getChild<LLButton>("metadata_btn")->setToggleState(TRUE);
	// </FS:TS>

	return LLPanelSnapshot::postBuild();
}

// virtual
void exoPanelSnapshotFlickr::updateControls(const LLSD& info)
{
	LLFloaterSnapshot::ESnapshotFormat fmt = (LLFloaterSnapshot::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat");
	getChild<LLComboBox>("local_format_combo")->selectNthItem((S32) fmt);

	const bool show_quality_ctrls = (fmt == LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
	getChild<LLUICtrl>("image_quality_slider")->setVisible(show_quality_ctrls);
	getChild<LLUICtrl>("image_quality_level")->setVisible(show_quality_ctrls);

	getChild<LLUICtrl>("image_quality_slider")->setValue(gSavedSettings.getS32("SnapshotQuality"));
	updateImageQualityLevel();

	const bool have_snapshot = info.has("have-snapshot") ? info["have-snapshot"].asBoolean() : true;
	getChild<LLUICtrl>("upload_btn")->setEnabled(have_snapshot);

	getChild<LLUICtrl>("rating_combo")->setValue(gSavedSettings.getS32("ExodusFlickrLastRating"));
}

void exoPanelSnapshotFlickr::onQualitySliderCommit(LLUICtrl* ctrl)
{
	updateImageQualityLevel();

	LLSliderCtrl* slider = (LLSliderCtrl*)ctrl;
	S32 quality_val = llfloor((F32)slider->getValue().asReal());
	LLSD info;
	info["image-quality-change"] = quality_val;
	LLFloaterSnapshot::getInstance()->notify(info);
}

void exoPanelSnapshotFlickr::onFormatComboCommit(LLUICtrl* ctrl)
{
	LLFloaterSnapshot::getInstance()->notify(LLSD().with("image-format-change", true));
}

void exoPanelSnapshotFlickr::onRatingComboCommit(LLUICtrl* ctrl)
{
	gSavedSettings.setS32("ExodusFlickrLastRating", ctrl->getValue().asInteger());
}

void exoPanelSnapshotFlickr::onUpload()
{
	// Build metadata params
	LLSD params;
	params["title"] = getChild<LLUICtrl>("title_form")->getValue();
	params["safety_level"] = getChild<LLUICtrl>("rating_combo")->getValue();
	std::ostringstream tags;
	std::ostringstream description;
	tags << getChild<LLUICtrl>("tags_form")->getValue().asString();
	description << getChild<LLUICtrl>("description_form")->getValue().asString();

	// Deal with location inclusion, if necessary.
	if(getChild<LLUICtrl>("location_check")->getValue().asBoolean())
	{
		// Work out our position.
		LLVector3d global = gAgent.getPositionGlobal();
		LLViewerRegion* region = gAgent.getRegion();
		if(region)
		{
			LLVector3 region_pos = region->getPosRegionFromGlobal(global);
			std::string region_name = region->getName();
			std::string parcel_name = LLViewerParcelMgr::instance().getAgentParcelName();
			std::string parcel_name_tag(parcel_name); // We can't escape quotes, so just drop them.
			parcel_name_tag.erase(std::remove(parcel_name_tag.begin(), parcel_name_tag.end(), '"'), parcel_name_tag.end());
			tags << " \"secondlife:region=" << region_name << "\"";
			tags << " secondlife:x=" << llround(region_pos[VX]);
			tags << " secondlife:y=" << llround(region_pos[VY]);
			tags << " secondlife:z=" << llround(region_pos[VZ]);
			tags << " \"secondlife:parcel=" << parcel_name_tag << "\"";

			if(gSavedSettings.getBOOL("ExodusFlickrIncludeSLURL"))
			{
				LLSLURL url(region_name, region_pos);
				if((int)description.tellp() != 0)
				{
					description << "\n\n";
				}
				description << "<a href='" << url.getSLURLString() << "'>";
				description << "Taken at " << parcel_name;
				description << ", " << region_name << " (";
				description << llround(region_pos[VX]) << ", ";
				description << llround(region_pos[VY]) << ", ";
				description << llround(region_pos[VZ]) << ")";
				description << "";
			}
		}
		else
		{
			tags << " \"secondlife:region=(unknown)\"";
		}
		tags << " secondlife:global_x=" << global[VX];
		tags << " secondlife:global_y=" << global[VY];
		tags << " secondlife:global_z=" << global[VZ];
	}

	params["tags"] = tags.str();
	params["description"] = description.str();
	exoFlickr::uploadPhoto(params, LLFloaterSnapshot::getImageData(), boost::bind(&exoPanelSnapshotFlickr::uploadCallback, this, _1, _2));

	gViewerWindow->playSnapshotAnimAndSound();

	LLFloaterSnapshot::postSave();
}

void exoPanelSnapshotFlickr::uploadCallback(bool success, const LLSD& response)
{
	LLSD args;
	if(success && response["stat"].asString() == "ok")
	{
		args["ID"] = response["photoid"];
		LLNotificationsUtil::add("ExodusFlickrUploadComplete", args);
		LLFloaterSnapshot::getInstance()->notify(LLSD().with("set-finished", LLSD().with("ok", true).with("msg", "flickr")));
	}
	else
	{
		LLFloaterSnapshot::getInstance()->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "flickr")));
	}
}

// virtual
LLFloaterSnapshot::ESnapshotFormat exoPanelSnapshotFlickr::getImageFormat() const
{
	std::string id = getChild<LLComboBox>("flickr_format_combo")->getValue().asString();
	if(id == "JPEG")
	{
		return LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG;
	}
	// Default to PNG if we get something we don't understand (or PNG).
	return LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG;
}
<|endoftext|>


<commit_before>// include library
#include <stack>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>

///*
//
// src comments: comments in sass syntax (staring with //)
// css comments: multiline comments in css syntax (starting with /*)
//
// KEEP_COMMENT: keep src comments in the resulting css code
// STRIP_COMMENT: strip out all comments (either src or css)
// CONVERT_COMMENT: convert all src comments to css comments
//
//*/

// our own header
#include "sass2scss.h"

// using std::string
using namespace std;

// add namespace for c++
namespace Sass
{

	// return the actual prettify value from options
	#define PRETTIFY(converter) (converter.options - (converter.options & 248))
	// query the options integer to check if the option is enables
	#define KEEP_COMMENT(converter) ((converter.options & SASS2SCSS_KEEP_COMMENT) == SASS2SCSS_KEEP_COMMENT)
	#define STRIP_COMMENT(converter) ((converter.options & SASS2SCSS_STRIP_COMMENT) == SASS2SCSS_STRIP_COMMENT)
	#define CONVERT_COMMENT(converter) ((converter.options & SASS2SCSS_CONVERT_COMMENT) == SASS2SCSS_CONVERT_COMMENT)

	// some makros to access the indentation stack
	#define INDENT(converter) (converter.indents.top())

	// some makros to query comment parser status
	#define IS_PARSING(converter) (converter.comment == "")
	#define IS_COMMENT(converter) (converter.comment != "")
	#define IS_SRC_COMMENT(converter) (converter.comment == "//" && ! CONVERT_COMMENT(converter))
	#define IS_CSS_COMMENT(converter) (converter.comment == "/*" || (converter.comment == "//" && CONVERT_COMMENT(converter)))

	// pretty printer helper function
	static string closer (const converter& converter)
	{
		return PRETTIFY(converter) == 0 ? " }" :
		     PRETTIFY(converter) <= 1 ? " }" :
		       "\n" + INDENT(converter) + "}";
	}

	// pretty printer helper function
	static string opener (const converter& converter)
	{
		return PRETTIFY(converter) == 0 ? " { " :
		     PRETTIFY(converter) <= 2 ? " {" :
		       "\n" + INDENT(converter) + "{";
	}

	// flush whitespace and print additional text, but
	// only print additional chars and buffer whitespace
	string flush (string& sass, converter& converter)
	{

		// return flushed
		string scss = "";

		// print whitespace buffer
		scss += PRETTIFY(converter) > 0 ?
		        converter.whitespace : "";
		// reset whitespace buffer
		converter.whitespace = "";

		// remove possible newlines from string
		size_t pos_right = sass.find_last_not_of("\n\r");
		if (pos_right == string::npos) return scss;

		// get the linefeeds from the string
		string lfs = sass.substr(pos_right + 1);
		sass = sass.substr(0, pos_right + 1);

		// add newline as getline discharged it
		converter.whitespace += lfs + "\n";

		// maybe remove any leading whitespace
		if (PRETTIFY(converter) == 0)
		{
			// remove leading whitespace and update string
			size_t pos_left = sass.find_first_not_of(" \t\n\v\f\r");
			if (pos_left != string::npos) sass = sass.substr(pos_left);
		}

		// add flushed data
		scss += sass;

		// return string
		return scss;

	}
	// EO flush

	// process a line of the sass text
	string process (string& sass, converter& converter)
	{

		// resulting string
		string scss = "";

		// get postion of first meaningfull character in string
		size_t pos_left = sass.find_first_not_of(" \t\n\v\f\r");

		// special case for final run
		if (converter.end_of_file) pos_left = 0;

		// maybe has only whitespace
		if (pos_left == string::npos)
		{
			// just add complete whitespace
			converter.whitespace += sass + "\n";
		}
		// have meaningfull first char
		else
		{

			// extract and store indentation string
			string indent = sass.substr(0, pos_left);

			// line has less or same indentation
			// finalize previous open parser context
			if (indent.length() <= INDENT(converter).length())
			{

				// close multilinie comment
				if (IS_CSS_COMMENT(converter))
				{
					// check if comments will be stripped anyway
					if (!STRIP_COMMENT(converter)) scss += " */";
				}
				// close src comment comment
				else if (IS_SRC_COMMENT(converter))
				{
					// add a newline to avoid closer on same line
					// this would put the bracket in the comment node
					if (KEEP_COMMENT(converter)) scss += "\n";
				}
				// close css properties
				else if (converter.property)
				{
					// add closer unless in concat mode
					if (!converter.comma)
					{
						// if there was no colon we have a selector
						// looks like there were no inner properties
						if (converter.selector) scss += " {}";
						// add final semicolon
						else scss += ";";
					}
				}

				// reset comment state
				converter.comment = "";

			}

			// make sure we close every "higher" block
			while (indent.length() < INDENT(converter).length())
			{
				// pop stacked context
				converter.indents.pop();
				// print close bracket
				if (IS_PARSING(converter))
				{ scss += closer(converter); }
				else { scss += " */"; }
				// reset comment state
				converter.comment = "";
			}

			// reset converter state
			converter.selector = false;

			// check if we have sass property syntax
			if (sass.substr(pos_left, 1) == ":")
			{
				// get postion of first whitespace char
				size_t pos_wspace = sass.find_first_of(" \t\n\v\f\r", pos_left);
				// assertion check for valid result
				if (pos_wspace != string::npos)
				{
					// get position of the first real property value char
					// pseudo selectors get this far, but have no actual value
					size_t pos_value =  sass.find_first_not_of(" \t\n\v\f\r", pos_wspace);
					// assertion check for valid result
					if (pos_value != string::npos)
					{
						// create new string by interchanging the colon sign for property and value
						sass = indent + sass.substr(pos_left + 1, pos_wspace - pos_left - 1) + ":" + sass.substr(pos_wspace);
					}
				}

				// try to find a colon in the current line, but only ...
				size_t pos_colon = sass.find_first_not_of(":", pos_left);
				// assertion for valid result
				if (pos_colon != string::npos)
				{
					// ... after the first word (skip begining colons)
					pos_colon = sass.find_first_of(":", pos_colon);
					// it is a selector if there was no colon found
					converter.selector = pos_colon == string::npos;
				}

			}

			// replace some specific sass shorthand directives
			else if (sass.substr(pos_left, 1) == "=") { sass = indent + "@mixin " + sass.substr(pos_left + 1); }
			else if (sass.substr(pos_left, 1) == "+") { sass = indent + "@include " + sass.substr(pos_left + 1); }

			// add quotes for import if needed
			else if (sass.substr(pos_left, 7) == "@import")
			{
				// get positions for the actual import url
				size_t pos_import = sass.find_first_of(" \t\n\v\f\r", pos_left + 7);
				size_t pos_quote = sass.find_first_not_of(" \t\n\v\f\r", pos_import);
				// check if the url is quoted
				if (sass.substr(pos_quote, 1) != "\"")
				{
					// get position of the last char on the line
					size_t pos_end = sass.find_last_not_of(" \t\n\v\f\r");
					// assertion check for valid result
					if (pos_end != string::npos)
					{
						// add quotes around the full line after the import statement
						sass = sass.substr(0, pos_quote) + "\"" + sass.substr(pos_quote, pos_end - pos_quote + 1) + "\"";
					}
				}

			}
			else if (
				sass.substr(pos_left, 7) != "@return" &&
				sass.substr(pos_left, 8) != "@content"
			) {

				// try to find a colon in the current line, but only ...
				size_t pos_colon = sass.find_first_not_of(":", pos_left);
				// assertion for valid result
				if (pos_colon != string::npos)
				{
					// ... after the first word (skip begining colons)
					pos_colon = sass.find_first_of(":", pos_colon);
					// it is a selector if there was no colon found
					converter.selector = pos_colon == string::npos;
				}

			}

			// check if current line starts a comment
			string open = sass.substr(pos_left, 2);

			// current line has more indentation
			if (indent.length() >= INDENT(converter).length())
			{
				// not in comment mode
				if (IS_PARSING(converter))
				{
					// probably a property
					converter.property = true;
				}
			}
			// current line has more indentation
			if (indent.length() > INDENT(converter).length())
			{
				// not in comment mode
				if (IS_PARSING(converter))
				{
					// print block opener
					scss += opener(converter);
					// push new stack context
					converter.indents.push("");
					// store block indentation
					INDENT(converter) = indent;
				}
				// is and will be a src comment
				else if (!IS_CSS_COMMENT(converter))
				{
					// scss does not allow multiline src comments
					// therefore add forward slashes to all lines
					sass[INDENT(converter).length()+0] = '/';
					// there is an edge case here if indentation
					// is minimal (will overwrite the fist char)
					sass[INDENT(converter).length()+1] = '/';
					// could code around that, but I dont' think
					// this will ever be the cause for any trouble
				}
			}

			// line is opening a new comment
			if (open == "/*" || open == "//")
			{
				// reset the property state
				converter.property = false;
				// close previous comment
				if (IS_CSS_COMMENT(converter) && open != "")
				{
					if (!STRIP_COMMENT(converter) && !CONVERT_COMMENT(converter)) scss += " */";
				}
				// force single line comments
				// into a correct css comment
				if (CONVERT_COMMENT(converter))
				{
					if (IS_PARSING(converter))
					{ sass[pos_left + 1] = '*'; }
				}
				// set comment flag
				converter.comment = open;

			}

			// flush data only under certain conditions
			if (!(
				// strip css and src comments if option is set
				(IS_COMMENT(converter) && STRIP_COMMENT(converter)) ||
				// strip src comment even if strip option is not set
				// but only if the keep src comment option is not set
				(IS_SRC_COMMENT(converter) && ! KEEP_COMMENT(converter))
			))
			{
				// flush data and buffer whitespace
				scss += flush(sass, converter);
			}

			// get postion of last meaningfull char
			size_t pos_right = sass.find_last_not_of(" \t\n\v\f\r");

			// check for invalid result
			if (pos_right != string::npos)
			{

				// get the last meaningfull char
				string close = sass.substr(pos_right, 1);

				// check if next line should be concatenated (list mode)
				converter.comma = IS_PARSING(converter) && close == ",";

				// check if we have more than
				// one meaningfull char
				if (pos_right > 0)
				{

					// get the last two chars from string
					string close = sass.substr(pos_right - 1, 2);
					// update parser status for expicitly closed comment
					if (close == "*/") converter.comment = "";

				}

			}
			// EO have meaningfull chars from end

		}
		// EO have meaningfull chars from start

		// return scss
		return scss;

	}
	// EO process

	// the main converter function for c++
	char* sass2scss (const string sass, const int options)
	{

		// local variables
		string line;
		string scss = "";
		const char delim = '\n';
		stringstream stream(sass);

		// create converter variable
		converter converter;
		// initialise all options
		converter.comma = false;
		converter.property = false;
		converter.end_of_file = false;
		converter.comment = "";
		converter.whitespace = "";
		converter.indents.push("");
		converter.options = options;

		// read line by line and process them
		while(std::getline(stream, line, delim))
		{ scss += process(line, converter); }

		// create mutable string
		string closer = "";
		// set the end of file flag
		converter.end_of_file = true;
		// process to close all open blocks
		scss += process(closer, converter);

		// allocate new memory on the heap
		// caller has to free it after use
		char * cstr = new char [scss.length()+1];
		// create a copy of the string
		strcpy (cstr, scss.c_str());
		// return pointer
		return &cstr[0];

	}
	// EO sass2scss

}
// EO namespace

// implement for c
extern "C"
{

	char* sass2scss (const char* sass, const int options)
	{
		return Sass::sass2scss(sass, options);
	}

}
<commit_msg>Implements special handling for @extend keyword<commit_after>// include library
#include <stack>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>

///*
//
// src comments: comments in sass syntax (staring with //)
// css comments: multiline comments in css syntax (starting with /*)
//
// KEEP_COMMENT: keep src comments in the resulting css code
// STRIP_COMMENT: strip out all comments (either src or css)
// CONVERT_COMMENT: convert all src comments to css comments
//
//*/

// our own header
#include "sass2scss.h"

// using std::string
using namespace std;

// add namespace for c++
namespace Sass
{

	// return the actual prettify value from options
	#define PRETTIFY(converter) (converter.options - (converter.options & 248))
	// query the options integer to check if the option is enables
	#define KEEP_COMMENT(converter) ((converter.options & SASS2SCSS_KEEP_COMMENT) == SASS2SCSS_KEEP_COMMENT)
	#define STRIP_COMMENT(converter) ((converter.options & SASS2SCSS_STRIP_COMMENT) == SASS2SCSS_STRIP_COMMENT)
	#define CONVERT_COMMENT(converter) ((converter.options & SASS2SCSS_CONVERT_COMMENT) == SASS2SCSS_CONVERT_COMMENT)

	// some makros to access the indentation stack
	#define INDENT(converter) (converter.indents.top())

	// some makros to query comment parser status
	#define IS_PARSING(converter) (converter.comment == "")
	#define IS_COMMENT(converter) (converter.comment != "")
	#define IS_SRC_COMMENT(converter) (converter.comment == "//" && ! CONVERT_COMMENT(converter))
	#define IS_CSS_COMMENT(converter) (converter.comment == "/*" || (converter.comment == "//" && CONVERT_COMMENT(converter)))

	// pretty printer helper function
	static string closer (const converter& converter)
	{
		return PRETTIFY(converter) == 0 ? " }" :
		     PRETTIFY(converter) <= 1 ? " }" :
		       "\n" + INDENT(converter) + "}";
	}

	// pretty printer helper function
	static string opener (const converter& converter)
	{
		return PRETTIFY(converter) == 0 ? " { " :
		     PRETTIFY(converter) <= 2 ? " {" :
		       "\n" + INDENT(converter) + "{";
	}

	// flush whitespace and print additional text, but
	// only print additional chars and buffer whitespace
	string flush (string& sass, converter& converter)
	{

		// return flushed
		string scss = "";

		// print whitespace buffer
		scss += PRETTIFY(converter) > 0 ?
		        converter.whitespace : "";
		// reset whitespace buffer
		converter.whitespace = "";

		// remove possible newlines from string
		size_t pos_right = sass.find_last_not_of("\n\r");
		if (pos_right == string::npos) return scss;

		// get the linefeeds from the string
		string lfs = sass.substr(pos_right + 1);
		sass = sass.substr(0, pos_right + 1);

		// add newline as getline discharged it
		converter.whitespace += lfs + "\n";

		// maybe remove any leading whitespace
		if (PRETTIFY(converter) == 0)
		{
			// remove leading whitespace and update string
			size_t pos_left = sass.find_first_not_of(" \t\n\v\f\r");
			if (pos_left != string::npos) sass = sass.substr(pos_left);
		}

		// add flushed data
		scss += sass;

		// return string
		return scss;

	}
	// EO flush

	// process a line of the sass text
	string process (string& sass, converter& converter)
	{

		// resulting string
		string scss = "";

		// get postion of first meaningfull character in string
		size_t pos_left = sass.find_first_not_of(" \t\n\v\f\r");

		// special case for final run
		if (converter.end_of_file) pos_left = 0;

		// maybe has only whitespace
		if (pos_left == string::npos)
		{
			// just add complete whitespace
			converter.whitespace += sass + "\n";
		}
		// have meaningfull first char
		else
		{

			// extract and store indentation string
			string indent = sass.substr(0, pos_left);

			// line has less or same indentation
			// finalize previous open parser context
			if (indent.length() <= INDENT(converter).length())
			{

				// close multilinie comment
				if (IS_CSS_COMMENT(converter))
				{
					// check if comments will be stripped anyway
					if (!STRIP_COMMENT(converter)) scss += " */";
				}
				// close src comment comment
				else if (IS_SRC_COMMENT(converter))
				{
					// add a newline to avoid closer on same line
					// this would put the bracket in the comment node
					if (KEEP_COMMENT(converter)) scss += "\n";
				}
				// close css properties
				else if (converter.property)
				{
					// add closer unless in concat mode
					if (!converter.comma)
					{
						// if there was no colon we have a selector
						// looks like there were no inner properties
						if (converter.selector) scss += " {}";
						// add final semicolon
						else scss += ";";
					}
				}

				// reset comment state
				converter.comment = "";

			}

			// make sure we close every "higher" block
			while (indent.length() < INDENT(converter).length())
			{
				// pop stacked context
				converter.indents.pop();
				// print close bracket
				if (IS_PARSING(converter))
				{ scss += closer(converter); }
				else { scss += " */"; }
				// reset comment state
				converter.comment = "";
			}

			// reset converter state
			converter.selector = false;

			// check if we have sass property syntax
			if (sass.substr(pos_left, 1) == ":")
			{
				// get postion of first whitespace char
				size_t pos_wspace = sass.find_first_of(" \t\n\v\f\r", pos_left);
				// assertion check for valid result
				if (pos_wspace != string::npos)
				{
					// get position of the first real property value char
					// pseudo selectors get this far, but have no actual value
					size_t pos_value =  sass.find_first_not_of(" \t\n\v\f\r", pos_wspace);
					// assertion check for valid result
					if (pos_value != string::npos)
					{
						// create new string by interchanging the colon sign for property and value
						sass = indent + sass.substr(pos_left + 1, pos_wspace - pos_left - 1) + ":" + sass.substr(pos_wspace);
					}
				}

				// try to find a colon in the current line, but only ...
				size_t pos_colon = sass.find_first_not_of(":", pos_left);
				// assertion for valid result
				if (pos_colon != string::npos)
				{
					// ... after the first word (skip begining colons)
					pos_colon = sass.find_first_of(":", pos_colon);
					// it is a selector if there was no colon found
					converter.selector = pos_colon == string::npos;
				}

			}

			// replace some specific sass shorthand directives
			else if (sass.substr(pos_left, 1) == "=") { sass = indent + "@mixin " + sass.substr(pos_left + 1); }
			else if (sass.substr(pos_left, 1) == "+") { sass = indent + "@include " + sass.substr(pos_left + 1); }

			// add quotes for import if needed
			else if (sass.substr(pos_left, 7) == "@import")
			{
				// get positions for the actual import url
				size_t pos_import = sass.find_first_of(" \t\n\v\f\r", pos_left + 7);
				size_t pos_quote = sass.find_first_not_of(" \t\n\v\f\r", pos_import);
				// check if the url is quoted
				if (sass.substr(pos_quote, 1) != "\"")
				{
					// get position of the last char on the line
					size_t pos_end = sass.find_last_not_of(" \t\n\v\f\r");
					// assertion check for valid result
					if (pos_end != string::npos)
					{
						// add quotes around the full line after the import statement
						sass = sass.substr(0, pos_quote) + "\"" + sass.substr(pos_quote, pos_end - pos_quote + 1) + "\"";
					}
				}

			}
			else if (
				sass.substr(pos_left, 7) != "@return" &&
				sass.substr(pos_left, 7) != "@extend" &&
				sass.substr(pos_left, 8) != "@content"
			) {

				// try to find a colon in the current line, but only ...
				size_t pos_colon = sass.find_first_not_of(":", pos_left);
				// assertion for valid result
				if (pos_colon != string::npos)
				{
					// ... after the first word (skip begining colons)
					pos_colon = sass.find_first_of(":", pos_colon);
					// it is a selector if there was no colon found
					converter.selector = pos_colon == string::npos;
				}

			}

			// check if current line starts a comment
			string open = sass.substr(pos_left, 2);

			// current line has more indentation
			if (indent.length() >= INDENT(converter).length())
			{
				// not in comment mode
				if (IS_PARSING(converter))
				{
					// probably a property
					converter.property = true;
				}
			}
			// current line has more indentation
			if (indent.length() > INDENT(converter).length())
			{
				// not in comment mode
				if (IS_PARSING(converter))
				{
					// print block opener
					scss += opener(converter);
					// push new stack context
					converter.indents.push("");
					// store block indentation
					INDENT(converter) = indent;
				}
				// is and will be a src comment
				else if (!IS_CSS_COMMENT(converter))
				{
					// scss does not allow multiline src comments
					// therefore add forward slashes to all lines
					sass[INDENT(converter).length()+0] = '/';
					// there is an edge case here if indentation
					// is minimal (will overwrite the fist char)
					sass[INDENT(converter).length()+1] = '/';
					// could code around that, but I dont' think
					// this will ever be the cause for any trouble
				}
			}

			// line is opening a new comment
			if (open == "/*" || open == "//")
			{
				// reset the property state
				converter.property = false;
				// close previous comment
				if (IS_CSS_COMMENT(converter) && open != "")
				{
					if (!STRIP_COMMENT(converter) && !CONVERT_COMMENT(converter)) scss += " */";
				}
				// force single line comments
				// into a correct css comment
				if (CONVERT_COMMENT(converter))
				{
					if (IS_PARSING(converter))
					{ sass[pos_left + 1] = '*'; }
				}
				// set comment flag
				converter.comment = open;

			}

			// flush data only under certain conditions
			if (!(
				// strip css and src comments if option is set
				(IS_COMMENT(converter) && STRIP_COMMENT(converter)) ||
				// strip src comment even if strip option is not set
				// but only if the keep src comment option is not set
				(IS_SRC_COMMENT(converter) && ! KEEP_COMMENT(converter))
			))
			{
				// flush data and buffer whitespace
				scss += flush(sass, converter);
			}

			// get postion of last meaningfull char
			size_t pos_right = sass.find_last_not_of(" \t\n\v\f\r");

			// check for invalid result
			if (pos_right != string::npos)
			{

				// get the last meaningfull char
				string close = sass.substr(pos_right, 1);

				// check if next line should be concatenated (list mode)
				converter.comma = IS_PARSING(converter) && close == ",";

				// check if we have more than
				// one meaningfull char
				if (pos_right > 0)
				{

					// get the last two chars from string
					string close = sass.substr(pos_right - 1, 2);
					// update parser status for expicitly closed comment
					if (close == "*/") converter.comment = "";

				}

			}
			// EO have meaningfull chars from end

		}
		// EO have meaningfull chars from start

		// return scss
		return scss;

	}
	// EO process

	// the main converter function for c++
	char* sass2scss (const string sass, const int options)
	{

		// local variables
		string line;
		string scss = "";
		const char delim = '\n';
		stringstream stream(sass);

		// create converter variable
		converter converter;
		// initialise all options
		converter.comma = false;
		converter.property = false;
		converter.end_of_file = false;
		converter.comment = "";
		converter.whitespace = "";
		converter.indents.push("");
		converter.options = options;

		// read line by line and process them
		while(std::getline(stream, line, delim))
		{ scss += process(line, converter); }

		// create mutable string
		string closer = "";
		// set the end of file flag
		converter.end_of_file = true;
		// process to close all open blocks
		scss += process(closer, converter);

		// allocate new memory on the heap
		// caller has to free it after use
		char * cstr = new char [scss.length()+1];
		// create a copy of the string
		strcpy (cstr, scss.c_str());
		// return pointer
		return &cstr[0];

	}
	// EO sass2scss

}
// EO namespace

// implement for c
extern "C"
{

	char* sass2scss (const char* sass, const int options)
	{
		return Sass::sass2scss(sass, options);
	}

}
<|endoftext|>


<commit_before>// include library
#include <stack>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>

///*
//
// src comments: comments in sass syntax (staring with //)
// css comments: multiline comments in css syntax (starting with /*)
//
// KEEP_COMMENT: keep src comments in the resulting css code
// STRIP_COMMENT: strip out all comments (either src or css)
// CONVERT_COMMENT: convert all src comments to css comments
//
//*/

// our own header
#include "sass2scss.h"

// using std::string
using namespace std;

// add namespace for c++
namespace Sass
{

	// return the actual prettify value from options
	#define PRETTIFY(converter) (converter.options - (converter.options & 248))
	// query the options integer to check if the option is enables
	#define KEEP_COMMENT(converter) ((converter.options & SASS2SCSS_KEEP_COMMENT) == SASS2SCSS_KEEP_COMMENT)
	#define STRIP_COMMENT(converter) ((converter.options & SASS2SCSS_STRIP_COMMENT) == SASS2SCSS_STRIP_COMMENT)
	#define CONVERT_COMMENT(converter) ((converter.options & SASS2SCSS_CONVERT_COMMENT) == SASS2SCSS_CONVERT_COMMENT)

	// some makros to access the indentation stack
	#define INDENT(converter) (converter.indents.top())

	// some makros to query comment parser status
	#define IS_PARSING(converter) (converter.comment == "")
	#define IS_COMMENT(converter) (converter.comment != "")
	#define IS_SRC_COMMENT(converter) (converter.comment == "//" && ! CONVERT_COMMENT(converter))
	#define IS_CSS_COMMENT(converter) (converter.comment == "/*" || (converter.comment == "//" && CONVERT_COMMENT(converter)))

	// pretty printer helper function
	static string closer (const converter& converter)
	{
		return PRETTIFY(converter) == 0 ? " }" :
		     PRETTIFY(converter) <= 1 ? " }" :
		       "\n" + INDENT(converter) + "}";
	}

	// pretty printer helper function
	static string opener (const converter& converter)
	{
		return PRETTIFY(converter) == 0 ? " { " :
		     PRETTIFY(converter) <= 2 ? " {" :
		       "\n" + INDENT(converter) + "{";
	}

	// flush whitespace and
	// print additional text
	// but only print additional
	// chars and buffer whitespace
	// ***************************************************************************************
	string flush (string& sass, converter& converter)
	{

		// return flushed
		string scss = "";

		// print whitespace buffer
		scss += PRETTIFY(converter) > 0 ?
		        converter.whitespace : "";
		// reset whitespace buffer
		converter.whitespace = "";

		// remove possible newlines from string
		size_t pos_right = sass.find_last_not_of("\n\r");
		if (pos_right == string::npos) return scss;

		// get the linefeeds from the string
		string lfs = sass.substr(pos_right + 1);
		sass = sass.substr(0, pos_right + 1);

		// add newline as getline discharged it
		converter.whitespace += lfs + "\n";

		// maybe remove any leading whitespace
		if (PRETTIFY(converter) == 0)
		{
			// remove leading whitespace and update string
			size_t pos_left = sass.find_first_not_of(" \t\n\v\f\r");
			if (pos_left != string::npos) sass = sass.substr(pos_left);
		}

		// add flushed data
		scss += sass;

		// return string
		return scss;

	}
	// EO flush

	// process a line of the sass text
	string process (string& sass, converter& converter)
	{

		// resulting string
		string scss = "";

		// get postion of first meaningfull character in string
		size_t pos_left = sass.find_first_not_of(" \t\n\v\f\r");

		// special case for final run
		if (converter.end_of_file) pos_left = 0;

		// maybe has only whitespace
		if (pos_left == string::npos)
		{
			// just add complete whitespace
			converter.whitespace += sass + "\n";
		}
		// have meaningfull first char
		else
		{

			// extract and store indentation string
			string indent = sass.substr(0, pos_left);

			// line has less or same indentation
			// finalize previous open parser context
			if (indent.length() <= INDENT(converter).length())
			{

				// close multilinie comment
				if (IS_CSS_COMMENT(converter))
				{
					// check if comments will be stripped anyway
					if (!STRIP_COMMENT(converter)) scss += " */";
				}
				// close src comment comment
				else if (IS_SRC_COMMENT(converter))
				{
					// add a newline to avoid closer on same line
					// this would but the bracket in the comment node
					if (KEEP_COMMENT(converter)) scss += "\n";
				}
				// close css properties
				else if (converter.property)
				{
					// add semicolon unless in concat mode
					if (!converter.comma) scss += ";";
				}

				// reset comment state
				converter.comment = "";

			}

			// make sure we close every "higher" block
			while (indent.length() < INDENT(converter).length())
			{
				// reset string
				INDENT(converter) == "";
				// pop stacked context
				converter.indents.pop();
				// print close bracket
				if (IS_PARSING(converter))
				{ scss += closer(converter); }
				else { scss += " */"; }
				// reset comment state
				converter.comment = "";
			}

			// check if we have sass property syntax
			if (sass.substr(pos_left, 1) == ":")
			{
				// get postion of first meaningfull char
				size_t pos_value = sass.find_first_of(" \t\n\v\f\r", pos_left);
				// create new string by interchanging the colon sign for property and value
				sass = indent + sass.substr(pos_left + 1, pos_value - pos_left - 1) + ":" + sass.substr(pos_value);
			}

			// replace some specific sass shorthand directives
			else if (sass.substr(pos_left, 1) == "=") { sass = indent + "@mixin " + sass.substr(pos_left + 1); }
			else if (sass.substr(pos_left, 1) == "+") { sass = indent + "@include " + sass.substr(pos_left + 1); }

			// add quotes for import if needed
			else if (sass.substr(pos_left, 7) == "@import")
			{
				// get positions for the actual import url
				size_t pos_import = sass.find_first_of(" \t\n\v\f\r", pos_left + 7);
				size_t pos_quote = sass.find_first_not_of(" \t\n\v\f\r", pos_import);
				// check if the url is quoted
				if (sass.substr(pos_quote, 1) != "\"")
				{
					// get position of the last char on the line
					size_t pos_end = sass.find_last_not_of(" \t\n\v\f\r");
					// add quotes around the full line after the import statement
					sass = sass.substr(0, pos_quote) + "\"" + sass.substr(pos_quote, pos_end - pos_quote + 1) + "\"";
				}
			}

			// check if current line starts a comment
			string open = sass.substr(pos_left, 2);

			// current line has more indentation
			if (indent.length() >= INDENT(converter).length())
			{
				// not in comment mode
				if (IS_PARSING(converter))
				{
					// probably a property
					converter.property = true;
				}
			}
			// current line has more indentation
			if (indent.length() > INDENT(converter).length())
			{
				// not in comment mode
				if (IS_PARSING(converter))
				{
					// print block opener
					scss += opener(converter);
					// push new stack context
					converter.indents.push("");
					// store block indentation
					INDENT(converter) = indent;
				}
				// is and will be a src comment
				else if (!IS_CSS_COMMENT(converter))
				{
					// scss does not allow multiline src comments
					// therefore add forward slashes to all lines
					sass[INDENT(converter).length()+0] = '/';
					// there is an edge case here if indentation
					// is minimal (will overwrite the fist char)
					sass[INDENT(converter).length()+1] = '/';
					// could code around that, but I dont' think
					// this will ever be the cause for any trouble
				}
			}

			// line is opening a new comment
			if (open == "/*" || open == "//")
			{
				// reset the property state
				converter.property = false;
				// close previous comment
				if (IS_CSS_COMMENT(converter) && open != "")
				{
					if (!STRIP_COMMENT(converter) && !CONVERT_COMMENT(converter)) scss += " */";
				}
				// force single line comments
				// into a correct css comment
				if (CONVERT_COMMENT(converter))
				{
					if (IS_PARSING(converter))
					{ sass[pos_left + 1] = '*'; }
				}
				// set comment flag
				converter.comment = open;

			}

			// flush data only under certain conditions
			if (!(
				// strip css and src comments if option is set
				(IS_COMMENT(converter) && STRIP_COMMENT(converter)) ||
				// strip src comment even if strip option is not set
				// but only if the keep src comment option is not set
				(IS_SRC_COMMENT(converter) && ! KEEP_COMMENT(converter))
			))
			{
				// flush data and buffer whitespace
				scss += flush(sass, converter);
			}

			// get postion of last meaningfull char
			size_t pos_right = sass.find_last_not_of(" \t\n\v\f\r");

			// check for invalid result
			if (pos_right != string::npos)
			{

				// get the last meaningfull char
				string close = sass.substr(pos_right, 1);

				// check if next line should be concatenated (list mode)
				converter.comma = IS_PARSING(converter) && close == ",";

				// check if we have more than
				// one meaningfull char
				if (pos_right > 0)
				{

					// get the last two chars from string
					string close = sass.substr(pos_right - 1, 2);
					// update parser status for expicitly closed comment
					if (close == "*/") converter.comment = "";

				}

			}
			// EO have meaningfull chars from end

		}
		// EO have meaningfull chars from start

		// return scss
		return scss;

	}
	// EO process

	// the main converter function for c++
	char* sass2scss (const string sass, const int options)
	{

		// local variables
		string line;
		string scss = "";
		const char delim = '\n';
		stringstream stream(sass);

		// create converter variable
		converter converter;
		// initialise all options
		converter.comma = false;
		converter.property = false;
		converter.end_of_file = false;
		converter.comment = "";
		converter.whitespace = "";
		converter.indents.push("");
		converter.options = options;

		// read line by line and process them
		while(std::getline(stream, line, delim))
		{ scss += process(line, converter); }

		// create mutable string
		string closer = "";
		// set the end of file flag
		converter.end_of_file = true;
		// process to close all open blocks
		scss += process(closer, converter);

		// allocate new memory on the heap
		// caller has to free it after use
		char * cstr = new char [scss.length()+1];
		// create a copy of the string
		strcpy (cstr, scss.c_str());
		// return pointer
		return &cstr[0];

	}
	// EO sass2scss

}
// EO namespace

// implement for c
extern "C"
{

	char* sass2scss (const char* sass, const int options)
	{
		return Sass::sass2scss(sass, options);
	}

}
<commit_msg>Removes unneeded (no-op) command<commit_after>// include library
#include <stack>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>

///*
//
// src comments: comments in sass syntax (staring with //)
// css comments: multiline comments in css syntax (starting with /*)
//
// KEEP_COMMENT: keep src comments in the resulting css code
// STRIP_COMMENT: strip out all comments (either src or css)
// CONVERT_COMMENT: convert all src comments to css comments
//
//*/

// our own header
#include "sass2scss.h"

// using std::string
using namespace std;

// add namespace for c++
namespace Sass
{

	// return the actual prettify value from options
	#define PRETTIFY(converter) (converter.options - (converter.options & 248))
	// query the options integer to check if the option is enables
	#define KEEP_COMMENT(converter) ((converter.options & SASS2SCSS_KEEP_COMMENT) == SASS2SCSS_KEEP_COMMENT)
	#define STRIP_COMMENT(converter) ((converter.options & SASS2SCSS_STRIP_COMMENT) == SASS2SCSS_STRIP_COMMENT)
	#define CONVERT_COMMENT(converter) ((converter.options & SASS2SCSS_CONVERT_COMMENT) == SASS2SCSS_CONVERT_COMMENT)

	// some makros to access the indentation stack
	#define INDENT(converter) (converter.indents.top())

	// some makros to query comment parser status
	#define IS_PARSING(converter) (converter.comment == "")
	#define IS_COMMENT(converter) (converter.comment != "")
	#define IS_SRC_COMMENT(converter) (converter.comment == "//" && ! CONVERT_COMMENT(converter))
	#define IS_CSS_COMMENT(converter) (converter.comment == "/*" || (converter.comment == "//" && CONVERT_COMMENT(converter)))

	// pretty printer helper function
	static string closer (const converter& converter)
	{
		return PRETTIFY(converter) == 0 ? " }" :
		     PRETTIFY(converter) <= 1 ? " }" :
		       "\n" + INDENT(converter) + "}";
	}

	// pretty printer helper function
	static string opener (const converter& converter)
	{
		return PRETTIFY(converter) == 0 ? " { " :
		     PRETTIFY(converter) <= 2 ? " {" :
		       "\n" + INDENT(converter) + "{";
	}

	// flush whitespace and print additional text, but
	// only print additional chars and buffer whitespace
	string flush (string& sass, converter& converter)
	{

		// return flushed
		string scss = "";

		// print whitespace buffer
		scss += PRETTIFY(converter) > 0 ?
		        converter.whitespace : "";
		// reset whitespace buffer
		converter.whitespace = "";

		// remove possible newlines from string
		size_t pos_right = sass.find_last_not_of("\n\r");
		if (pos_right == string::npos) return scss;

		// get the linefeeds from the string
		string lfs = sass.substr(pos_right + 1);
		sass = sass.substr(0, pos_right + 1);

		// add newline as getline discharged it
		converter.whitespace += lfs + "\n";

		// maybe remove any leading whitespace
		if (PRETTIFY(converter) == 0)
		{
			// remove leading whitespace and update string
			size_t pos_left = sass.find_first_not_of(" \t\n\v\f\r");
			if (pos_left != string::npos) sass = sass.substr(pos_left);
		}

		// add flushed data
		scss += sass;

		// return string
		return scss;

	}
	// EO flush

	// process a line of the sass text
	string process (string& sass, converter& converter)
	{

		// resulting string
		string scss = "";

		// get postion of first meaningfull character in string
		size_t pos_left = sass.find_first_not_of(" \t\n\v\f\r");

		// special case for final run
		if (converter.end_of_file) pos_left = 0;

		// maybe has only whitespace
		if (pos_left == string::npos)
		{
			// just add complete whitespace
			converter.whitespace += sass + "\n";
		}
		// have meaningfull first char
		else
		{

			// extract and store indentation string
			string indent = sass.substr(0, pos_left);

			// line has less or same indentation
			// finalize previous open parser context
			if (indent.length() <= INDENT(converter).length())
			{

				// close multilinie comment
				if (IS_CSS_COMMENT(converter))
				{
					// check if comments will be stripped anyway
					if (!STRIP_COMMENT(converter)) scss += " */";
				}
				// close src comment comment
				else if (IS_SRC_COMMENT(converter))
				{
					// add a newline to avoid closer on same line
					// this would but the bracket in the comment node
					if (KEEP_COMMENT(converter)) scss += "\n";
				}
				// close css properties
				else if (converter.property)
				{
					// add semicolon unless in concat mode
					if (!converter.comma) scss += ";";
				}

				// reset comment state
				converter.comment = "";

			}

			// make sure we close every "higher" block
			while (indent.length() < INDENT(converter).length())
			{
				// pop stacked context
				converter.indents.pop();
				// print close bracket
				if (IS_PARSING(converter))
				{ scss += closer(converter); }
				else { scss += " */"; }
				// reset comment state
				converter.comment = "";
			}

			// check if we have sass property syntax
			if (sass.substr(pos_left, 1) == ":")
			{
				// get postion of first meaningfull char
				size_t pos_value = sass.find_first_of(" \t\n\v\f\r", pos_left);
				// create new string by interchanging the colon sign for property and value
				sass = indent + sass.substr(pos_left + 1, pos_value - pos_left - 1) + ":" + sass.substr(pos_value);
			}

			// replace some specific sass shorthand directives
			else if (sass.substr(pos_left, 1) == "=") { sass = indent + "@mixin " + sass.substr(pos_left + 1); }
			else if (sass.substr(pos_left, 1) == "+") { sass = indent + "@include " + sass.substr(pos_left + 1); }

			// add quotes for import if needed
			else if (sass.substr(pos_left, 7) == "@import")
			{
				// get positions for the actual import url
				size_t pos_import = sass.find_first_of(" \t\n\v\f\r", pos_left + 7);
				size_t pos_quote = sass.find_first_not_of(" \t\n\v\f\r", pos_import);
				// check if the url is quoted
				if (sass.substr(pos_quote, 1) != "\"")
				{
					// get position of the last char on the line
					size_t pos_end = sass.find_last_not_of(" \t\n\v\f\r");
					// add quotes around the full line after the import statement
					sass = sass.substr(0, pos_quote) + "\"" + sass.substr(pos_quote, pos_end - pos_quote + 1) + "\"";
				}
			}

			// check if current line starts a comment
			string open = sass.substr(pos_left, 2);

			// current line has more indentation
			if (indent.length() >= INDENT(converter).length())
			{
				// not in comment mode
				if (IS_PARSING(converter))
				{
					// probably a property
					converter.property = true;
				}
			}
			// current line has more indentation
			if (indent.length() > INDENT(converter).length())
			{
				// not in comment mode
				if (IS_PARSING(converter))
				{
					// print block opener
					scss += opener(converter);
					// push new stack context
					converter.indents.push("");
					// store block indentation
					INDENT(converter) = indent;
				}
				// is and will be a src comment
				else if (!IS_CSS_COMMENT(converter))
				{
					// scss does not allow multiline src comments
					// therefore add forward slashes to all lines
					sass[INDENT(converter).length()+0] = '/';
					// there is an edge case here if indentation
					// is minimal (will overwrite the fist char)
					sass[INDENT(converter).length()+1] = '/';
					// could code around that, but I dont' think
					// this will ever be the cause for any trouble
				}
			}

			// line is opening a new comment
			if (open == "/*" || open == "//")
			{
				// reset the property state
				converter.property = false;
				// close previous comment
				if (IS_CSS_COMMENT(converter) && open != "")
				{
					if (!STRIP_COMMENT(converter) && !CONVERT_COMMENT(converter)) scss += " */";
				}
				// force single line comments
				// into a correct css comment
				if (CONVERT_COMMENT(converter))
				{
					if (IS_PARSING(converter))
					{ sass[pos_left + 1] = '*'; }
				}
				// set comment flag
				converter.comment = open;

			}

			// flush data only under certain conditions
			if (!(
				// strip css and src comments if option is set
				(IS_COMMENT(converter) && STRIP_COMMENT(converter)) ||
				// strip src comment even if strip option is not set
				// but only if the keep src comment option is not set
				(IS_SRC_COMMENT(converter) && ! KEEP_COMMENT(converter))
			))
			{
				// flush data and buffer whitespace
				scss += flush(sass, converter);
			}

			// get postion of last meaningfull char
			size_t pos_right = sass.find_last_not_of(" \t\n\v\f\r");

			// check for invalid result
			if (pos_right != string::npos)
			{

				// get the last meaningfull char
				string close = sass.substr(pos_right, 1);

				// check if next line should be concatenated (list mode)
				converter.comma = IS_PARSING(converter) && close == ",";

				// check if we have more than
				// one meaningfull char
				if (pos_right > 0)
				{

					// get the last two chars from string
					string close = sass.substr(pos_right - 1, 2);
					// update parser status for expicitly closed comment
					if (close == "*/") converter.comment = "";

				}

			}
			// EO have meaningfull chars from end

		}
		// EO have meaningfull chars from start

		// return scss
		return scss;

	}
	// EO process

	// the main converter function for c++
	char* sass2scss (const string sass, const int options)
	{

		// local variables
		string line;
		string scss = "";
		const char delim = '\n';
		stringstream stream(sass);

		// create converter variable
		converter converter;
		// initialise all options
		converter.comma = false;
		converter.property = false;
		converter.end_of_file = false;
		converter.comment = "";
		converter.whitespace = "";
		converter.indents.push("");
		converter.options = options;

		// read line by line and process them
		while(std::getline(stream, line, delim))
		{ scss += process(line, converter); }

		// create mutable string
		string closer = "";
		// set the end of file flag
		converter.end_of_file = true;
		// process to close all open blocks
		scss += process(closer, converter);

		// allocate new memory on the heap
		// caller has to free it after use
		char * cstr = new char [scss.length()+1];
		// create a copy of the string
		strcpy (cstr, scss.c_str());
		// return pointer
		return &cstr[0];

	}
	// EO sass2scss

}
// EO namespace

// implement for c
extern "C"
{

	char* sass2scss (const char* sass, const int options)
	{
		return Sass::sass2scss(sass, options);
	}

}
<|endoftext|>


<commit_before>/*
 * Jamoma DSP Audio Buffer Object
 * Copyright © 2003, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTBuffer.h"

#define thisTTClass			TTBuffer
#define thisTTClassName		"buffer"
#define thisTTClassTags		"audio, buffer"

TTObjectPtr TTBuffer::instantiate(TTSymbolPtr name, TTValue& arguments)
{
	return new TTBuffer(arguments);
}

extern "C" void TTBuffer::registerClass()
{
	TTClassRegister(TT("buffer"), thisTTClassTags, TTBuffer::instantiate);
}

TTBuffer::TTBuffer(TTValue& arguments) :
	TTMatrix(arguments),
	mSampleRate(44100.0)
{
	this->setType(TT("float64"));
	this->setElementCount(1);

	addAttributeWithGetterAndSetter(NumChannels,		kTypeUInt16);
	addAttributeWithGetterAndSetter(Length,				kTypeFloat64);
	addAttributeWithGetterAndSetter(LengthInSamples,	kTypeUInt64);
	addAttribute(SampleRate,							kTypeFloat64);

	addMessage(normalize);
	addMessageWithArguments(fill);

	addMessageWithArguments(getValueAtIndex);
	registerMessage(TT("peek"), (TTMethod)&TTBuffer::getValueAtIndex);

	addMessageWithArguments(setValueAtIndex);
	registerMessage(TT("poke"), (TTMethod)&TTBuffer::setValueAtIndex);

	// TODO: more messages to implement
	//	"readFile"   (requires libsndfile straightening-out)
	//	"writeFile"  (requires libsndfile straightening-out)
	//	a way to query attributes: for example what is the sr and bpm of an AIFF file?
}

TTBuffer::~TTBuffer()
{
	;
}

TTErr TTBuffer::setNumChannels(const TTValue& newNumChannels)
{
	TTValue v(mDimensions[0], TTUInt32(newNumChannels));

	return setDimensions(v);
}

TTErr TTBuffer::getNumChannels(TTValue& returnedChannelCount)
{
	returnedChannelCount = mDimensions[0];
	return kTTErrNone;
}

TTErr TTBuffer::setLength(const TTValue& newLength)
{
	TTValue v(TTFloat64(newLength) * mSampleRate * 0.001, mDimensions[1]);

	return setDimensions(v);
}

TTErr TTBuffer::getLength(TTValue& returnedLength)
{
	returnedLength = (mDimensions[1] / mSampleRate) * 1000.0;
	return kTTErrNone;
}

TTErr TTBuffer::setLengthInSamples(const TTValue& newLengthInSamples)
{
	TTValue v(TTUInt32(newLengthInSamples), mDimensions[1]);

	return setDimensions(v);
}

TTErr TTBuffer::getLengthInSamples(TTValue& returnedLengthInSamples)
{
	returnedLengthInSamples = mDimensions[1];
	return kTTErrNone;
}

TTErr TTBuffer::getValueAtIndex(const TTValue& index, TTValue &output)
{
	TTUInt32		sampleIndex;
	TTUInt16		sampleChannel = 0;
	TTSampleValue	sampleValue;
	TTUInt8			i = 0;
	TTErr			err;

	index.get(i++, sampleIndex);
	if (index.getSize() > 2)		// TODO: sure would be nice to change the name of this method to "size" or something...
		index.get(i++, sampleChannel);

	err = peek(sampleIndex, sampleChannel, sampleValue);
	if (!err)
		output.set(i++, sampleValue);
	return err;
}

TTErr TTBuffer::peek(const TTUInt64 index, const TTUInt16 channel, TTSampleValue& value)
{
	// TODO: perhaps we should range check the input here first...
	get2d(index, channel, value);
	return kTTErrNone;
}

/**	Set the sample value for a given index.
	The first number passed in the index parameter will be interpreted as the sample index.
	If there are three numbers passed, then the second number, if passed, will designate the channel index (defaults to zero).
	The final value will be used as the sample value that will be copied to the designated index.
*/
TTErr TTBuffer::setValueAtIndex(const TTValue& index, TTValue& unusedOutput)
{
	TTUInt32		sampleIndex;
	TTUInt16		sampleChannel = 0;
	TTSampleValue	sampleValue;
	TTUInt8			i = 0;

	index.get(i++, sampleIndex);
	if (index.getSize() > 2)
		index.get(i++, sampleChannel);
	index.get(i++, sampleValue);

	return poke(sampleIndex, sampleChannel, sampleValue);
}

TTErr TTBuffer::poke(const TTUInt64 index, const TTUInt16 channel, const TTSampleValue value)
{
	// TODO: perhaps we should range check the input here first...
	set2d(index, channel, value);
	return kTTErrNone;
}

#define mLengthInSamples mDimensions[0]
#define mNumChannels mDimensions[1]

TTErr TTBuffer::fill(const TTValue& value, TTValue& unusedOutput)
{
	TTSymbol*	fillAlgorithm = value;

	if (fillAlgorithm == kTTSym_sine) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i+1, channel+1, sin(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0))));
		}
	}
	else if (fillAlgorithm == kTTSym_sineMod) {							// (modulator version: ranges from 0.0 to 1.0, rather than -1.0 to 1.0)
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i+1, channel+1, 0.5 + (0.5 * sin(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0)))));
		}
	}
	else if (fillAlgorithm == kTTSym_cosine) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i+1, channel+1, cos(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0))));
		}
	}
	else if (fillAlgorithm == kTTSym_cosineMod) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i+1, channel+1, 0.5 + (0.5 * cos(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0)))));
		}
	}
	else if (fillAlgorithm == kTTSym_ramp) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mDimensions[0]; i++)
				set2d(i+1, channel+1, -1.0 + (2.0 * (float(i) / mDimensions[0])));
		}
	}
	else if (fillAlgorithm == kTTSym_rampMod) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mDimensions[0]; i++)
				set2d(i+1, channel+1, float(i) / mDimensions[0]);
		}
	}

	return kTTErrNone;
}

TTErr TTBuffer::normalize(const TTValue& aValue)
{
	TTFloat64			normalizeTo = 1.0;
	TTRowID				m = mDimensions[0]; // mFrameLength
	TTColumnID			n = mDimensions[1]; // mNumChannels
	TTSampleValuePtr	samples = (TTSampleValuePtr)getLockedPointer();
	TTFloat64			peakValue = 0.0;
	TTFloat64			scalar;

	if (aValue.getSize() && TTFloat64(aValue) > 0.0)
		normalizeTo = aValue;

	for (int k=0; k<m*n; k++) {
		TTFloat64 magnitude = abs(samples[k]);

		if (magnitude > peakValue)
			peakValue = magnitude;
	}

	scalar = normalizeTo / peakValue;

	for (int k=0; k<m*n; k++)
		samples[k] *= scalar;

	releaseLockedPointer();
	return kTTErrNone;
}
<commit_msg>TTBuffer: re-added the sawtooth and triangle fill methods.  These went missing at some point which broke the jcom.waveform≈ object that expected to have these waveforms.<commit_after>/*
 * Jamoma DSP Audio Buffer Object
 * Copyright © 2003, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTBuffer.h"

#define thisTTClass			TTBuffer
#define thisTTClassName		"buffer"
#define thisTTClassTags		"audio, buffer"

TTObjectPtr TTBuffer::instantiate(TTSymbolPtr name, TTValue& arguments)
{
	return new TTBuffer(arguments);
}

extern "C" void TTBuffer::registerClass()
{
	TTClassRegister(TT("buffer"), thisTTClassTags, TTBuffer::instantiate);
}

TTBuffer::TTBuffer(TTValue& arguments) :
	TTMatrix(arguments),
	mSampleRate(44100.0)
{
	this->setType(TT("float64"));
	this->setElementCount(1);

	addAttributeWithGetterAndSetter(NumChannels,		kTypeUInt16);
	addAttributeWithGetterAndSetter(Length,				kTypeFloat64);
	addAttributeWithGetterAndSetter(LengthInSamples,	kTypeUInt64);
	addAttribute(SampleRate,							kTypeFloat64);

	addMessage(normalize);
	addMessageWithArguments(fill);

	addMessageWithArguments(getValueAtIndex);
	registerMessage(TT("peek"), (TTMethod)&TTBuffer::getValueAtIndex);

	addMessageWithArguments(setValueAtIndex);
	registerMessage(TT("poke"), (TTMethod)&TTBuffer::setValueAtIndex);

	// TODO: more messages to implement
	//	"readFile"   (requires libsndfile straightening-out)
	//	"writeFile"  (requires libsndfile straightening-out)
	//	a way to query attributes: for example what is the sr and bpm of an AIFF file?
}

TTBuffer::~TTBuffer()
{
	;
}

TTErr TTBuffer::setNumChannels(const TTValue& newNumChannels)
{
	TTValue v(mDimensions[0], TTUInt32(newNumChannels));

	return setDimensions(v);
}

TTErr TTBuffer::getNumChannels(TTValue& returnedChannelCount)
{
	returnedChannelCount = mDimensions[0];
	return kTTErrNone;
}

TTErr TTBuffer::setLength(const TTValue& newLength)
{
	TTValue v(TTFloat64(newLength) * mSampleRate * 0.001, mDimensions[1]);

	return setDimensions(v);
}

TTErr TTBuffer::getLength(TTValue& returnedLength)
{
	returnedLength = (mDimensions[1] / mSampleRate) * 1000.0;
	return kTTErrNone;
}

TTErr TTBuffer::setLengthInSamples(const TTValue& newLengthInSamples)
{
	TTValue v(TTUInt32(newLengthInSamples), mDimensions[1]);

	return setDimensions(v);
}

TTErr TTBuffer::getLengthInSamples(TTValue& returnedLengthInSamples)
{
	returnedLengthInSamples = mDimensions[1];
	return kTTErrNone;
}

TTErr TTBuffer::getValueAtIndex(const TTValue& index, TTValue &output)
{
	TTUInt32		sampleIndex;
	TTUInt16		sampleChannel = 0;
	TTSampleValue	sampleValue;
	TTUInt8			i = 0;
	TTErr			err;

	index.get(i++, sampleIndex);
	if (index.getSize() > 2)		// TODO: sure would be nice to change the name of this method to "size" or something...
		index.get(i++, sampleChannel);

	err = peek(sampleIndex, sampleChannel, sampleValue);
	if (!err)
		output.set(i++, sampleValue);
	return err;
}

TTErr TTBuffer::peek(const TTUInt64 index, const TTUInt16 channel, TTSampleValue& value)
{
	// TODO: perhaps we should range check the input here first...
	get2d(index, channel, value);
	return kTTErrNone;
}

/**	Set the sample value for a given index.
	The first number passed in the index parameter will be interpreted as the sample index.
	If there are three numbers passed, then the second number, if passed, will designate the channel index (defaults to zero).
	The final value will be used as the sample value that will be copied to the designated index.
*/
TTErr TTBuffer::setValueAtIndex(const TTValue& index, TTValue& unusedOutput)
{
	TTUInt32		sampleIndex;
	TTUInt16		sampleChannel = 0;
	TTSampleValue	sampleValue;
	TTUInt8			i = 0;

	index.get(i++, sampleIndex);
	if (index.getSize() > 2)
		index.get(i++, sampleChannel);
	index.get(i++, sampleValue);

	return poke(sampleIndex, sampleChannel, sampleValue);
}

TTErr TTBuffer::poke(const TTUInt64 index, const TTUInt16 channel, const TTSampleValue value)
{
	// TODO: perhaps we should range check the input here first...
	set2d(index, channel, value);
	return kTTErrNone;
}

#define mLengthInSamples mDimensions[0]
#define mNumChannels mDimensions[1]

TTErr TTBuffer::fill(const TTValue& value, TTValue& unusedOutput)
{
	TTSymbol*	fillAlgorithm = value;

	if (fillAlgorithm == kTTSym_sine) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i+1, channel+1, sin(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0))));
		}
	}
	else if (fillAlgorithm == kTTSym_sineMod) {							// (modulator version: ranges from 0.0 to 1.0, rather than -1.0 to 1.0)
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i+1, channel+1, 0.5 + (0.5 * sin(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0)))));
		}
	}
	else if (fillAlgorithm == kTTSym_cosine) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i+1, channel+1, cos(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0))));
		}
	}
	else if (fillAlgorithm == kTTSym_cosineMod) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mLengthInSamples; i++)
				set2d(i+1, channel+1, 0.5 + (0.5 * cos(kTTTwoPi * (i / (TTFloat64(mDimensions[0]) - 1.0)))));
		}
	}
	else if (fillAlgorithm == kTTSym_ramp) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mDimensions[0]; i++)
				set2d(i+1, channel+1, -1.0 + (2.0 * (float(i) / mDimensions[0])));
		}
	}
	else if (fillAlgorithm == kTTSym_rampMod) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mDimensions[0]; i++)
				set2d(i+1, channel+1, float(i) / mDimensions[0]);
		}
	}
	else if (fillAlgorithm == kTTSym_sawtooth) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mDimensions[0]; i++)
				set2d(mDimensions[0]-i, channel+1, -1.0 + (2.0 * (float(i) / mDimensions[0])));
		}
	}
	else if (fillAlgorithm == kTTSym_sawtoothMod) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt64 i=0; i<mDimensions[0]; i++)
				set2d(mDimensions[0]-i, channel+1, float(i) / mDimensions[0]);
		}
	}
	else if (fillAlgorithm == kTTSym_triangle) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt32 i=0; i < mDimensions[0]/2; i++) {
				set2d(i+1, channel+1, -1.0 + (4.0 * (float(i) / mDimensions[0])));
				set2d(mDimensions[0]-i, channel+1, -1.0 + (4.0 * (float(i) / mDimensions[0])));
			}
		}
	}
	else if (fillAlgorithm == kTTSym_triangleMod) {
		for (TTUInt16 channel=0; channel<mNumChannels; channel++) {
			for (TTUInt32 i=0; i < mDimensions[0]/2; i++) {
				set2d(i+1, channel+1, -1.0 + (4.0 * (float(i) / mDimensions[0])));
				set2d(mDimensions[0]-i, channel+1, -1.0 + (4.0 * (float(i) / mDimensions[0])));
			}
		}
	}

	return kTTErrNone;
}

TTErr TTBuffer::normalize(const TTValue& aValue)
{
	TTFloat64			normalizeTo = 1.0;
	TTRowID				m = mDimensions[0]; // mFrameLength
	TTColumnID			n = mDimensions[1]; // mNumChannels
	TTSampleValuePtr	samples = (TTSampleValuePtr)getLockedPointer();
	TTFloat64			peakValue = 0.0;
	TTFloat64			scalar;

	if (aValue.getSize() && TTFloat64(aValue) > 0.0)
		normalizeTo = aValue;

	for (int k=0; k<m*n; k++) {
		TTFloat64 magnitude = abs(samples[k]);

		if (magnitude > peakValue)
			peakValue = magnitude;
	}

	scalar = normalizeTo / peakValue;

	for (int k=0; k<m*n; k++)
		samples[k] *= scalar;

	releaseLockedPointer();
	return kTTErrNone;
}
<|endoftext|>


<commit_before><commit_msg>do not proceed with removing zero-length slice<commit_after><|endoftext|>