<commit_before>
// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2003 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// 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; either
// version 2.1 of the License, or (at your option) any later version.
//
// 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.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

#include "config_dap.h"

#include <stdio.h>
#include <stdlib.h>

#include "AISDatabaseParser.h"
#include "debug.h"

static const not_used char *states[] = {
    "START",
    "FINISH",
    "AIS",
    "ENTRY",
    "PRIMARY",
    "ANCILLARY",
    "UNKNOWN",
    "ERROR"
};

/** These methods are declared static in the class header. This gives them C
    linkage which allows them to be used as callbacks by the SAX parser
    engine.
    @see aisSAXParser. */
//@{

/** Initialize the SAX parser state object. This object is passed to each
    callback as a void pointer.
    @param state The SAX parser state. */
void
AISDatabaseParser::aisStartDocument(AISParserState *state)
{
    state->state = PARSER_START;
    state->unknown_depth = 0;
    state->prev_state = PARSER_UNKNOWN;
    state->error_msg = "";

    DBG2(cerr << "Parser state: " << states[state->state] << endl);
}

/** Clean up after finishing a parse.
    @param state The SAX parser state. */
void
AISDatabaseParser::aisEndDocument(AISParserState *state)
{
    DBG2(cerr << "Ending state == " << states[state->state] << endl);

    if (state->unknown_depth != 0) {
	state->state = PARSER_ERROR;
	state->error_msg = "The document contained unbalanced tags.";

        DBG(cerr << "unknown_depth != 0 (" << state->unknown_depth << ")"
	    << endl);
    }
}

/** Process a start element tag. Because the AIS DTD uses attributes and
    because libxml2 does not validate those, we do attribute validation here.
    Values pulled from the attributes are recorded in state for
    later use in aisEndElement.
    @param state The SAX parser state. */
void
AISDatabaseParser::aisStartElement(AISParserState *state, const char *name,
				   const char **attrs)
{
    switch (state->state) {
      case PARSER_START:
	if (strcmp(name, "ais") != 0) {
            DBG(cerr << "Expecting ais.  Got " << name << endl);
	}
	state->state = AIS;
	break;

      case PARSER_FINISH:
	break;

      case AIS:
        if (strcmp(name, "entry") == 0) {
	    state->prev_state = state->state;
	    state->state = ENTRY;
        }
	else {
            state->prev_state = state->state;
            state->state = PARSER_UNKNOWN;
            state->unknown_depth++;
        }
        break;

      case ENTRY:
	if (strcmp(name, "primary") == 0) {
	    state->prev_state = state->state;
	    state->state = PRIMARY;
	    // only one attribute, must check for attribute errors.
	    if (attrs && strcmp(attrs[0], "url") == 0)
		state->primary = attrs[1];
	    else {
		state->state = PARSER_ERROR;
		state->error_msg = "Required attribute 'url' missing from element 'primary'.";
		break;
	    }
	}
	else if (strcmp(name, "ancillary") == 0) {
	    state->prev_state = state->state;
	    state->state = ANCILLARY;

	    string url = "";	// set defaults, MUST have url
	    string rule = "overwrite";
	    for (int i = 0; attrs && attrs[i] != 0; i = i + 2) {
		if (strcmp(attrs[i], "url") == 0)
		    url = attrs[i+1];
		else if (strcmp(attrs[i], "rule") == 0)
		    rule = attrs[i+1];
	    }

	    // If this parser validated the XML, these tests would be
	    // unnecessary.
	    if (url == "") {
		state->state = PARSER_ERROR;
		state->error_msg = "Required attribute 'url' missing from element 'ancillary'.";
		break;
	    }

	    if (rule != "overwrite" && rule != "replace" && rule != "fallback") {
		state->state = PARSER_ERROR;
		state->error_msg = string("Optional attribute 'rule' in element 'ancillary' has a bad value: ") + rule + "\nIt should be one of 'overwrite', 'replace' or 'fallback'.";
		break;
	    }

	    Resource r(url, rule);
	    state->rv.push_back(r);
	}
	else {
            state->prev_state = state->state;
            state->state = PARSER_UNKNOWN;
            state->unknown_depth++;
        }
        break;

      case PRIMARY:
	break;

      case ANCILLARY:
	break;

      case PARSER_UNKNOWN:
	state->unknown_depth++;
	break;

      case PARSER_ERROR:
	break;
    }

    DBG2(cerr << "Start element " << name << " (state "
	 << states[state->state] << ")" << endl);
}

/** Process an end element tag. This is where values are added to the
    AISResources object that's held by state.
    @param state The SAX parser state. */
void
AISDatabaseParser::aisEndElement(AISParserState *state, const char *name)
{
    DBG2(cerr << "End element " << name << " (state " << states[state->state]
	 << ")" << endl);

    switch (state->state) {
      case AIS:
	state->prev_state = state->state;
	state->state = PARSER_FINISH;
	break;

      case ENTRY:
	state->prev_state = state->state;
	state->state = AIS;
	// record 'primary' and 'rv'
	state->ais->add_resource(state->primary, state->rv);
	// empty rv for the next set of ancillary resources.
	state->rv.erase(state->rv.begin(), state->rv.end());
	break;

      case PRIMARY:
	state->prev_state = state->state;
	state->state = ENTRY;
	break;

      case ANCILLARY:
	state->prev_state = state->state;
	state->state = ENTRY;
	break;

      case PARSER_UNKNOWN:
	// Leave the state and prev_state alone.
	state->unknown_depth--;
	break;

      case PARSER_ERROR:
	break;

      default:
	break;
    }
}

/** Handle the standard XML entities.
    @param state The SAX parser state.
    @param name The XML entity. */
xmlEntityPtr
AISDatabaseParser::aisGetEntity(AISParserState *state, const xmlChar *name)
{
    return xmlGetPredefinedEntity(name);
}

/** Process an XML warning. This is treated as a fatal error since there's no
    easy way for libdap++ to signal warning to users.
    @param state The SAX parser state.
    @param msg A printf-style format string. */
void
AISDatabaseParser::aisWarning(AISParserState *state, const char *msg, ...)
{
    va_list args;

    state->state = PARSER_ERROR;

    va_start(args, msg);
    char str[1024];
    vsnprintf(str, 1024, msg, args);
    va_end(args);

    state->error_msg += string(str) + string("\n");
}

/** Process an XML error. This is treated as a fatal error since there's no
    easy way for libdap++ to signal warning to users.
    @param state The SAX parser state.
    @param msg A printf-style format string. */
void
AISDatabaseParser::aisError(AISParserState *state, const char *msg, ...)
{
    va_list args;

    state->state = PARSER_ERROR;

    va_start(args, msg);
    char str[1024];
    vsnprintf(str, 1024, msg, args);
    va_end(args);

    state->error_msg += string(str) + string("\n");
}

/** Process an XML fatal error.
    @param state The SAX parser state.
    @param msg A printf-style format string. */
void
AISDatabaseParser::aisFatalError(AISParserState *state, const char *msg, ...)
{
    va_list args;

    state->state = PARSER_ERROR;

    va_start(args, msg);
    char str[1024];
    vsnprintf(str, 1024, msg, args);
    va_end(args);

    state->error_msg += string(str) + string("\n");
}

//@}

/** This local variable holds pointers to the callback functions which
    comprise the SAX parser. */
static xmlSAXHandler aisSAXParser = {
    0, // internalSubset
    0, // isStandalone
    0, // hasInternalSubset
    0, // hasExternalSubset
    0, // resolveEntity
    (getEntitySAXFunc)AISDatabaseParser::aisGetEntity, // getEntity
    0, // entityDecl
    0, // notationDecl
    0, // attributeDecl
    0, // elementDecl
    0, // unparsedEntityDecl
    0, // setDocumentLocator
    (startDocumentSAXFunc)AISDatabaseParser::aisStartDocument, // startDocument
    (endDocumentSAXFunc)AISDatabaseParser::aisEndDocument,  // endDocument
    (startElementSAXFunc)AISDatabaseParser::aisStartElement,  // startElement
    (endElementSAXFunc)AISDatabaseParser::aisEndElement,  // endElement
    0, // reference
    0, // (charactersSAXFunc)gladeCharacters,  characters
    0, // ignorableWhitespace
    0, // processingInstruction
    0, // (commentSAXFunc)gladeComment,  comment
    (warningSAXFunc)AISDatabaseParser::aisWarning, // warning
    (errorSAXFunc)AISDatabaseParser::aisError, // error
    (fatalErrorSAXFunc)AISDatabaseParser::aisFatalError // fatalError
};

void
AISDatabaseParser::parse(const string &database, AISResources *ais)
    throw(AISDatabaseReadFailed)
{
    xmlParserCtxtPtr ctxt;
    AISParserState state;

    state.ais = ais;		// dump values here

    ctxt = xmlCreateFileParserCtxt(database.c_str());
    if (!ctxt)
	return;

    ctxt->sax = &aisSAXParser;
    ctxt->userData = &state;
    ctxt->validate = true;

    xmlParseDocument(ctxt);

    // use getLineNumber and getColumnNumber to make the error messages better.
    if (!ctxt->wellFormed)
	throw AISDatabaseReadFailed("The database is not a well formed XML document.\n" + state.error_msg);

    if (!ctxt->valid)
	throw AISDatabaseReadFailed("The database is not a valid document.\n" + state.error_msg);

    if (state.state == PARSER_ERROR)
	throw AISDatabaseReadFailed("Error parsing AIS resources.\n" + state.error_msg);

    ctxt->sax = NULL;
    xmlFreeParserCtxt(ctxt);
}

// $Log: AISDatabaseParser.cc,v $
// Revision 1.2  2003/02/21 00:14:24  jimg
// Repaired copyright.
//
// Revision 1.1  2003/02/20 22:16:04  jimg
// Added.
//
<commit_msg>Added line numbers to error messages. Improved message formatting a little.<commit_after>
// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2003 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// 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; either
// version 2.1 of the License, or (at your option) any later version.
//
// 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.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

#include "config_dap.h"

#include <stdio.h>
#include <stdlib.h>

#include "AISDatabaseParser.h"
#include "util.h"
#include "debug.h"

static const not_used char *states[] = {
    "START",
    "FINISH",
    "AIS",
    "ENTRY",
    "PRIMARY",
    "ANCILLARY",
    "UNKNOWN",
    "ERROR"
};

/** These methods are declared static in the class header. This gives them C
    linkage which allows them to be used as callbacks by the SAX parser
    engine.
    @see aisSAXParser. */
//@{

/** Initialize the SAX parser state object. This object is passed to each
    callback as a void pointer.
    @param state The SAX parser state. */
void
AISDatabaseParser::aisStartDocument(AISParserState *state)
{
    state->state = PARSER_START;
    state->unknown_depth = 0;
    state->prev_state = PARSER_UNKNOWN;
    state->error_msg = "";

    DBG2(cerr << "Parser state: " << states[state->state] << endl);
}

/** Clean up after finishing a parse.
    @param state The SAX parser state. */
void
AISDatabaseParser::aisEndDocument(AISParserState *state)
{
    DBG2(cerr << "Ending state == " << states[state->state] << endl);

    if (state->unknown_depth != 0) {
	AISDatabaseParser::aisFatalError(state, "The document contained unbalanced tags.");

        DBG(cerr << "unknown_depth != 0 (" << state->unknown_depth << ")"
	    << endl);
    }
}

/** Process a start element tag. Because the AIS DTD uses attributes and
    because libxml2 does not validate those, we do attribute validation here.
    Values pulled from the attributes are recorded in state for
    later use in aisEndElement.
    @param state The SAX parser state. */
void
AISDatabaseParser::aisStartElement(AISParserState *state, const char *name,
				   const char **attrs)
{
    switch (state->state) {
      case PARSER_START:
	if (strcmp(name, "ais") != 0) {
            DBG(cerr << "Expecting ais.  Got " << name << endl);
	}
	state->state = AIS;
	break;

      case PARSER_FINISH:
	break;

      case AIS:
        if (strcmp(name, "entry") == 0) {
	    state->prev_state = state->state;
	    state->state = ENTRY;
        }
	else {
            state->prev_state = state->state;
            state->state = PARSER_UNKNOWN;
            state->unknown_depth++;
        }
        break;

      case ENTRY:
	if (strcmp(name, "primary") == 0) {
	    state->prev_state = state->state;
	    state->state = PRIMARY;
	    // only one attribute, must check for attribute errors.
	    if (attrs && strcmp(attrs[0], "url") == 0)
		state->primary = attrs[1];
	    else {
		AISDatabaseParser::aisFatalError(state, "Required attribute 'url' missing from element 'primary'.");
		break;
	    }
	}
	else if (strcmp(name, "ancillary") == 0) {
	    state->prev_state = state->state;
	    state->state = ANCILLARY;

	    string url = "";	// set defaults, MUST have url
	    string rule = "overwrite";
	    for (int i = 0; attrs && attrs[i] != 0; i = i + 2) {
		if (strcmp(attrs[i], "url") == 0)
		    url = attrs[i+1];
		else if (strcmp(attrs[i], "rule") == 0)
		    rule = attrs[i+1];
	    }

	    // If this parser validated the XML, these tests would be
	    // unnecessary.
	    if (url == "") {
		AISDatabaseParser::aisFatalError(state, "Required attribute 'url' missing from element 'ancillary'.");
		break;
	    }

	    if (rule != "overwrite" && rule != "replace" && rule != "fallback") {
		string msg = string("Optional attribute 'rule' in element 'ancillary' has a bad value: ") + rule + "\nIt should be one of 'overwrite', 'replace' or 'fallback'.";
		AISDatabaseParser::aisFatalError(state, msg.c_str());
		break;
	    }

	    Resource r(url, rule);
	    state->rv.push_back(r);
	}
	else {
            state->prev_state = state->state;
            state->state = PARSER_UNKNOWN;
            state->unknown_depth++;
        }
        break;

      case PRIMARY:
	break;

      case ANCILLARY:
	break;

      case PARSER_UNKNOWN:
	state->unknown_depth++;
	break;

      case PARSER_ERROR:
	break;
    }

    DBG2(cerr << "Start element " << name << " (state "
	 << states[state->state] << ")" << endl);
}

/** Process an end element tag. This is where values are added to the
    AISResources object that's held by state.
    @param state The SAX parser state. */
void
AISDatabaseParser::aisEndElement(AISParserState *state, const char *name)
{
    DBG2(cerr << "End element " << name << " (state " << states[state->state]
	 << ")" << endl);

    switch (state->state) {
      case AIS:
	state->prev_state = state->state;
	state->state = PARSER_FINISH;
	break;

      case ENTRY:
	state->prev_state = state->state;
	state->state = AIS;
	// record 'primary' and 'rv'
	state->ais->add_resource(state->primary, state->rv);
	// empty rv for the next set of ancillary resources.
	state->rv.erase(state->rv.begin(), state->rv.end());
	break;

      case PRIMARY:
	state->prev_state = state->state;
	state->state = ENTRY;
	break;

      case ANCILLARY:
	state->prev_state = state->state;
	state->state = ENTRY;
	break;

      case PARSER_UNKNOWN:
	// Leave the state and prev_state alone.
	state->unknown_depth--;
	break;

      case PARSER_ERROR:
	break;

      default:
	break;
    }
}

/** Handle the standard XML entities.
    @param state The SAX parser state.
    @param name The XML entity. */
xmlEntityPtr
AISDatabaseParser::aisGetEntity(AISParserState *state, const xmlChar *name)
{
    return xmlGetPredefinedEntity(name);
}

/** Process an XML warning. This is treated as a fatal error since there's no
    easy way for libdap++ to signal warning to users.
    @param state The SAX parser state.
    @param msg A printf-style format string. */
void
AISDatabaseParser::aisWarning(AISParserState *state, const char *msg, ...)
{
    va_list args;

    state->state = PARSER_ERROR;

    va_start(args, msg);
    char str[1024];
    vsnprintf(str, 1024, msg, args);
    va_end(args);

    int line = getLineNumber(state->ctxt);
    state->error_msg += "At line: " + long_to_string(line) + ": ";
    state->error_msg += string(str) + string("\n");
}

/** Process an XML error. This is treated as a fatal error since there's no
    easy way for libdap++ to signal warning to users.
    @param state The SAX parser state.
    @param msg A printf-style format string. */
void
AISDatabaseParser::aisError(AISParserState *state, const char *msg, ...)
{
    va_list args;

    state->state = PARSER_ERROR;

    va_start(args, msg);
    char str[1024];
    vsnprintf(str, 1024, msg, args);
    va_end(args);

    int line = getLineNumber(state->ctxt);
    state->error_msg += "At line: " + long_to_string(line) + ": ";
    state->error_msg += string(str) + string("\n");
}

/** Process an XML fatal error.
    @param state The SAX parser state.
    @param msg A printf-style format string. */
void
AISDatabaseParser::aisFatalError(AISParserState *state, const char *msg, ...)
{
    va_list args;

    state->state = PARSER_ERROR;

    va_start(args, msg);
    char str[1024];
    vsnprintf(str, 1024, msg, args);
    va_end(args);

    int line = getLineNumber(state->ctxt);
    state->error_msg += "At line: " + long_to_string(line) + ": ";
    state->error_msg += string(str) + string("\n");
}

//@}

/** This local variable holds pointers to the callback functions which
    comprise the SAX parser. */
static xmlSAXHandler aisSAXParser = {
    0, // internalSubset
    0, // isStandalone
    0, // hasInternalSubset
    0, // hasExternalSubset
    0, // resolveEntity
    (getEntitySAXFunc)AISDatabaseParser::aisGetEntity, // getEntity
    0, // entityDecl
    0, // notationDecl
    0, // attributeDecl
    0, // elementDecl
    0, // unparsedEntityDecl
    0, // setDocumentLocator
    (startDocumentSAXFunc)AISDatabaseParser::aisStartDocument, // startDocument
    (endDocumentSAXFunc)AISDatabaseParser::aisEndDocument,  // endDocument
    (startElementSAXFunc)AISDatabaseParser::aisStartElement,  // startElement
    (endElementSAXFunc)AISDatabaseParser::aisEndElement,  // endElement
    0, // reference
    0, // (charactersSAXFunc)gladeCharacters,  characters
    0, // ignorableWhitespace
    0, // processingInstruction
    0, // (commentSAXFunc)gladeComment,  comment
    (warningSAXFunc)AISDatabaseParser::aisWarning, // warning
    (errorSAXFunc)AISDatabaseParser::aisError, // error
    (fatalErrorSAXFunc)AISDatabaseParser::aisFatalError // fatalError
};

void
AISDatabaseParser::parse(const string &database, AISResources *ais)
    throw(AISDatabaseReadFailed)
{
    xmlParserCtxtPtr ctxt;
    AISParserState state;

    ctxt = xmlCreateFileParserCtxt(database.c_str());
    if (!ctxt)
	return;

    state.ais = ais;		// dump values here
    state.ctxt = ctxt;		// need ctxt for error messages

    ctxt->sax = &aisSAXParser;
    ctxt->userData = &state;
    ctxt->validate = true;

    xmlParseDocument(ctxt);

    // use getLineNumber and getColumnNumber to make the error messages better.
    if (!ctxt->wellFormed) {
	ctxt->sax = NULL;
	xmlFreeParserCtxt(ctxt);
	throw AISDatabaseReadFailed(string("\nThe database is not a well formed XML document.\n") + state.error_msg);
    }

    if (!ctxt->valid) {
	ctxt->sax = NULL;
	xmlFreeParserCtxt(ctxt);
	throw AISDatabaseReadFailed(string("\nThe database is not a valid document.\n") + state.error_msg);
    }

    if (state.state == PARSER_ERROR) {
	ctxt->sax = NULL;
	xmlFreeParserCtxt(ctxt);
	throw AISDatabaseReadFailed(string("\nError parsing AIS resources.\n") + state.error_msg);
    }

    ctxt->sax = NULL;
    xmlFreeParserCtxt(ctxt);
}

// $Log: AISDatabaseParser.cc,v $
// Revision 1.3  2003/02/25 04:18:53  jimg
// Added line numbers to error messages. Improved message formatting a little.
//
// Revision 1.2  2003/02/21 00:14:24  jimg
// Repaired copyright.
//
// Revision 1.1  2003/02/20 22:16:04  jimg
// Added.
//
<|endoftext|>


<commit_before>#include "init.hpp"

#include "DiscardRule"
#include "TokenRule"
#include "MultipleRule"
#include "AlternativeRule"
#include "SequenceRule"

using namespace sprout;

BOOST_AUTO_TEST_CASE(testDiscard)
{
    auto rule = make::discard(
        AnyTokenRule<char, std::string>("_-")
    );
    Result<std::string> tokens;

    auto cursor = makeCursor<char>("_Dog");
    BOOST_CHECK(rule(cursor, tokens));

    BOOST_CHECK(!tokens);
    BOOST_CHECK_EQUAL('D', *cursor);
}

BOOST_AUTO_TEST_CASE(testDiscardWithMultiple)
{
    auto rule = make::discard(
        make::multiple(
            AnyTokenRule<char, std::string>("_-")
        )
    );
    Result<std::string> tokens;

    auto cursor = makeCursor<char>("____----____Dog");
    BOOST_CHECK(rule(cursor, tokens));

    BOOST_CHECK(!tokens);
    BOOST_CHECK_EQUAL('D', *cursor);
}

BOOST_AUTO_TEST_CASE(testDiscardWithLambda)
{
    auto rule = make::discard<char, std::string>(
        [](Cursor<char>& input, Result<std::string>& result) {
            std::string str;
            while (input && *input == '_') {
                str += *input;
                ++input;
            }
            if (!str.empty()) {
                result << str;
            }
            return str;
        }
    );
    Result<std::string> tokens;

    auto cursor = makeCursor<char>("_Dog");
    BOOST_CHECK(rule(cursor, tokens));

    BOOST_CHECK(!tokens);
    BOOST_CHECK_EQUAL('D', *cursor);
}
<commit_msg>Minor refactors to t/discard.cpp's return value<commit_after>#include "init.hpp"

#include "DiscardRule"
#include "TokenRule"
#include "MultipleRule"
#include "AlternativeRule"
#include "SequenceRule"

using namespace sprout;

BOOST_AUTO_TEST_CASE(testDiscard)
{
    auto rule = make::discard(
        AnyTokenRule<char, std::string>("_-")
    );
    Result<std::string> tokens;

    auto cursor = makeCursor<char>("_Dog");
    BOOST_CHECK(rule(cursor, tokens));

    BOOST_CHECK(!tokens);
    BOOST_CHECK_EQUAL('D', *cursor);
}

BOOST_AUTO_TEST_CASE(testDiscardWithMultiple)
{
    auto rule = make::discard(
        make::multiple(
            AnyTokenRule<char, std::string>("_-")
        )
    );
    Result<std::string> tokens;

    auto cursor = makeCursor<char>("____----____Dog");
    BOOST_CHECK(rule(cursor, tokens));

    BOOST_CHECK(!tokens);
    BOOST_CHECK_EQUAL('D', *cursor);
}

BOOST_AUTO_TEST_CASE(testDiscardWithLambda)
{
    auto rule = make::discard<char, std::string>(
        [](Cursor<char>& input, Result<std::string>& result) {
            std::string str;
            while (input && *input == '_') {
                str += *input;
                ++input;
            }
            auto found = !str.empty();
            if (found) {
                result << str;
            }
            return found;
        }
    );
    Result<std::string> tokens;

    auto cursor = makeCursor<char>("_Dog");
    BOOST_CHECK(rule(cursor, tokens));

    BOOST_CHECK(!tokens);
    BOOST_CHECK_EQUAL('D', *cursor);
}
<|endoftext|>


<commit_before>#include "LARACLMB.H"

#include "CAMERA.H"
#include "CONTROL.H"
#include "LARA.H"
#if PSX_VERSION
	#include "PSXINPUT.H"
#else
	#include "PSXPCINPUT.H"
#endif
#include "SPECIFIC.H"

short GetClimbTrigger(long x, long y, long z, short room_number)//46E38, 4729C
{
	S_Warn("[GetClimbTrigger] - Unimplemented!\n");
	return 0;
}

void lara_col_climbend(struct ITEM_INFO *item, struct COLL_INFO *coll)//46E30(<), 47294(<) (F)
{
	return;
}

void lara_as_climbend(struct ITEM_INFO *item, struct COLL_INFO *coll)//46DF8(<), 4725C(<) (F)
{
	coll->enable_baddie_push = 0;
	coll->enable_spaz = 0;
	camera.flags = 1;
	camera.target_angle = -ANGLE45;
}

void lara_col_climbdown(struct ITEM_INFO *item, struct COLL_INFO *coll)//46BD0, 47034
{
	S_Warn("[lara_col_climbdown] - Unimplemented!\n");
}

void lara_as_climbdown(struct ITEM_INFO *item, struct COLL_INFO *coll)//46BA4(<), 47008(<) (F)
{
	coll->enable_baddie_push = 0;
	coll->enable_spaz = 0;
	camera.target_elevation = -ANGLE45;
}

void lara_col_climbing(struct ITEM_INFO *item, struct COLL_INFO *coll)//469B0, 46E14
{
	S_Warn("[lara_col_climbing] - Unimplemented!\n");
}

void lara_as_climbing(struct ITEM_INFO *item, struct COLL_INFO *coll)//46984(<), 46DE8(<) (F)
{
	coll->enable_baddie_push = 0;
	coll->enable_spaz = 0;
	camera.target_elevation = ANGLE30;
}

void lara_col_climbright(struct ITEM_INFO *item, struct COLL_INFO *coll)//46908(<), 46D6C(<) (F)
{
	S_Warn("[lara_col_climbright] - Unimplemented!\n");
	return;

	// DAMN IT why is this casting pointers to int and then treating the ints as pos vectors fml
	// todo someone needs to decompile this (at least the functions calls)
	// they seem wrong af both on psx mips and pc asm / pseudocode
	int shift;
	if (!LaraCheckForLetGo(item, coll))
	{
		lara.move_angle = item->pos.y_rot + ANGLE90;
		LaraDoClimbLeftRight(item, coll,
			//LaraTestClimbPos(item, coll->radius, coll->radius + 120, -512, 512, (int *)coll), shift); // todo it may be wrong af
	}
}

void lara_as_climbright(struct ITEM_INFO *item, struct COLL_INFO *coll)//468B8(<), 46D1C(<) (F)
{
	coll->enable_baddie_push = 0;
	coll->enable_spaz = 0;
	camera.target_angle = ANGLE30;
	camera.target_elevation = -ANGLE15;
	if (!(input & (IN_RIGHT | IN_RSTEP)))
		item->goal_anim_state = STATE_LARA_LADDER_IDLE;
}

void lara_col_climbleft(struct ITEM_INFO *item, struct COLL_INFO *coll)//46834(<), 46C98(<) (F)
{
	if (!LaraCheckForLetGo(item, coll))
	{
		lara.move_angle = item->pos.y_rot - ANGLE90;
		LaraDoClimbLeftRight(item, coll,
			//LaraTestClimbPos(item, coll->radius, -(coll->radius + 120), -512, 512, (int *)&coll), (int)coll); // todo it may be wrong af
	}
}

void lara_as_climbleft(struct ITEM_INFO *item, struct COLL_INFO *coll)//467E4(<), 46C48(<) (F)
{
	coll->enable_baddie_push = 0;
	coll->enable_spaz = 0;
	camera.target_angle = -ANGLE30;
	camera.target_elevation = -ANGLE15;
	if (!(input & (IN_LEFT | IN_LSTEP)))
		item->goal_anim_state = STATE_LARA_LADDER_IDLE;
}

void lara_col_climbstnc(struct ITEM_INFO *item, struct COLL_INFO *coll)//464E8, 4694C
{
	S_Warn("[lara_col_climbstnc] - Unimplemented!\n");
}

void lara_as_climbstnc(struct ITEM_INFO *item, struct COLL_INFO *coll)//463F0, 46854
{
	S_Warn("[lara_as_climbstnc] - Unimplemented!\n");
}

int LaraTestClimbPos(struct ITEM_INFO *item, int front, int right, int origin, int height, int *shift)//462F8, 4675C
{
	S_Warn("[LaraTestClimbPos] - Unimplemented!\n");
	return 0;
}

void LaraDoClimbLeftRight(struct ITEM_INFO *item, struct COLL_INFO *coll, int result, int shift)//46100, 46564
{
	S_Warn("[LaraDoClimbLeftRight] - Unimplemented!\n");
}

int LaraClimbRightCornerTest(struct ITEM_INFO *item, struct COLL_INFO *coll)//45DE4, 46248
{
	S_Warn("[LaraClimbRightCornerTest] - Unimplemented!\n");
	return 0;
}

int LaraClimbLeftCornerTest(struct ITEM_INFO *item, struct COLL_INFO *coll)//45ABC, 45F20
{
	S_Warn("[LaraClimbLeftCornerTest] - Unimplemented!\n");
	return 0;
}

int LaraTestClimb(int x, int y, int z, int xfront, int zfront, int item_height, int item_room, int *shift)//457F0, 45C54
{
	S_Warn("[LaraTestClimb] - Unimplemented!\n");
	return 0;
}

int LaraTestClimbUpPos(struct ITEM_INFO *item, int front, int right, int *shift, int *ledge)//45530, 45994
{
	S_Warn("[LaraTestClimbUpPos] - Unimplemented!\n");
	return 0;
}

long LaraCheckForLetGo(struct ITEM_INFO *item, struct COLL_INFO *coll)//45434, 45898
{
	S_Warn("[LaraCheckForLetGo] - Unimplemented!\n");
	return 0;
}<commit_msg>Oops forgot to comment out this line too...<commit_after>#include "LARACLMB.H"

#include "CAMERA.H"
#include "CONTROL.H"
#include "LARA.H"
#if PSX_VERSION
	#include "PSXINPUT.H"
#else
	#include "PSXPCINPUT.H"
#endif
#include "SPECIFIC.H"

short GetClimbTrigger(long x, long y, long z, short room_number)//46E38, 4729C
{
	S_Warn("[GetClimbTrigger] - Unimplemented!\n");
	return 0;
}

void lara_col_climbend(struct ITEM_INFO *item, struct COLL_INFO *coll)//46E30(<), 47294(<) (F)
{
	return;
}

void lara_as_climbend(struct ITEM_INFO *item, struct COLL_INFO *coll)//46DF8(<), 4725C(<) (F)
{
	coll->enable_baddie_push = 0;
	coll->enable_spaz = 0;
	camera.flags = 1;
	camera.target_angle = -ANGLE45;
}

void lara_col_climbdown(struct ITEM_INFO *item, struct COLL_INFO *coll)//46BD0, 47034
{
	S_Warn("[lara_col_climbdown] - Unimplemented!\n");
}

void lara_as_climbdown(struct ITEM_INFO *item, struct COLL_INFO *coll)//46BA4(<), 47008(<) (F)
{
	coll->enable_baddie_push = 0;
	coll->enable_spaz = 0;
	camera.target_elevation = -ANGLE45;
}

void lara_col_climbing(struct ITEM_INFO *item, struct COLL_INFO *coll)//469B0, 46E14
{
	S_Warn("[lara_col_climbing] - Unimplemented!\n");
}

void lara_as_climbing(struct ITEM_INFO *item, struct COLL_INFO *coll)//46984(<), 46DE8(<) (F)
{
	coll->enable_baddie_push = 0;
	coll->enable_spaz = 0;
	camera.target_elevation = ANGLE30;
}

void lara_col_climbright(struct ITEM_INFO *item, struct COLL_INFO *coll)//46908(<), 46D6C(<) (F)
{
	S_Warn("[lara_col_climbright] - Unimplemented!\n");
	return;

	// DAMN IT why is this casting pointers to int and then treating the ints as pos vectors fml
	// todo someone needs to decompile this (at least the functions calls)
	// they seem wrong af both on psx mips and pc asm / pseudocode
	int shift;
	if (!LaraCheckForLetGo(item, coll))
	{
		lara.move_angle = item->pos.y_rot + ANGLE90;
		//LaraDoClimbLeftRight(item, coll,
			//LaraTestClimbPos(item, coll->radius, coll->radius + 120, -512, 512, (int *)coll), shift); // todo it may be wrong af
	}
}

void lara_as_climbright(struct ITEM_INFO *item, struct COLL_INFO *coll)//468B8(<), 46D1C(<) (F)
{
	coll->enable_baddie_push = 0;
	coll->enable_spaz = 0;
	camera.target_angle = ANGLE30;
	camera.target_elevation = -ANGLE15;
	if (!(input & (IN_RIGHT | IN_RSTEP)))
		item->goal_anim_state = STATE_LARA_LADDER_IDLE;
}

void lara_col_climbleft(struct ITEM_INFO *item, struct COLL_INFO *coll)//46834(<), 46C98(<) (F)
{
	if (!LaraCheckForLetGo(item, coll))
	{
		lara.move_angle = item->pos.y_rot - ANGLE90;
		//LaraDoClimbLeftRight(item, coll,
			//LaraTestClimbPos(item, coll->radius, -(coll->radius + 120), -512, 512, (int *)&coll), (int)coll); // todo it may be wrong af
	}
}

void lara_as_climbleft(struct ITEM_INFO *item, struct COLL_INFO *coll)//467E4(<), 46C48(<) (F)
{
	coll->enable_baddie_push = 0;
	coll->enable_spaz = 0;
	camera.target_angle = -ANGLE30;
	camera.target_elevation = -ANGLE15;
	if (!(input & (IN_LEFT | IN_LSTEP)))
		item->goal_anim_state = STATE_LARA_LADDER_IDLE;
}

void lara_col_climbstnc(struct ITEM_INFO *item, struct COLL_INFO *coll)//464E8, 4694C
{
	S_Warn("[lara_col_climbstnc] - Unimplemented!\n");
}

void lara_as_climbstnc(struct ITEM_INFO *item, struct COLL_INFO *coll)//463F0, 46854
{
	S_Warn("[lara_as_climbstnc] - Unimplemented!\n");
}

int LaraTestClimbPos(struct ITEM_INFO *item, int front, int right, int origin, int height, int *shift)//462F8, 4675C
{
	S_Warn("[LaraTestClimbPos] - Unimplemented!\n");
	return 0;
}

void LaraDoClimbLeftRight(struct ITEM_INFO *item, struct COLL_INFO *coll, int result, int shift)//46100, 46564
{
	S_Warn("[LaraDoClimbLeftRight] - Unimplemented!\n");
}

int LaraClimbRightCornerTest(struct ITEM_INFO *item, struct COLL_INFO *coll)//45DE4, 46248
{
	S_Warn("[LaraClimbRightCornerTest] - Unimplemented!\n");
	return 0;
}

int LaraClimbLeftCornerTest(struct ITEM_INFO *item, struct COLL_INFO *coll)//45ABC, 45F20
{
	S_Warn("[LaraClimbLeftCornerTest] - Unimplemented!\n");
	return 0;
}

int LaraTestClimb(int x, int y, int z, int xfront, int zfront, int item_height, int item_room, int *shift)//457F0, 45C54
{
	S_Warn("[LaraTestClimb] - Unimplemented!\n");
	return 0;
}

int LaraTestClimbUpPos(struct ITEM_INFO *item, int front, int right, int *shift, int *ledge)//45530, 45994
{
	S_Warn("[LaraTestClimbUpPos] - Unimplemented!\n");
	return 0;
}

long LaraCheckForLetGo(struct ITEM_INFO *item, struct COLL_INFO *coll)//45434, 45898
{
	S_Warn("[LaraCheckForLetGo] - Unimplemented!\n");
	return 0;
}<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "DebugOperatorNew.h"

#include <boost/thread.hpp>

#include "MemoryLeakCheck.h"

#include "Foundation.h"
#include "ModuleManager.h"

#include "HttpUtilities.h"

#if defined(_MSC_VER) && defined(MEMORY_LEAK_CHECK)
// for reporting memory leaks upon debug exit
#include <crtdbg.h>
#endif

#if defined(_MSC_VER) && defined(_DMEMDUMP)
// For generating minidump
#include <dbghelp.h>
#include <shellapi.h>
#include <shlobj.h>
#pragma warning(push)
#pragma warning(disable : 4996)
#include <strsafe.h>
#pragma warning(pop)
#endif

void setup(Foundation::Framework &fw);
int run(int argc, char **argv);
void options(int argc, char **argv, Foundation::Framework &fw);

#if defined(_MSC_VER) && defined(_DMEMDUMP)
int generate_dump(EXCEPTION_POINTERS* pExceptionPointers);
#endif

int main (int argc, char **argv)
{
    int return_value = EXIT_SUCCESS;

    // set up a debug flag for memory leaks. Output the results to file when the app exits.
    // Note that this file is written to the same directory where the executable resides,
    // so you can only use this in a development version where you have write access to
    // that directory.
#if defined(_MSC_VER) && defined(MEMORY_LEAK_CHECK)
    int tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF;
    _CrtSetDbgFlag(tmpDbgFlag);

    HANDLE hLogFile = CreateFileW(L"fullmemoryleaklog.txt", GENERIC_WRITE,
      FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
#endif

#if defined(_MSC_VER) && defined(_DMEMDUMP)
    __try
    {
#endif
        return_value = run(argc, argv);

#if defined(_MSC_VER) && defined(_DMEMDUMP)
    }
    __except(generate_dump(GetExceptionInformation()))
    {
    }
#endif

#if defined(_MSC_VER) && defined(MEMORY_LEAK_CHECK)
    if (hLogFile != INVALID_HANDLE_VALUE)
    {
       _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
       _CrtSetReportFile(_CRT_WARN, hLogFile);
       _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
       _CrtSetReportFile(_CRT_ERROR, hLogFile);
       _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
       _CrtSetReportFile(_CRT_ASSERT, hLogFile);
    }
#endif

    // Note: We cannot close the file handle manually here. Have to let the OS close it
    // after it has printed out the list of leaks to the file.
//  CloseHandle(hLogFile);

    return return_value;
}

//! post init setup for framework
void setup (Foundation::Framework &fw)
{
}

int run (int argc, char **argv)
{
    int return_value = EXIT_SUCCESS;

    // Create application object
#if !defined(_DEBUG) || !defined (_MSC_VER)
    try
#endif
    {
        HttpUtilities::InitializeHttp();
        Foundation::Framework fw(argc, argv);
        if (fw.Initialized())
        {
            setup (fw);

            fw.Go();
        }

        HttpUtilities::UninitializeHttp();
    }
#if !defined(_DEBUG) || !defined (_MSC_VER)
    catch (std::exception& e)
    {
        Foundation::Platform::Message("An exception has occurred!", e.what());
#if defined(_DEBUG)
        throw;
#else
        return_value = EXIT_FAILURE;
#endif
    }
#endif

    return return_value;
}

#if defined(_MSC_VER) && defined(WINDOWS_APP)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    // Parse Windows command line
    std::vector<std::string> arguments;

    std::string cmdLine(lpCmdLine);
    unsigned i;
    unsigned cmdStart = 0;
    unsigned cmdEnd = 0;
    bool cmd = false;
    bool quote = false;

    for (i = 0; i < cmdLine.length(); ++i)
    {
        if (cmdLine[i] == '\"')
            quote = !quote;
        if ((cmdLine[i] == ' ') && (!quote))
        {
            if (cmd)
            {
                cmd = false;
                cmdEnd = i;
                arguments.push_back(cmdLine.substr(cmdStart, cmdEnd-cmdStart));
            }
        }
        else
        {
            if (!cmd)
            {
               cmd = true;
               cmdStart = i;
            }
        }
    }
    if (cmd)
        arguments.push_back(cmdLine.substr(cmdStart, i-cmdStart));

    std::vector<const char*> argv;
    for (int i = 0; i < arguments.size(); ++i)
        argv.push_back(arguments[i].c_str());

    if (argv.size())
        return main(argv.size(), (char**)&argv[0]);
    else
        return main(0, 0);
}
#endif

#if defined(_MSC_VER) && defined(_DMEMDUMP)
int generate_dump(EXCEPTION_POINTERS* pExceptionPointers)
{
    BOOL bMiniDumpSuccessful;
    WCHAR szPath[MAX_PATH];
    WCHAR szFileName[MAX_PATH];

    // Can't use Foundation::Application for application name and version,
    // since it might have not been initialized yet, or it might have caused
    // the exception in the first place
    WCHAR* szAppName = L"realXtend";
    WCHAR* szVersion = L"Naali_v0.1";
    DWORD dwBufferSize = MAX_PATH;
    HANDLE hDumpFile;
    SYSTEMTIME stLocalTime;
    MINIDUMP_EXCEPTION_INFORMATION ExpParam;

    GetLocalTime( &stLocalTime );
    GetTempPathW( dwBufferSize, szPath );

    StringCchPrintf( szFileName, MAX_PATH, L"%s%s", szPath, szAppName );
    CreateDirectoryW( szFileName, 0 );
    StringCchPrintf( szFileName, MAX_PATH, L"%s%s\\%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
               szPath, szAppName, szVersion,
               stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
               stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
               GetCurrentProcessId(), GetCurrentThreadId());

    hDumpFile = CreateFileW(szFileName, GENERIC_READ|GENERIC_WRITE,
                FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);

    ExpParam.ThreadId = GetCurrentThreadId();
    ExpParam.ExceptionPointers = pExceptionPointers;
    ExpParam.ClientPointers = TRUE;

    bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
                    hDumpFile, MiniDumpWithDataSegs, &ExpParam, 0, 0);

    std::wstring message(L"Program ");
    message += szAppName;
    message += L" encountered an unexpected error.\n\nCrashdump was saved to location:\n";
    message += szFileName;

    if (bMiniDumpSuccessful)
        Foundation::Platform::Message(L"Minidump generated!", message);
    else
        Foundation::Platform::Message(szAppName, L"Unexpected error was encountered while generating minidump!");

    return EXCEPTION_EXECUTE_HANDLER;
}
#endif

<commit_msg>Push "viewer" as argv[0] in Windows application mode<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "DebugOperatorNew.h"

#include <boost/thread.hpp>

#include "MemoryLeakCheck.h"

#include "Foundation.h"
#include "ModuleManager.h"

#include "HttpUtilities.h"

#if defined(_MSC_VER) && defined(MEMORY_LEAK_CHECK)
// for reporting memory leaks upon debug exit
#include <crtdbg.h>
#endif

#if defined(_MSC_VER) && defined(_DMEMDUMP)
// For generating minidump
#include <dbghelp.h>
#include <shellapi.h>
#include <shlobj.h>
#pragma warning(push)
#pragma warning(disable : 4996)
#include <strsafe.h>
#pragma warning(pop)
#endif

void setup(Foundation::Framework &fw);
int run(int argc, char **argv);
void options(int argc, char **argv, Foundation::Framework &fw);

#if defined(_MSC_VER) && defined(_DMEMDUMP)
int generate_dump(EXCEPTION_POINTERS* pExceptionPointers);
#endif

int main (int argc, char **argv)
{
    int return_value = EXIT_SUCCESS;

    // set up a debug flag for memory leaks. Output the results to file when the app exits.
    // Note that this file is written to the same directory where the executable resides,
    // so you can only use this in a development version where you have write access to
    // that directory.
#if defined(_MSC_VER) && defined(MEMORY_LEAK_CHECK)
    int tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF;
    _CrtSetDbgFlag(tmpDbgFlag);

    HANDLE hLogFile = CreateFileW(L"fullmemoryleaklog.txt", GENERIC_WRITE,
      FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
#endif

#if defined(_MSC_VER) && defined(_DMEMDUMP)
    __try
    {
#endif
        return_value = run(argc, argv);

#if defined(_MSC_VER) && defined(_DMEMDUMP)
    }
    __except(generate_dump(GetExceptionInformation()))
    {
    }
#endif

#if defined(_MSC_VER) && defined(MEMORY_LEAK_CHECK)
    if (hLogFile != INVALID_HANDLE_VALUE)
    {
       _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
       _CrtSetReportFile(_CRT_WARN, hLogFile);
       _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
       _CrtSetReportFile(_CRT_ERROR, hLogFile);
       _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
       _CrtSetReportFile(_CRT_ASSERT, hLogFile);
    }
#endif

    // Note: We cannot close the file handle manually here. Have to let the OS close it
    // after it has printed out the list of leaks to the file.
//  CloseHandle(hLogFile);

    return return_value;
}

//! post init setup for framework
void setup (Foundation::Framework &fw)
{
}

int run (int argc, char **argv)
{
    int return_value = EXIT_SUCCESS;

    // Create application object
#if !defined(_DEBUG) || !defined (_MSC_VER)
    try
#endif
    {
        HttpUtilities::InitializeHttp();
        Foundation::Framework fw(argc, argv);
        if (fw.Initialized())
        {
            setup (fw);

            fw.Go();
        }

        HttpUtilities::UninitializeHttp();
    }
#if !defined(_DEBUG) || !defined (_MSC_VER)
    catch (std::exception& e)
    {
        Foundation::Platform::Message("An exception has occurred!", e.what());
#if defined(_DEBUG)
        throw;
#else
        return_value = EXIT_FAILURE;
#endif
    }
#endif

    return return_value;
}

#if defined(_MSC_VER) && defined(WINDOWS_APP)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    // Parse Windows command line
    std::vector<std::string> arguments;

    std::string cmdLine(lpCmdLine);
    unsigned i;
    unsigned cmdStart = 0;
    unsigned cmdEnd = 0;
    bool cmd = false;
    bool quote = false;

    arguments.push_back("viewer");

    for (i = 0; i < cmdLine.length(); ++i)
    {
        if (cmdLine[i] == '\"')
            quote = !quote;
        if ((cmdLine[i] == ' ') && (!quote))
        {
            if (cmd)
            {
                cmd = false;
                cmdEnd = i;
                arguments.push_back(cmdLine.substr(cmdStart, cmdEnd-cmdStart));
            }
        }
        else
        {
            if (!cmd)
            {
               cmd = true;
               cmdStart = i;
            }
        }
    }
    if (cmd)
        arguments.push_back(cmdLine.substr(cmdStart, i-cmdStart));

    std::vector<const char*> argv;
    for (int i = 0; i < arguments.size(); ++i)
        argv.push_back(arguments[i].c_str());

    if (argv.size())
        return main(argv.size(), (char**)&argv[0]);
    else
        return main(0, 0);
}
#endif

#if defined(_MSC_VER) && defined(_DMEMDUMP)
int generate_dump(EXCEPTION_POINTERS* pExceptionPointers)
{
    BOOL bMiniDumpSuccessful;
    WCHAR szPath[MAX_PATH];
    WCHAR szFileName[MAX_PATH];

    // Can't use Foundation::Application for application name and version,
    // since it might have not been initialized yet, or it might have caused
    // the exception in the first place
    WCHAR* szAppName = L"realXtend";
    WCHAR* szVersion = L"Naali_v0.1";
    DWORD dwBufferSize = MAX_PATH;
    HANDLE hDumpFile;
    SYSTEMTIME stLocalTime;
    MINIDUMP_EXCEPTION_INFORMATION ExpParam;

    GetLocalTime( &stLocalTime );
    GetTempPathW( dwBufferSize, szPath );

    StringCchPrintf( szFileName, MAX_PATH, L"%s%s", szPath, szAppName );
    CreateDirectoryW( szFileName, 0 );
    StringCchPrintf( szFileName, MAX_PATH, L"%s%s\\%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
               szPath, szAppName, szVersion,
               stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
               stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
               GetCurrentProcessId(), GetCurrentThreadId());

    hDumpFile = CreateFileW(szFileName, GENERIC_READ|GENERIC_WRITE,
                FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);

    ExpParam.ThreadId = GetCurrentThreadId();
    ExpParam.ExceptionPointers = pExceptionPointers;
    ExpParam.ClientPointers = TRUE;

    bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
                    hDumpFile, MiniDumpWithDataSegs, &ExpParam, 0, 0);

    std::wstring message(L"Program ");
    message += szAppName;
    message += L" encountered an unexpected error.\n\nCrashdump was saved to location:\n";
    message += szFileName;

    if (bMiniDumpSuccessful)
        Foundation::Platform::Message(L"Minidump generated!", message);
    else
        Foundation::Platform::Message(szAppName, L"Unexpected error was encountered while generating minidump!");

    return EXCEPTION_EXECUTE_HANDLER;
}
#endif

<|endoftext|>


<commit_before>/*

Copyright (c) 2009-2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/allocator.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"

#if defined TORRENT_BEOS
#include <kernel/OS.h>
#include <stdlib.h> // malloc/free
#elif !defined TORRENT_WINDOWS
#include <stdlib.h> // valloc/free
#include <unistd.h> // _SC_PAGESIZE
#endif

#if TORRENT_USE_MEMALIGN || TORRENT_USE_POSIX_MEMALIGN || defined TORRENT_WINDOWS
#include <malloc.h> // memalign and _aligned_malloc
#include <stdlib.h> // _aligned_malloc on mingw
#endif

#ifdef TORRENT_WINDOWS
// windows.h must be included after stdlib.h under mingw
#include <windows.h>
#endif

#ifdef TORRENT_MINGW
#define _aligned_malloc __mingw_aligned_malloc
#define _aligned_free __mingw_aligned_free
#endif

#ifdef TORRENT_DEBUG_BUFFERS
#ifndef TORRENT_WINDOWS
#include <sys/mman.h>
#endif
#include "libtorrent/size_type.hpp"

struct alloc_header
{
	libtorrent::size_type size;
	int magic;
	char stack[3072];
};

#endif

#if defined TORRENT_DEBUG_BUFFERS && (defined __linux__ || (defined __APPLE__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050))
	void print_backtrace(char* out, int len, int max_depth = 0);
#endif

namespace libtorrent
{

	int page_size()
	{
		static int s = 0;
		if (s != 0) return s;

#ifdef TORRENT_WINDOWS
		SYSTEM_INFO si;
		GetSystemInfo(&si);
		s = si.dwPageSize;
#elif defined TORRENT_BEOS
		s = B_PAGE_SIZE;
#else
		s = sysconf(_SC_PAGESIZE);
#endif
		// assume the page size is 4 kiB if we
		// fail to query it
		if (s <= 0) s = 4096;
		return s;
	}

	char* page_aligned_allocator::malloc(size_type bytes)
	{
		TORRENT_ASSERT(bytes >= page_size());
#ifdef TORRENT_DEBUG_BUFFERS
		int page = page_size();
		int num_pages = (bytes + (page-1)) / page + 2;
		char* ret = (char*)valloc(num_pages * page);
		// make the two surrounding pages non-readable and -writable
		alloc_header* h = (alloc_header*)ret;
		h->size = bytes;
		h->magic = 0x1337;
#if defined __linux__ || (defined __APPLE__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
		print_backtrace(h->stack, sizeof(h->stack));
#endif

#ifdef TORRENT_WINDOWS
#define mprotect(buf, size, prot) VirtualProtect(buf, size, prot, NULK)
#define PROT_READ PAGE_READONLY
#endif
		mprotect(ret, page, PROT_READ);
		mprotect(ret + (num_pages-1) * page, page, PROT_READ);

#ifdef TORRENT_WINDOWS
#undef mprotect
#undef PROT_READ
#endif
//		fprintf(stderr, "malloc: %p head: %p tail: %p size: %d\n", ret + page, ret, ret + page + bytes, int(bytes));

		return ret + page;
#endif

#if TORRENT_USE_POSIX_MEMALIGN
		void* ret;
		if (posix_memalign(&ret, page_size(), bytes) != 0) ret = 0;
		return (char*)ret;
#elif TORRENT_USE_MEMALIGN
		return (char*)memalign(page_size(), bytes);
#elif defined TORRENT_WINDOWS
		return (char*)_aligned_malloc(bytes, page_size());
#elif defined TORRENT_BEOS
		void* ret = 0;
		area_id id = create_area("", &ret, B_ANY_ADDRESS
			, (bytes + page_size() - 1) & (page_size()-1), B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
		if (id < B_OK) return 0;
		return (char*)ret;
#else
		return (char*)valloc(bytes);
#endif
	}

	void page_aligned_allocator::free(char* const block)
	{

#ifdef TORRENT_DEBUG_BUFFERS

#ifdef TORRENT_WINDOWS
#define mprotect(buf, size, prot) VirtualProtect(buf, size, prot, NULK)
#define PROT_READ PAGE_READONLY
#define PROT_WRITE PAGE_READWRITE
#endif
		int page = page_size();
		// make the two surrounding pages non-readable and -writable
		mprotect(block - page, page, PROT_READ | PROT_WRITE);
		alloc_header* h = (alloc_header*)(block - page);
		int num_pages = (h->size + (page-1)) / page + 2;
		TORRENT_ASSERT(h->magic == 0x1337);
		mprotect(block + (num_pages-2) * page, page, PROT_READ | PROT_WRITE);
//		fprintf(stderr, "free: %p head: %p tail: %p size: %d\n", block, block - page, block + h->size, int(h->size));
		h->magic = 0;

#ifdef TORRENT_WINDOWS
#undef mprotect
#undef PROT_READ
#undef PROT_WRITE
#endif

#if defined __linux__ || (defined __APPLE__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
		print_backtrace(h->stack, sizeof(h->stack));
#endif
		::free(block - page);
		return;
#endif

#ifdef TORRENT_WINDOWS
		_aligned_free(block);
#elif defined TORRENT_BEOS
		area_id id = area_for(block);
		if (id < B_OK) return;
		delete_area(id);
#else
		::free(block);
#endif
	}

}

<commit_msg>comments<commit_after>/*

Copyright (c) 2009-2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/allocator.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"

#if defined TORRENT_BEOS
#include <kernel/OS.h>
#include <stdlib.h> // malloc/free
#elif !defined TORRENT_WINDOWS
#include <stdlib.h> // valloc/free
#include <unistd.h> // _SC_PAGESIZE
#endif

#if TORRENT_USE_MEMALIGN || TORRENT_USE_POSIX_MEMALIGN || defined TORRENT_WINDOWS
#include <malloc.h> // memalign and _aligned_malloc
#include <stdlib.h> // _aligned_malloc on mingw
#endif

#ifdef TORRENT_WINDOWS
// windows.h must be included after stdlib.h under mingw
#include <windows.h>
#endif

#ifdef TORRENT_MINGW
#define _aligned_malloc __mingw_aligned_malloc
#define _aligned_free __mingw_aligned_free
#endif

#ifdef TORRENT_DEBUG_BUFFERS
#ifndef TORRENT_WINDOWS
#include <sys/mman.h>
#endif
#include "libtorrent/size_type.hpp"

struct alloc_header
{
	libtorrent::size_type size;
	int magic;
	char stack[3072];
};

#endif

#if defined TORRENT_DEBUG_BUFFERS && (defined __linux__ || (defined __APPLE__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050))
	void print_backtrace(char* out, int len, int max_depth = 0);
#endif

namespace libtorrent
{

	int page_size()
	{
		static int s = 0;
		if (s != 0) return s;

#ifdef TORRENT_WINDOWS
		SYSTEM_INFO si;
		GetSystemInfo(&si);
		s = si.dwPageSize;
#elif defined TORRENT_BEOS
		s = B_PAGE_SIZE;
#else
		s = sysconf(_SC_PAGESIZE);
#endif
		// assume the page size is 4 kiB if we
		// fail to query it
		if (s <= 0) s = 4096;
		return s;
	}

	char* page_aligned_allocator::malloc(size_type bytes)
	{
		TORRENT_ASSERT(bytes >= page_size());
#ifdef TORRENT_DEBUG_BUFFERS
		int page = page_size();
		int num_pages = (bytes + (page-1)) / page + 2;
		char* ret = (char*)valloc(num_pages * page);
		// make the two surrounding pages non-readable and -writable
		alloc_header* h = (alloc_header*)ret;
		h->size = bytes;
		h->magic = 0x1337;
#if defined __linux__ || (defined __APPLE__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
		print_backtrace(h->stack, sizeof(h->stack));
#endif

#ifdef TORRENT_WINDOWS
#define mprotect(buf, size, prot) VirtualProtect(buf, size, prot, NULK)
#define PROT_READ PAGE_READONLY
#endif
		mprotect(ret, page, PROT_READ);
		mprotect(ret + (num_pages-1) * page, page, PROT_READ);

#ifdef TORRENT_WINDOWS
#undef mprotect
#undef PROT_READ
#endif
//		fprintf(stderr, "malloc: %p head: %p tail: %p size: %d\n", ret + page, ret, ret + page + bytes, int(bytes));

		return ret + page;
#endif

#if TORRENT_USE_POSIX_MEMALIGN
		void* ret;
		if (posix_memalign(&ret, page_size(), bytes) != 0) ret = 0;
		return (char*)ret;
#elif TORRENT_USE_MEMALIGN
		return (char*)memalign(page_size(), bytes);
#elif defined TORRENT_WINDOWS
		return (char*)_aligned_malloc(bytes, page_size());
#elif defined TORRENT_BEOS
		void* ret = 0;
		area_id id = create_area("", &ret, B_ANY_ADDRESS
			, (bytes + page_size() - 1) & (page_size()-1), B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
		if (id < B_OK) return 0;
		return (char*)ret;
#else
		return (char*)valloc(bytes);
#endif
	}

	void page_aligned_allocator::free(char* const block)
	{

#ifdef TORRENT_DEBUG_BUFFERS

#ifdef TORRENT_WINDOWS
#define mprotect(buf, size, prot) VirtualProtect(buf, size, prot, NULK)
#define PROT_READ PAGE_READONLY
#define PROT_WRITE PAGE_READWRITE
#endif
		int page = page_size();
		// make the two surrounding pages non-readable and -writable
		mprotect(block - page, page, PROT_READ | PROT_WRITE);
		alloc_header* h = (alloc_header*)(block - page);
		int num_pages = (h->size + (page-1)) / page + 2;
		TORRENT_ASSERT(h->magic == 0x1337);
		mprotect(block + (num_pages-2) * page, page, PROT_READ | PROT_WRITE);
//		fprintf(stderr, "free: %p head: %p tail: %p size: %d\n", block, block - page, block + h->size, int(h->size));
		h->magic = 0;

#ifdef TORRENT_WINDOWS
#undef mprotect
#undef PROT_READ
#undef PROT_WRITE
#endif

#if defined __linux__ || (defined __APPLE__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
		print_backtrace(h->stack, sizeof(h->stack));
#endif
		::free(block - page);
		return;
#endif // TORRENT_DEBUG_BUFFERS

#ifdef TORRENT_WINDOWS
		_aligned_free(block);
#elif defined TORRENT_BEOS
		area_id id = area_for(block);
		if (id < B_OK) return;
		delete_area(id);
#else
		::free(block);
#endif // TORRENT_WINDOWS
	}

}

<|endoftext|>


<commit_before>#include "animation.hpp"

//////////////
// Includes //
#include <vector>
#include <tuple>

#include "spritesheet.hpp"
#include "rectangle.hpp"
#include "window.hpp"

//////////
// Code //

// TODO: Do the things with timing for this animation stuff. I think that is useful.

// Determining the index of order for a given time.
int Animation::determineIndex(float time) const {
    // TODO: DO THIS PART :)
    return 0;
}

// Constructing an animation from all required info.
Animation::Animation(SpriteSheet ss, std::vector<std::tuple<int, int>> order, float frameTime, bool repeats) : sheet(ss) {
    this->order     = order;
    this->frameTime = frameTime;
    this->repeats   = repeats;
}

// Constructing an animation with the default ordering (top left to bottom
// right, by row.)
Animation::Animation(SpriteSheet ss, float frameTime, bool repeats) : sheet(ss) {
    for (int row = 0; row < this->sheet.getRows(); row++)
        for (int col = 0; col < this->sheet.getCols(); col++)
            this->order.push_back(std::make_tuple(col, row));

    this->frameTime = frameTime;
    this->repeats   = repeats;
}

// Rendering a specific frame in an animation.
void Animation::blit(Window& w, Rectangle dst, int frame) const {
    auto pos = this->order[frame];
    this->sheet.blit(w, dst, std::get<0>(pos), std::get<1>(pos));
}

// Rendering an animation's current frame.
void Animation::blit(Window& w, Rectangle dst) const {
    // TODO: Determine the current time.
    this->blit(w, dst, this->determineIndex(0));
}
<commit_msg>Wrote the function to determine the index or whatever?<commit_after>#include "animation.hpp"

//////////////
// Includes //
#include <vector>
#include <tuple>

#include "spritesheet.hpp"
#include "rectangle.hpp"
#include "window.hpp"

//////////
// Code //

// Determining the index of order for a given time.
int Animation::determineIndex(float time) const {
    return (int)(time / this->frameTime);
}

// Constructing an animation from all required info.
Animation::Animation(SpriteSheet ss, std::vector<std::tuple<int, int>> order, float frameTime, bool repeats) : sheet(ss) {
    this->order     = order;
    this->frameTime = frameTime;
    this->repeats   = repeats;
}

// Constructing an animation with the default ordering (top left to bottom
// right, by row.)
Animation::Animation(SpriteSheet ss, float frameTime, bool repeats) : sheet(ss) {
    for (int row = 0; row < this->sheet.getRows(); row++)
        for (int col = 0; col < this->sheet.getCols(); col++)
            this->order.push_back(std::make_tuple(col, row));

    this->frameTime = frameTime;
    this->repeats   = repeats;
}

// Rendering a specific frame in an animation.
void Animation::blit(Window& w, Rectangle dst, int frame) const {
    auto pos = this->order[frame];
    this->sheet.blit(w, dst, std::get<0>(pos), std::get<1>(pos));
}

// Rendering an animation's current frame.
void Animation::blit(Window& w, Rectangle dst) const {
    // TODO: Determine the current time.
    this->blit(w, dst, this->determineIndex(0));
}
<|endoftext|>


<commit_before>#include "jakmuse_common.h"

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <cassert>

#include <iostream>
#include <string>
#include <sstream>

static int toknum = 0;
static std::string token("");

#define ENSURE(a) do{ \
    if(!(a)) cancel(#a); \
}while(0)

#define TOKEN(a) do{ \
    std::string STR; \
    std::cin >> STR; \
    std::stringstream S1; \
    S1 << STR; \
    S1 >> a; \
    std::stringstream S; \
    ++toknum; \
    token.assign(STR); \
}while(0)

static void cancel(const char* assertion)
{
    fprintf(stderr, "Syntax error near token %d \"%s\"\n", toknum, token.c_str());
    fprintf(stderr, "Failed assertion '%s'\n", assertion);
    return abort();
}

static bool isnote(char c)
{
    static char notes[] = "CDEFGAB";
    return strchr(notes, c) != NULL;
}

static signed translate_note(char name)
{
    switch(name) {
    case 'C': return 0;
    case 'D': return 2;
    case 'E': return 4;
    case 'F': return 5;
    case 'G': return 7;
    case 'A': return 9;
    case 'B': return 11;
    default: ENSURE(isnote(name));
    }
}

static unsigned short get_frequency(char name, signed scale, char accidental)
{
    signed Ascale = 4;
    signed A = 9;
    signed note = translate_note(name);

    signed step = (scale - Ascale) * 12 + note - A;

    switch(accidental) {
    case '#':
        ++step;
        break;
    case 'b':
        --step;
        break;
    default:
        break;
    }

    return (unsigned short)(440.0f * std::pow(2.0f, (float)step / 12.0f));
}

void parse()
{
    while(!std::cin.eof()) {
        // get channel
        unsigned channel(255);
        TOKEN(channel);
        if(!std::cin.good()) break;
        ENSURE(channel < 5);
        // get fill factor
        unsigned fill(128);
        TOKEN(fill);
        // get scale factor
        unsigned scale(1);
        TOKEN(scale);
        ENSURE(scale > 0);
        // start reading notes
        std::string s;
        do {
            TOKEN(s);
            if(s.empty() || s.compare(";") == 0) break;

            size_t i = 0;
            size_t const ns = s.size();

            int length = 0;
            do {
                if(i >= ns || !isdigit(s[i])) break;
                length *= 10;
                length += s[i++] - '0';
            } while(1);
            ENSURE(length > 0);
            ENSURE(i < ns);

            char note = s[i++];
            unsigned short frequency(0);

            if(isnote(note)) {
                ENSURE(i < ns);
                char accidental = '\0';
                if(s[i] == '#' || s[i] == 'b') {
                    accidental = s[i++];
                }
                ENSURE(i < ns);

                signed offset = 0;
                do {
                    if(i >= ns || !isdigit(s[i])) break;
                    offset *= 10;
                    offset += s[i++] - '0';
                } while(1);
                ENSURE(i >= ns);

                frequency = get_frequency(note, offset, accidental);
            }

            for(size_t i = 0; i < length * scale; ++i) {
                pwm el = { frequency, fill };
                g_channels[channel].push_back(el);
            }

            g_maxChannelLen = std::max(g_maxChannelLen, g_channels[channel].size());
        } while(1);
        ENSURE(std::cin.good());
    }
}
<commit_msg>no longer include assert.h<commit_after>#include "jakmuse_common.h"

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>

#include <iostream>
#include <string>
#include <sstream>

static int toknum = 0;
static std::string token("");

#define ENSURE(a) do{ \
    if(!(a)) cancel(#a); \
}while(0)

#define TOKEN(a) do{ \
    std::string STR; \
    std::cin >> STR; \
    std::stringstream S1; \
    S1 << STR; \
    S1 >> a; \
    std::stringstream S; \
    ++toknum; \
    token.assign(STR); \
}while(0)

static void cancel(const char* assertion)
{
    fprintf(stderr, "Syntax error near token %d \"%s\"\n", toknum, token.c_str());
    fprintf(stderr, "Failed assertion '%s'\n", assertion);
    return abort();
}

static bool isnote(char c)
{
    static char notes[] = "CDEFGAB";
    return strchr(notes, c) != NULL;
}

static signed translate_note(char name)
{
    switch(name) {
    case 'C': return 0;
    case 'D': return 2;
    case 'E': return 4;
    case 'F': return 5;
    case 'G': return 7;
    case 'A': return 9;
    case 'B': return 11;
    default: ENSURE(isnote(name));
    }
}

static unsigned short get_frequency(char name, signed scale, char accidental)
{
    signed Ascale = 4;
    signed A = 9;
    signed note = translate_note(name);

    signed step = (scale - Ascale) * 12 + note - A;

    switch(accidental) {
    case '#':
        ++step;
        break;
    case 'b':
        --step;
        break;
    default:
        break;
    }

    return (unsigned short)(440.0f * std::pow(2.0f, (float)step / 12.0f));
}

void parse()
{
    while(!std::cin.eof()) {
        // get channel
        unsigned channel(255);
        TOKEN(channel);
        if(!std::cin.good()) break;
        ENSURE(channel < 5);
        // get fill factor
        unsigned fill(128);
        TOKEN(fill);
        // get scale factor
        unsigned scale(1);
        TOKEN(scale);
        ENSURE(scale > 0);
        // start reading notes
        std::string s;
        do {
            TOKEN(s);
            if(s.empty() || s.compare(";") == 0) break;

            size_t i = 0;
            size_t const ns = s.size();

            int length = 0;
            do {
                if(i >= ns || !isdigit(s[i])) break;
                length *= 10;
                length += s[i++] - '0';
            } while(1);
            ENSURE(length > 0);
            ENSURE(i < ns);

            char note = s[i++];
            unsigned short frequency(0);

            if(isnote(note)) {
                ENSURE(i < ns);
                char accidental = '\0';
                if(s[i] == '#' || s[i] == 'b') {
                    accidental = s[i++];
                }
                ENSURE(i < ns);

                signed offset = 0;
                do {
                    if(i >= ns || !isdigit(s[i])) break;
                    offset *= 10;
                    offset += s[i++] - '0';
                } while(1);
                ENSURE(i >= ns);

                frequency = get_frequency(note, offset, accidental);
            }

            for(size_t i = 0; i < length * scale; ++i) {
                pwm el = { frequency, fill };
                g_channels[channel].push_back(el);
            }

            g_maxChannelLen = std::max(g_maxChannelLen, g_channels[channel].size());
        } while(1);
        ENSURE(std::cin.good());
    }
}
<|endoftext|>


<commit_before>// This file is part of the "x0" project, http://github.com/christianparpart/x0>
//   (c) 2009-2017 Christian Parpart <christian@parpart.family>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <xzero/http/client/HttpClient.h>
#include <xzero/http/HttpRequest.h>
#include <xzero/http/HeaderFieldList.h>
#include <xzero/net/TcpEndPoint.h>
#include <xzero/executor/PosixScheduler.h>
#include <xzero/net/DnsClient.h>
#include <xzero/io/FileUtil.h>
#include <xzero/Application.h>
#include <xzero/RuntimeError.h>
#include <xzero/Uri.h>
#include <xzero/Flags.h>
#include <xzero/logging.h>
#include <unordered_map>
#include "sysconfig.h"
#include <iostream>
#include <unistd.h>

// #define PACKAGE_VERSION X0_VERSION
#define PACKAGE_HOMEPAGE_URL "https://xzero.io"

#define DEBUG(msg...) logDebug("xurl", msg)
#define TRACE(msg...) logTrace("xurl", msg)

using namespace xzero;
using namespace xzero::http;
using namespace xzero::http::client;

using xzero::http::HttpRequestInfo;
using xzero::http::HttpVersion;
using xzero::http::HeaderField;

class ServicePortMapping { // {{{
 public:
  ServicePortMapping();

  void loadFile(const std::string& path = "/etc/services");
  void loadContent(const std::string& content);

  int tcp(const std::string& name);
  int udp(const std::string& name);

 private:
  std::unordered_map<std::string, int> tcp_;
  std::unordered_map<std::string, int> udp_;
};

ServicePortMapping::ServicePortMapping()
    : tcp_() {
  tcp_["http"] = 80;
  tcp_["https"] = 443;
}

int ServicePortMapping::tcp(const std::string& name) {
  auto i = tcp_.find(name);
  if (i != tcp_.end())
    return i->second;

  RAISE(RuntimeError, "Unknown service '%s'", name.c_str());
}
// }}}

class TerminalLogTarget : public ::xzero::LogTarget { // {{{
 public:
  void log(LogLevel level,
           const std::string& component,
           const std::string& message) override;
};

void TerminalLogTarget::log(LogLevel level,
                            const std::string& component,
                            const std::string& message) {
  if (component == "xurl") {
    printf("%s\n", message.c_str());
  } else {
    printf("[%s] %s\n", component.c_str(), message.c_str());
  }
}
// }}}

class XUrl {
 public:
  XUrl();

  int run(int argc, const char* argv[]);

 private:
  void addRequestHeader(const std::string& value);
  Uri makeUri(const std::string& url);
  IPAddress getIPAddress(const std::string& host);
  int getPort(const Uri& uri);
  void query(const Uri& uri);

 private:
  PosixScheduler scheduler_;
  Flags flags_;
  DnsClient dns_;
  Duration connectTimeout_;
  Duration readTimeout_;
  Duration writeTimeout_;
  TerminalLogTarget logTarget_;
  http::HeaderFieldList requestHeaders_;
};

XUrl::XUrl()
    : scheduler_(CatchAndLogExceptionHandler("xurl")),
      flags_(),
      dns_(),
      connectTimeout_(4_seconds),
      readTimeout_(60_seconds),
      writeTimeout_(10_seconds),
      logTarget_(),
      requestHeaders_()
{
  Application::init();
  //Application::logToStderr(LogLevel::Info);
  Logger::get()->addTarget(&logTarget_);

  requestHeaders_.push_back("User-Agent", "xurl/" PACKAGE_VERSION);

  flags_.defineBool("help", 'h', "Prints this help.");
  flags_.defineBool("head", 'I', "Performs a HEAD request.");
  flags_.defineBool("verbose", 'v', "Be verbose (log level: info)");
  flags_.defineString("output", 'o', "PATH", "Write response body to given file.");
  flags_.defineString("log-level", 'L', "STRING", "Log level.", "warning");
  flags_.defineString("method", 'X', "METHOD", "HTTP method", "GET");
  flags_.defineNumber("connect-timeout", 0, "MS", "TCP connect() timeout", 10_seconds .milliseconds());
  flags_.defineString("upload-file", 'T', "PATH", "Uploads given file.", "");
  flags_.defineString("header", 'H', "HEADER", "Adds a custom request header",
      None(),
      std::bind(&XUrl::addRequestHeader, this, std::placeholders::_1));
  flags_.defineBool("ipv4", '4', "Favor IPv4 for TCP/IP communication.");
  flags_.defineBool("ipv6", '6', "Favor IPv6 for TCP/IP communication.");
  flags_.enableParameters("URL", "URL to query");
}

void XUrl::addRequestHeader(const std::string& field) {
  requestHeaders_.push_back(HeaderField::parse(field));
}

int XUrl::run(int argc, const char* argv[]) {
  std::error_code ec = flags_.parse(argc, argv);
  if (ec) {
    fprintf(stderr, "Failed to parse flags. %s\n", ec.message().c_str());
    return 1;
  }

  if (flags_.isSet("log-level"))
    Logger::get()->setMinimumLogLevel(make_loglevel(flags_.getString("log-level")));

  if (flags_.getBool("verbose"))
    Logger::get()->setMinimumLogLevel(make_loglevel("info"));

  if (flags_.getBool("help")) {
    std::cerr
      << "xurl: Xzero HTTP Client " PACKAGE_VERSION
          << " [" PACKAGE_HOMEPAGE_URL "]" << std::endl
      << "Copyright (c) 2009-2017 by Christian Parpart <christian@parpart.family>" << std::endl
      << std::endl
      << "Usage: xurl [options ...]" << std::endl
      << std::endl
      << "Options:" << std::endl
      << flags_.helpText() << std::endl;
    return 0;
  }

  if (flags_.parameters().empty()) {
    logError("xurl", "No URL given.");
    return 1;
  }

  if (flags_.parameters().size() != 1) {
    logError("xurl", "Too many URLs given.");
  }

  Uri uri = makeUri(flags_.parameters()[0]);
  query(uri);

  return 0;
}

Uri XUrl::makeUri(const std::string& url) {
  Uri uri(url);

  if (uri.path() == "")
    uri.setPath("/");

  return uri;
}

IPAddress XUrl::getIPAddress(const std::string& host) {
  std::vector<IPAddress> ipaddresses = dns_.ipv4(host);
  if (ipaddresses.empty())
    RAISE(RuntimeError, "Could not resolve %s.", host.c_str());

  return ipaddresses.front();
}

int XUrl::getPort(const Uri& uri) {
  if (uri.port())
    return uri.port();

  return ServicePortMapping().tcp(uri.scheme());
}

void XUrl::query(const Uri& uri) {
  IPAddress ipaddr = getIPAddress(uri.host());
  int port = getPort(uri);
  InetAddress inetAddr(ipaddr, port);
  Duration keepAlive = 8_seconds;

  logDebug("xurl", "inet addr: $0, uri: $1", inetAddr, uri.toString());

  TRACE("getting request method");
  std::string method = flags_.getString("method");

  TRACE("getting request head?");
  if (flags_.getBool("head")) {
    method = "HEAD";
  }

  TRACE("getting request body");
  HugeBuffer body;
  if (!flags_.getString("upload-file").empty()) {
    method = "PUT";
    body = FileUtil::read(flags_.getString("upload-file"));
  }

  requestHeaders_.overwrite("Host", uri.hostAndPort());

  HttpRequest req(HttpVersion::VERSION_1_1,
                  method,
                  uri.pathAndQuery(),
                  requestHeaders_,
                  uri.scheme() == "https",
                  std::move(body));
  req.setScheme(uri.scheme());

  logInfo("xurl", "> $0 $1 HTTP/$2", req.unparsedMethod(),
                                     req.unparsedUri(),
                                     req.version());

  for (const HeaderField& field: req.headers()) {
    if (field.name()[0] != ':') {
      logInfo("xurl", "> $0: $1", field.name(), field.value());
    }
  }
  logInfo("xurl", ">");

  HttpClient httpClient(&scheduler_, inetAddr,
                        connectTimeout_, readTimeout_, writeTimeout_,
                        keepAlive);

  Future<HttpClient::Response> f = httpClient.send(req);

  f.onSuccess([](HttpClient::Response& response) {
    logInfo("xurl", "< HTTP/$0 $1 $2", response.version(),
                                       (int) response.status(),
                                       response.reason());

    for (const HeaderField& field: response.headers()) {
      logInfo("xurl", "< $0: $1", field.name(), field.value());
    }
    logInfo("xurl", "<");

    const BufferRef& content = response.content().getBuffer();
    write(STDOUT_FILENO, content.data(), content.size());
  });

  f.onFailure([](std::error_code ec) {
    logError("xurl", "connect() failed. $0", ec.message());
  });

  scheduler_.runLoop();
}

int main(int argc, const char* argv[]) {
  XUrl app;
  return app.run(argc, argv);
}
<commit_msg>[xurl] minors<commit_after>// This file is part of the "x0" project, http://github.com/christianparpart/x0>
//   (c) 2009-2017 Christian Parpart <christian@parpart.family>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <xzero/http/client/HttpClient.h>
#include <xzero/http/HttpRequest.h>
#include <xzero/http/HeaderFieldList.h>
#include <xzero/net/TcpEndPoint.h>
#include <xzero/executor/PosixScheduler.h>
#include <xzero/net/DnsClient.h>
#include <xzero/io/FileUtil.h>
#include <xzero/Application.h>
#include <xzero/RuntimeError.h>
#include <xzero/Uri.h>
#include <xzero/Flags.h>
#include <xzero/logging.h>
#include <unordered_map>
#include "sysconfig.h"
#include <iostream>
#include <unistd.h>

// #define PACKAGE_VERSION X0_VERSION
#define PACKAGE_HOMEPAGE_URL "https://xzero.io"

#define VERBOSE(msg...) logInfo("xurl", msg)
#define DEBUG(msg...) logDebug("xurl", msg)
#define TRACE(msg...) logTrace("xurl", msg)

using namespace xzero;
using namespace xzero::http;
using namespace xzero::http::client;

using xzero::http::HttpRequestInfo;
using xzero::http::HttpVersion;
using xzero::http::HeaderField;

class ServicePortMapping { // {{{
 public:
  ServicePortMapping();

  void loadFile(const std::string& path = "/etc/services");
  void loadContent(const std::string& content);

  int tcp(const std::string& name);
  int udp(const std::string& name);

 private:
  std::unordered_map<std::string, int> tcp_;
  std::unordered_map<std::string, int> udp_;
};

ServicePortMapping::ServicePortMapping()
    : tcp_() {
  tcp_["http"] = 80;
  tcp_["https"] = 443;
}

int ServicePortMapping::tcp(const std::string& name) {
  auto i = tcp_.find(name);
  if (i != tcp_.end())
    return i->second;

  RAISE(RuntimeError, "Unknown service '%s'", name.c_str());
}
// }}}

class TerminalLogTarget : public ::xzero::LogTarget { // {{{
 public:
  void log(LogLevel level,
           const std::string& component,
           const std::string& message) override;
};

void TerminalLogTarget::log(LogLevel level,
                            const std::string& component,
                            const std::string& message) {
  if (component == "xurl") {
    printf("%s\n", message.c_str());
  } else {
    printf("[%s] %s\n", component.c_str(), message.c_str());
  }
}
// }}}

class XUrl {
 public:
  XUrl();

  int run(int argc, const char* argv[]);

 private:
  void addRequestHeader(const std::string& value);
  Uri makeUri(const std::string& url);
  IPAddress getIPAddress(const std::string& host);
  int getPort(const Uri& uri);
  void query(const Uri& uri);

 private:
  PosixScheduler scheduler_;
  Flags flags_;
  DnsClient dns_;
  Duration connectTimeout_;
  Duration readTimeout_;
  Duration writeTimeout_;
  TerminalLogTarget logTarget_;
  http::HeaderFieldList requestHeaders_;
};

XUrl::XUrl()
    : scheduler_(CatchAndLogExceptionHandler("xurl")),
      flags_(),
      dns_(),
      connectTimeout_(4_seconds),
      readTimeout_(60_seconds),
      writeTimeout_(10_seconds),
      logTarget_(),
      requestHeaders_()
{
  Application::init();
  //Application::logToStderr(LogLevel::Info);
  Logger::get()->addTarget(&logTarget_);

  requestHeaders_.push_back("User-Agent", "xurl/" PACKAGE_VERSION);

  flags_.defineBool("help", 'h', "Prints this help.");
  flags_.defineBool("head", 'I', "Performs a HEAD request.");
  flags_.defineBool("verbose", 'v', "Be verbose (log level: info)");
  flags_.defineString("output", 'o', "PATH", "Write response body to given file.");
  flags_.defineString("log-level", 'L', "STRING", "Log level.", "warning");
  flags_.defineString("method", 'X', "METHOD", "HTTP method", "GET");
  flags_.defineNumber("connect-timeout", 0, "MS", "TCP connect() timeout", 10_seconds .milliseconds());
  flags_.defineString("upload-file", 'T', "PATH", "Uploads given file.", "");
  flags_.defineString("header", 'H', "HEADER", "Adds a custom request header",
      None(),
      std::bind(&XUrl::addRequestHeader, this, std::placeholders::_1));
  flags_.defineBool("ipv4", '4', "Favor IPv4 for TCP/IP communication.");
  flags_.defineBool("ipv6", '6', "Favor IPv6 for TCP/IP communication.");
  flags_.enableParameters("URL", "URL to query");
}

void XUrl::addRequestHeader(const std::string& field) {
  requestHeaders_.push_back(HeaderField::parse(field));
}

int XUrl::run(int argc, const char* argv[]) {
  std::error_code ec = flags_.parse(argc, argv);
  if (ec) {
    fprintf(stderr, "Failed to parse flags. %s\n", ec.message().c_str());
    return 1;
  }

  if (flags_.isSet("log-level"))
    Logger::get()->setMinimumLogLevel(make_loglevel(flags_.getString("log-level")));

  if (flags_.getBool("verbose"))
    Logger::get()->setMinimumLogLevel(make_loglevel("info"));

  if (flags_.getBool("help")) {
    std::cerr
      << "xurl: Xzero HTTP Client " PACKAGE_VERSION
          << " [" PACKAGE_HOMEPAGE_URL "]" << std::endl
      << "Copyright (c) 2009-2017 by Christian Parpart <christian@parpart.family>" << std::endl
      << std::endl
      << "Usage: xurl [options ...]" << std::endl
      << std::endl
      << "Options:" << std::endl
      << flags_.helpText() << std::endl;
    return 0;
  }

  if (flags_.parameters().empty()) {
    logError("xurl", "No URL given.");
    return 1;
  }

  if (flags_.parameters().size() != 1) {
    logError("xurl", "Too many URLs given.");
    return 1;
  }

  Uri uri = makeUri(flags_.parameters()[0]);
  query(uri);

  return 0;
}

Uri XUrl::makeUri(const std::string& url) {
  Uri uri(url);

  if (uri.path() == "")
    uri.setPath("/");

  return uri;
}

IPAddress XUrl::getIPAddress(const std::string& host) {
  std::vector<IPAddress> ipaddresses = dns_.ipv4(host);
  if (ipaddresses.empty())
    RAISE(RuntimeError, "Could not resolve %s.", host.c_str());

  return ipaddresses.front();
}

int XUrl::getPort(const Uri& uri) {
  if (uri.port())
    return uri.port();

  return ServicePortMapping().tcp(uri.scheme());
}

void XUrl::query(const Uri& uri) {
  IPAddress ipaddr = getIPAddress(uri.host());
  int port = getPort(uri);
  InetAddress inetAddr(ipaddr, port);
  Duration keepAlive = 8_seconds;

  logDebug("xurl", "inet addr: $0, uri: $1", inetAddr, uri.toString());

  std::string method = flags_.getString("method");

  if (flags_.getBool("head")) {
    method = "HEAD";
  }

  HugeBuffer body;
  if (!flags_.getString("upload-file").empty()) {
    method = "PUT";
    body = FileUtil::read(flags_.getString("upload-file"));
  }

  requestHeaders_.overwrite("Host", uri.hostAndPort());

  HttpRequest req(HttpVersion::VERSION_1_1,
                  method,
                  uri.pathAndQuery(),
                  requestHeaders_,
                  uri.scheme() == "https",
                  std::move(body));
  req.setScheme(uri.scheme());

  VERBOSE("> $0 $1 HTTP/$2", req.unparsedMethod(),
                             req.unparsedUri(),
                             req.version());

  for (const HeaderField& field: req.headers())
    if (field.name()[0] != ':')
      VERBOSE("> $0: $1", field.name(), field.value());

  VERBOSE(">");

  HttpClient httpClient(&scheduler_, inetAddr,
                        connectTimeout_, readTimeout_, writeTimeout_,
                        keepAlive);

  Future<HttpClient::Response> f = httpClient.send(req);

  f.onSuccess([](HttpClient::Response& response) {
    VERBOSE("< HTTP/$0 $1 $2", response.version(),
                               (int) response.status(),
                               response.reason());

    for (const HeaderField& field: response.headers())
      VERBOSE("< $0: $1", field.name(), field.value());

    VERBOSE("<");

    const BufferRef& content = response.content().getBuffer();
    write(STDOUT_FILENO, content.data(), content.size());
  });

  f.onFailure([](std::error_code ec) {
    logError("xurl", "connect() failed. $0", ec.message());
  });

  scheduler_.runLoop();
}

int main(int argc, const char* argv[]) {
  XUrl app;
  return app.run(argc, argv);
}
<|endoftext|>