<commit_before>#include <string>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifdef DARWIN
#include <sys/param.h>
#include <sys/sysctl.h>
#endif
#include <sys/time.h>
#include <sys/stat.h>

#include "tools.h"
#include "failure.h"

using std::string;

/* purpose: formats ISO 8601 timestamp into given buffer (simplified)
 * paramtr: seconds (IN): time stamp
 *          buffer (OUT): where to put the results
 *          size (IN): capacity of buffer
 * returns: pointer to start of buffer for convenience.
 */
char * isodate( time_t seconds, char* buffer, size_t size ) {
    struct tm zulu = *gmtime(&seconds);
    struct tm local = *localtime(&seconds);
    zulu.tm_isdst = local.tm_isdst;
    {
        time_t distance = (seconds - mktime(&zulu)) / 60;
        int hours = distance / 60;
        int minutes = distance < 0 ? -distance % 60 : distance % 60;
        size_t len = strftime( buffer, size, "%Y-%m-%dT%H:%M:%S", &local );
        snprintf( buffer+len, size-len, "%+03d:%02d", hours, minutes );
    }
    return buffer;
}

/* purpose: formats ISO 8601 timestamp into given buffer (simplified)
 * paramtr: seconds_wf (IN): time stamp with fractional seconds (millis)
 *          buffer (OUT): where to put the results
 *          size (IN): capacity of buffer
 * returns: pointer to start of buffer for convenience.
 */
char * iso2date( double seconds_wf, char* buffer, size_t size ) {
    char millis[8];
    double integral, fractional = modf(seconds_wf,&integral);
    time_t seconds = (time_t) integral;
    struct tm zulu = *gmtime(&seconds);
    struct tm local = *localtime(&seconds);
    zulu.tm_isdst = local.tm_isdst;
    snprintf( millis, sizeof(millis), "%.3f", fractional );
    {
        time_t distance = (seconds - mktime(&zulu)) / 60;
        int hours = distance / 60;
        int minutes = distance < 0 ? -distance % 60 : distance % 60;
        size_t len = strftime( buffer, size, "%Y-%m-%dT%H:%M:%S", &local );
        snprintf( buffer+len, size-len, "%s%+03d:%02d", millis+1, hours, minutes );
    }
    return buffer;
}

/* Get the local host name */
void get_host_name(std::string &hostname) {
    char name[HOST_NAME_MAX];
    if (gethostname(name, HOST_NAME_MAX) < 0) {
        myfailures("Unable to get host name");
    }
    hostname = name;
}

/* Get the current time as the number of seconds since the epoch */
double current_time() {
    struct timeval now;
    gettimeofday(&now, NULL);
    double ts = now.tv_sec + (now.tv_usec/1000000.0);
    return ts;
}

/* Get the total amount of physical memory in bytes */
unsigned long get_host_memory() {
    unsigned long memory;
#ifdef DARWIN
    size_t size = sizeof(memory);
    if (sysctlbyname("hw.memsize", &memory, &size, NULL, 0) < 0) {
        myfailures("Unable to get host physical memory size");
    }
#else
    long pages = sysconf(_SC_PHYS_PAGES);
    if (pages < 0) {
        myfailures("Unable to get number of host physical memory pages");
    }
    long pagesize = sysconf(_SC_PAGE_SIZE);
    if (pagesize < 0) {
        myfailures("Unable to get physical page size");
    }
    memory = pages * pagesize;
#endif
    if (memory == 0) {
        myfailure("Invalid memory size: %lu bytes", memory);
    }
    return memory;
}

/* Get the total number of cpus on the host */
unsigned int get_host_cpus() {
    unsigned int cpus;
#ifdef __MACH__
    size_t size = sizeof(cpus);
    if (sysctlbyname("hw.physicalcpu", &cpus, &size, NULL, 0) < 0) {
        myfailures("Unable to get number of physical CPUs");
    }
#else
    long nprocessors = sysconf(_SC_NPROCESSORS_CONF);
    if (nprocessors <= 0) {
        myfailures("Unable to get number of physical CPUs");
    }
    cpus = nprocessors;
#endif
    if (cpus == 0) {
        myfailure("Invalid number of CPUs: %u", cpus);
    }
    return cpus;
}

int mkdirs(const char *path) {
    if (path == NULL || strlen(path) == 0) {
        return 0;
    }

    // No need to create cwd
    if (path[0] == '.' && path[1] == '\0') {
        return 0;
    }

    if (strlen(path) > MAXPATHLEN) {
        errno = ENAMETOOLONG;
        return -1;
    }

    char mypath[MAXPATHLEN];
    char *p = mypath;

    if (path[0] == '.' && path[1] == '.') {
        if (getcwd(mypath, MAXPATHLEN) == NULL) {
            return -1;
        }

        char *parent = strrchr(mypath, '/');
        if (parent) *parent = '\0';

        int off = strlen(mypath);
        strcpy(mypath+off, path+2);

        // In this case we don't need to go back to the root
        p = mypath + off;
    } else if (path[0] == '.' && path[1] == '/') {
        strcpy(mypath, path+2);
    } else {
        strcpy(mypath, path);
    }

    while (*p == '/') p++;

    int created = 0;
    struct stat st;
    while ((p = strchr(p, '/'))) {
        *p = '\0';

        if (stat(mypath, &st)) {
            if (errno == ENOENT) {
                if (mkdir(mypath, 0777)) {
                    return -1;
                }
                created++;
            } else {
                return -1;
            }
        } else {
            // If it exists, make sure it is a dir
            if (S_ISDIR(st.st_mode) == 0) {
                errno = ENOTDIR;
                return -1;
            }
        }

        *p = '/';
        while (*p == '/') p++;
    }

    // Last element of path
    if (stat(mypath, &st)) {
        if (errno == ENOENT) {
            if (mkdir(mypath, 0777)) {
                return -1;
            }
            created++;
        } else {
            return -1;
        }
    } else {
        if (S_ISDIR(st.st_mode) == 0) {
            errno = ENOTDIR;
            return -1;
        }
    }

    return created;
}
<commit_msg>PMC: Use PATH_MAX instead of MAXPATHLEN<commit_after>#include <string>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifdef DARWIN
#include <sys/param.h>
#include <sys/sysctl.h>
#endif
#include <sys/time.h>
#include <sys/stat.h>

#include "tools.h"
#include "failure.h"

using std::string;

/* purpose: formats ISO 8601 timestamp into given buffer (simplified)
 * paramtr: seconds (IN): time stamp
 *          buffer (OUT): where to put the results
 *          size (IN): capacity of buffer
 * returns: pointer to start of buffer for convenience.
 */
char * isodate( time_t seconds, char* buffer, size_t size ) {
    struct tm zulu = *gmtime(&seconds);
    struct tm local = *localtime(&seconds);
    zulu.tm_isdst = local.tm_isdst;
    {
        time_t distance = (seconds - mktime(&zulu)) / 60;
        int hours = distance / 60;
        int minutes = distance < 0 ? -distance % 60 : distance % 60;
        size_t len = strftime( buffer, size, "%Y-%m-%dT%H:%M:%S", &local );
        snprintf( buffer+len, size-len, "%+03d:%02d", hours, minutes );
    }
    return buffer;
}

/* purpose: formats ISO 8601 timestamp into given buffer (simplified)
 * paramtr: seconds_wf (IN): time stamp with fractional seconds (millis)
 *          buffer (OUT): where to put the results
 *          size (IN): capacity of buffer
 * returns: pointer to start of buffer for convenience.
 */
char * iso2date( double seconds_wf, char* buffer, size_t size ) {
    char millis[8];
    double integral, fractional = modf(seconds_wf,&integral);
    time_t seconds = (time_t) integral;
    struct tm zulu = *gmtime(&seconds);
    struct tm local = *localtime(&seconds);
    zulu.tm_isdst = local.tm_isdst;
    snprintf( millis, sizeof(millis), "%.3f", fractional );
    {
        time_t distance = (seconds - mktime(&zulu)) / 60;
        int hours = distance / 60;
        int minutes = distance < 0 ? -distance % 60 : distance % 60;
        size_t len = strftime( buffer, size, "%Y-%m-%dT%H:%M:%S", &local );
        snprintf( buffer+len, size-len, "%s%+03d:%02d", millis+1, hours, minutes );
    }
    return buffer;
}

/* Get the local host name */
void get_host_name(std::string &hostname) {
    char name[HOST_NAME_MAX];
    if (gethostname(name, HOST_NAME_MAX) < 0) {
        myfailures("Unable to get host name");
    }
    hostname = name;
}

/* Get the current time as the number of seconds since the epoch */
double current_time() {
    struct timeval now;
    gettimeofday(&now, NULL);
    double ts = now.tv_sec + (now.tv_usec/1000000.0);
    return ts;
}

/* Get the total amount of physical memory in bytes */
unsigned long get_host_memory() {
    unsigned long memory;
#ifdef DARWIN
    size_t size = sizeof(memory);
    if (sysctlbyname("hw.memsize", &memory, &size, NULL, 0) < 0) {
        myfailures("Unable to get host physical memory size");
    }
#else
    long pages = sysconf(_SC_PHYS_PAGES);
    if (pages < 0) {
        myfailures("Unable to get number of host physical memory pages");
    }
    long pagesize = sysconf(_SC_PAGE_SIZE);
    if (pagesize < 0) {
        myfailures("Unable to get physical page size");
    }
    memory = pages * pagesize;
#endif
    if (memory == 0) {
        myfailure("Invalid memory size: %lu bytes", memory);
    }
    return memory;
}

/* Get the total number of cpus on the host */
unsigned int get_host_cpus() {
    unsigned int cpus;
#ifdef __MACH__
    size_t size = sizeof(cpus);
    if (sysctlbyname("hw.physicalcpu", &cpus, &size, NULL, 0) < 0) {
        myfailures("Unable to get number of physical CPUs");
    }
#else
    long nprocessors = sysconf(_SC_NPROCESSORS_CONF);
    if (nprocessors <= 0) {
        myfailures("Unable to get number of physical CPUs");
    }
    cpus = nprocessors;
#endif
    if (cpus == 0) {
        myfailure("Invalid number of CPUs: %u", cpus);
    }
    return cpus;
}

int mkdirs(const char *path) {
    if (path == NULL || strlen(path) == 0) {
        return 0;
    }

    // No need to create cwd
    if (path[0] == '.' && path[1] == '\0') {
        return 0;
    }

    if (strlen(path) > PATH_MAX) {
        errno = ENAMETOOLONG;
        return -1;
    }

    char mypath[PATH_MAX];
    char *p = mypath;

    if (path[0] == '.' && path[1] == '.') {
        if (getcwd(mypath, PATH_MAX) == NULL) {
            return -1;
        }

        char *parent = strrchr(mypath, '/');
        if (parent) *parent = '\0';

        int off = strlen(mypath);
        strcpy(mypath+off, path+2);

        // In this case we don't need to go back to the root
        p = mypath + off;
    } else if (path[0] == '.' && path[1] == '/') {
        strcpy(mypath, path+2);
    } else {
        strcpy(mypath, path);
    }

    while (*p == '/') p++;

    int created = 0;
    struct stat st;
    while ((p = strchr(p, '/'))) {
        *p = '\0';

        if (stat(mypath, &st)) {
            if (errno == ENOENT) {
                if (mkdir(mypath, 0777)) {
                    return -1;
                }
                created++;
            } else {
                return -1;
            }
        } else {
            // If it exists, make sure it is a dir
            if (S_ISDIR(st.st_mode) == 0) {
                errno = ENOTDIR;
                return -1;
            }
        }

        *p = '/';
        while (*p == '/') p++;
    }

    // Last element of path
    if (stat(mypath, &st)) {
        if (errno == ENOENT) {
            if (mkdir(mypath, 0777)) {
                return -1;
            }
            created++;
        } else {
            return -1;
        }
    } else {
        if (S_ISDIR(st.st_mode) == 0) {
            errno = ENOTDIR;
            return -1;
        }
    }

    return created;
}
<|endoftext|>


<commit_before>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2017 Igor Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

// UnitTest include.
#include <UnitTest/unit_test.hpp>

// cfgfile include.
#include <cfgfile/all.hpp>

// C++ include.
#include <sstream>

class ThirdTag
	:	public cfgfile::tag_t<>
{
public:
	explicit ThirdTag( tag_t<> & owner )
		:	cfgfile::tag_t<>( owner, "thirdTag", false )
		,	m_started( false )
		,	m_finished( false )
		,	m_withString( false )
	{
	}

	bool isStarted() const
	{
		return m_started;
	}

	bool isFinished() const
	{
		return m_finished;
	}

	bool isWithString() const
	{
		return m_withString;
	}

	std::string print( int indent = 0 ) const override
	{
		(void) indent;
		return std::string();
	}

protected:
	void on_start( const cfgfile::parser_info_t<> & ) override
	{
		m_started = true;
	}

	void on_finish( const cfgfile::parser_info_t<> & ) override
	{
		m_finished = true;
	}

	void on_string( const cfgfile::parser_info_t<> &,
		const std::string & ) override
	{
		m_withString = true;
	}

private:
	bool m_started;
	bool m_finished;
	bool m_withString;
}; // class ThirdTag

class SecondTag
	:	public cfgfile::tag_t<>
{
public:
	explicit SecondTag( tag_t<> & owner )
		:	cfgfile::tag_t<>( owner, "secondTag", false )
		,	m_started( false )
		,	m_finished( false )
		,	m_withString( false )
		,	m_child( *this )
	{
	}

	const ThirdTag & thirdTag() const
	{
		return m_child;
	}

	bool isStarted() const
	{
		return m_started;
	}

	bool isFinished() const
	{
		return m_finished;
	}

	bool isWithString() const
	{
		return m_withString;
	}

	std::string print( int indent = 0 ) const override
	{
		(void) indent;
		return std::string();
	}

protected:
	void on_start( const cfgfile::parser_info_t<> & ) override
	{
		m_started = true;
	}

	void on_finish( const cfgfile::parser_info_t<> & ) override
	{
		m_finished = true;
	}

	void on_string( const cfgfile::parser_info_t<> &,
		const std::string & ) override
	{
		m_withString = true;
	}

private:
	bool m_started;
	bool m_finished;
	bool m_withString;
	ThirdTag m_child;
}; // class SecondTag

class FirstTag
	:	public cfgfile::tag_t<>
{
public:
	FirstTag()
		:	cfgfile::tag_t<>( "firstTag", false )
		,	m_started( false )
		,	m_finished( false )
		,	m_withString( false )
		,	m_child( *this )
	{
	}

	const SecondTag & secondTag() const
	{
		return m_child;
	}

	bool isStarted() const
	{
		return m_started;
	}

	bool isFinished() const
	{
		return m_finished;
	}

	bool isWithString() const
	{
		return m_withString;
	}

	std::string print( int indent = 0 ) const override
	{
		(void) indent;
		return std::string();
	}

protected:
	void on_start( const cfgfile::parser_info_t<> & ) override
	{
		m_started = true;
	}

	void on_finish( const cfgfile::parser_info_t<> & ) override
	{
		m_finished = true;
	}

	void on_string( const cfgfile::parser_info_t<> &,
		const std::string & ) override
	{
		m_withString = true;
	}

private:
	bool m_started;
	bool m_finished;
	bool m_withString;
	SecondTag m_child;
}; // class FirstTag

TEST( Parser, test_configWithOneTag )
{
	std::stringstream stream( "{firstTag \"lexeme1\"}" );

	cfgfile::input_stream_t<> input( "test_configWithOneTag", stream );

	FirstTag firstTag;

	cfgfile::parser_t<> parser( firstTag, input );

	parser.parse( "test_configWithOneTag" );

	firstTag.set_defined();

	CHECK_CONDITION( firstTag.is_defined() == true );
	CHECK_CONDITION( firstTag.isStarted() == true );
	CHECK_CONDITION( firstTag.isFinished() == true );
	CHECK_CONDITION( firstTag.isWithString() == true );

	CHECK_CONDITION( firstTag.secondTag().is_defined() == false );
	CHECK_CONDITION( firstTag.secondTag().isStarted() == false );
	CHECK_CONDITION( firstTag.secondTag().isFinished() == false );
	CHECK_CONDITION( firstTag.secondTag().isWithString() == false );

	CHECK_CONDITION( firstTag.secondTag().thirdTag().is_defined() == false );
	CHECK_CONDITION( firstTag.secondTag().thirdTag().isStarted() == false );
	CHECK_CONDITION( firstTag.secondTag().thirdTag().isFinished() == false );
	CHECK_CONDITION( firstTag.secondTag().thirdTag().isWithString() == false );
} // test_configWithOneTag

TEST( Parser, test_configWithThreeTags )
{
	std::stringstream stream( "{firstTag \"lexeme1\"\r\n"
		"\t{secondTag \"lexeme2\"\r\n"
		"\t\t{thirdTag \"lexeme3\"}\r\n"
		"}\r\n"
		"}" );

	cfgfile::input_stream_t<> input( "test_configWithThreeTags", stream );

	FirstTag firstTag;

	cfgfile::parser_t<> parser( firstTag, input );

	parser.parse( "test_configWithThreeTags" );

	firstTag.set_defined();

	CHECK_CONDITION( firstTag.is_defined() == true );
	CHECK_CONDITION( firstTag.isStarted() == true );
	CHECK_CONDITION( firstTag.isFinished() == true );
	CHECK_CONDITION( firstTag.isWithString() == true );

	CHECK_CONDITION( firstTag.secondTag().is_defined() == false );
	CHECK_CONDITION( firstTag.secondTag().isStarted() == true );
	CHECK_CONDITION( firstTag.secondTag().isFinished() == true );
	CHECK_CONDITION( firstTag.secondTag().isWithString() == true );

	CHECK_CONDITION( firstTag.secondTag().thirdTag().is_defined() == false );
	CHECK_CONDITION( firstTag.secondTag().thirdTag().isStarted() == true );
	CHECK_CONDITION( firstTag.secondTag().thirdTag().isFinished() == true );
	CHECK_CONDITION( firstTag.secondTag().thirdTag().isWithString() == true );
} // test_configWithThreeTags

TEST( Parser, test_unexpectedStartCurlBrace )
{
	std::stringstream stream( "{{firstTag \"lexeme1\"}" );

	cfgfile::input_stream_t<> input( "test_unexpectedStartCurlBrace", stream );

	FirstTag firstTag;

	cfgfile::parser_t<> parser( firstTag, input );

	try {
		parser.parse( "test_unexpectedStartCurlBrace" );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() ==
			"Unexpected start curl brace. "
			"We expected tag name, but we've got start curl brace. "
			"In file \"test_unexpectedStartCurlBrace\" on line 1." );

		return;
	}

	CHECK_CONDITION( false );
} // test_unexpectedStartCurlBrace

TEST( Parser, test_unexpectedTagName1 )
{
	std::stringstream stream( "{secondTag \"lexeme1\"}" );

	cfgfile::input_stream_t<> input( "test_unexpectedTagName1", stream );

	FirstTag firstTag;

	cfgfile::parser_t<> parser( firstTag, input );

	try {
		parser.parse( "test_unexpectedTagName1" );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() ==
			"Unexpected tag name. "
			"We expected \"firstTag\", but we've got \"secondTag\". "
			"In file \"test_unexpectedTagName1\" on line 1." );

		return;
	}

	CHECK_CONDITION( false );
} // test_unexpectedTagName1

TEST( Parser, test_unexpectedTagName2 )
{
	std::stringstream stream( "{firstTag \"lexeme1\"\r\n"
		"\t{thirdTag \"lexeme2\"}\r\n"
		"}" );

	cfgfile::input_stream_t<> input( "test_unexpectedTagName2", stream );

	FirstTag firstTag;

	cfgfile::parser_t<> parser( firstTag, input );

	try {
		parser.parse( "test_unexpectedTagName2" );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() ==
			"Unexpected tag name. "
			"We expected one child tag of tag \"firstTag\", "
			"but we've got \"thirdTag\". "
			"In file \"test_unexpectedTagName2\" on line 2." );

		return;
	}

	CHECK_CONDITION( false );
} // test_unexpectedTagName2

TEST( Parser, test_unexpectedEndOfFile )
{
	std::stringstream stream( "{firstTag \"lexeme1\"\r\n"
		"\t{secondTag \"lexeme2\"}\r\n" );

	cfgfile::input_stream_t<> input( "test_unexpectedEndOfFile", stream );

	FirstTag firstTag;

	cfgfile::parser_t<> parser( firstTag, input );

	try {
		parser.parse( "test_unexpectedEndOfFile" );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() ==
			"Unexpected end of file. "
			"Still unfinished tag \"firstTag\"." );

		return;
	}

	CHECK_CONDITION( false );
} // test_unexpectedEndOfFile

class empty_tag_t
	:	public cfgfile::tag_t<>
{
public:
	empty_tag_t( const std::string & name, bool is_mandatory = false )
		:	cfgfile::tag_t<> ( name, is_mandatory )
	{
	}

	empty_tag_t( cfgfile::tag_t<> & parent,
		const std::string & name, bool is_mandatory = false )
		:	cfgfile::tag_t<> ( parent, name, is_mandatory )
	{
	}

	virtual ~empty_tag_t()
	{
	}

	std::string print( int indent = 0 ) const override
	{
		(void) indent;

		return std::string();
	}

	void on_finish( const cfgfile::parser_info_t<> & ) override
	{
	}

	void on_string( const cfgfile::parser_info_t<> &,
		const typename std::string & ) override
	{
	}
};

TEST( Parser, test_undefinedFirstMandatoryTag )
{
	std::stringstream stream( "{cfg}" );

	cfgfile::input_stream_t<> input( "test_undefinedFirstMandatoryTag", stream );

	empty_tag_t tag( "cfg", true );

	cfgfile::parser_t<> parser( tag, input );

	try {
		parser.parse( "test_undefinedFirstMandatoryTag" );

		CHECK_CONDITION( false );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() ==
			"Undefined mandatory tag: \"cfg\"." );
	}
}

int main()
{
	RUN_ALL_TESTS()

	return 0;
}
<commit_msg>Testing.<commit_after>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2017 Igor Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

// UnitTest include.
#include <UnitTest/unit_test.hpp>

// cfgfile include.
#include <cfgfile/all.hpp>

// C++ include.
#include <sstream>

class ThirdTag
	:	public cfgfile::tag_t<>
{
public:
	explicit ThirdTag( tag_t<> & owner )
		:	cfgfile::tag_t<>( owner, "thirdTag", false )
		,	m_started( false )
		,	m_finished( false )
		,	m_withString( false )
	{
	}

	bool isStarted() const
	{
		return m_started;
	}

	bool isFinished() const
	{
		return m_finished;
	}

	bool isWithString() const
	{
		return m_withString;
	}

	std::string print( int indent = 0 ) const override
	{
		(void) indent;
		return std::string();
	}

protected:
	void on_start( const cfgfile::parser_info_t<> & ) override
	{
		m_started = true;
	}

	void on_finish( const cfgfile::parser_info_t<> & ) override
	{
		m_finished = true;
	}

	void on_string( const cfgfile::parser_info_t<> &,
		const std::string & ) override
	{
		m_withString = true;
	}

private:
	bool m_started;
	bool m_finished;
	bool m_withString;
}; // class ThirdTag

class SecondTag
	:	public cfgfile::tag_t<>
{
public:
	explicit SecondTag( tag_t<> & owner )
		:	cfgfile::tag_t<>( owner, "secondTag", false )
		,	m_started( false )
		,	m_finished( false )
		,	m_withString( false )
		,	m_child( *this )
	{
	}

	const ThirdTag & thirdTag() const
	{
		return m_child;
	}

	bool isStarted() const
	{
		return m_started;
	}

	bool isFinished() const
	{
		return m_finished;
	}

	bool isWithString() const
	{
		return m_withString;
	}

	std::string print( int indent = 0 ) const override
	{
		(void) indent;
		return std::string();
	}

protected:
	void on_start( const cfgfile::parser_info_t<> & ) override
	{
		m_started = true;
	}

	void on_finish( const cfgfile::parser_info_t<> & ) override
	{
		m_finished = true;
	}

	void on_string( const cfgfile::parser_info_t<> &,
		const std::string & ) override
	{
		m_withString = true;
	}

private:
	bool m_started;
	bool m_finished;
	bool m_withString;
	ThirdTag m_child;
}; // class SecondTag

class FirstTag
	:	public cfgfile::tag_t<>
{
public:
	FirstTag()
		:	cfgfile::tag_t<>( "firstTag", false )
		,	m_started( false )
		,	m_finished( false )
		,	m_withString( false )
		,	m_child( *this )
	{
	}

	const SecondTag & secondTag() const
	{
		return m_child;
	}

	bool isStarted() const
	{
		return m_started;
	}

	bool isFinished() const
	{
		return m_finished;
	}

	bool isWithString() const
	{
		return m_withString;
	}

	std::string print( int indent = 0 ) const override
	{
		(void) indent;
		return std::string();
	}

protected:
	void on_start( const cfgfile::parser_info_t<> & ) override
	{
		m_started = true;
	}

	void on_finish( const cfgfile::parser_info_t<> & ) override
	{
		m_finished = true;
	}

	void on_string( const cfgfile::parser_info_t<> &,
		const std::string & ) override
	{
		m_withString = true;
	}

private:
	bool m_started;
	bool m_finished;
	bool m_withString;
	SecondTag m_child;
}; // class FirstTag

TEST( Parser, test_configWithOneTag )
{
	std::stringstream stream( "{firstTag \"lexeme1\"}" );

	cfgfile::input_stream_t<> input( "test_configWithOneTag", stream );

	FirstTag firstTag;

	cfgfile::parser_t<> parser( firstTag, input );

	parser.parse( "test_configWithOneTag" );

	firstTag.set_defined();

	CHECK_CONDITION( firstTag.is_defined() == true );
	CHECK_CONDITION( firstTag.isStarted() == true );
	CHECK_CONDITION( firstTag.isFinished() == true );
	CHECK_CONDITION( firstTag.isWithString() == true );

	CHECK_CONDITION( firstTag.secondTag().is_defined() == false );
	CHECK_CONDITION( firstTag.secondTag().isStarted() == false );
	CHECK_CONDITION( firstTag.secondTag().isFinished() == false );
	CHECK_CONDITION( firstTag.secondTag().isWithString() == false );

	CHECK_CONDITION( firstTag.secondTag().thirdTag().is_defined() == false );
	CHECK_CONDITION( firstTag.secondTag().thirdTag().isStarted() == false );
	CHECK_CONDITION( firstTag.secondTag().thirdTag().isFinished() == false );
	CHECK_CONDITION( firstTag.secondTag().thirdTag().isWithString() == false );
} // test_configWithOneTag

TEST( Parser, test_configWithThreeTags )
{
	std::stringstream stream( "{firstTag \"lexeme1\"\r\n"
		"\t{secondTag \"lexeme2\"\r\n"
		"\t\t{thirdTag \"lexeme3\"}\r\n"
		"}\r\n"
		"}" );

	cfgfile::input_stream_t<> input( "test_configWithThreeTags", stream );

	FirstTag firstTag;

	cfgfile::parser_t<> parser( firstTag, input );

	parser.parse( "test_configWithThreeTags" );

	firstTag.set_defined();

	CHECK_CONDITION( firstTag.is_defined() == true );
	CHECK_CONDITION( firstTag.isStarted() == true );
	CHECK_CONDITION( firstTag.isFinished() == true );
	CHECK_CONDITION( firstTag.isWithString() == true );

	CHECK_CONDITION( firstTag.secondTag().is_defined() == false );
	CHECK_CONDITION( firstTag.secondTag().isStarted() == true );
	CHECK_CONDITION( firstTag.secondTag().isFinished() == true );
	CHECK_CONDITION( firstTag.secondTag().isWithString() == true );

	CHECK_CONDITION( firstTag.secondTag().thirdTag().is_defined() == false );
	CHECK_CONDITION( firstTag.secondTag().thirdTag().isStarted() == true );
	CHECK_CONDITION( firstTag.secondTag().thirdTag().isFinished() == true );
	CHECK_CONDITION( firstTag.secondTag().thirdTag().isWithString() == true );
} // test_configWithThreeTags

TEST( Parser, test_unexpectedStartCurlBrace )
{
	std::stringstream stream( "{{firstTag \"lexeme1\"}" );

	cfgfile::input_stream_t<> input( "test_unexpectedStartCurlBrace", stream );

	FirstTag firstTag;

	cfgfile::parser_t<> parser( firstTag, input );

	try {
		parser.parse( "test_unexpectedStartCurlBrace" );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() ==
			"Unexpected start curl brace. "
			"We expected tag name, but we've got start curl brace. "
			"In file \"test_unexpectedStartCurlBrace\" on line 1." );

		return;
	}

	CHECK_CONDITION( false );
} // test_unexpectedStartCurlBrace

TEST( Parser, test_unexpectedTagName1 )
{
	std::stringstream stream( "{secondTag \"lexeme1\"}" );

	cfgfile::input_stream_t<> input( "test_unexpectedTagName1", stream );

	FirstTag firstTag;

	cfgfile::parser_t<> parser( firstTag, input );

	try {
		parser.parse( "test_unexpectedTagName1" );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() ==
			"Unexpected tag name. "
			"We expected \"firstTag\", but we've got \"secondTag\". "
			"In file \"test_unexpectedTagName1\" on line 1." );

		return;
	}

	CHECK_CONDITION( false );
} // test_unexpectedTagName1

TEST( Parser, test_unexpectedTagName2 )
{
	std::stringstream stream( "{firstTag \"lexeme1\"\r\n"
		"\t{thirdTag \"lexeme2\"}\r\n"
		"}" );

	cfgfile::input_stream_t<> input( "test_unexpectedTagName2", stream );

	FirstTag firstTag;

	cfgfile::parser_t<> parser( firstTag, input );

	try {
		parser.parse( "test_unexpectedTagName2" );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() ==
			"Unexpected tag name. "
			"We expected one child tag of tag \"firstTag\", "
			"but we've got \"thirdTag\". "
			"In file \"test_unexpectedTagName2\" on line 2." );

		return;
	}

	CHECK_CONDITION( false );
} // test_unexpectedTagName2

TEST( Parser, test_unexpectedEndOfFile )
{
	std::stringstream stream( "{firstTag \"lexeme1\"\r\n"
		"\t{secondTag \"lexeme2\"}\r\n" );

	cfgfile::input_stream_t<> input( "test_unexpectedEndOfFile", stream );

	FirstTag firstTag;

	cfgfile::parser_t<> parser( firstTag, input );

	try {
		parser.parse( "test_unexpectedEndOfFile" );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() ==
			"Unexpected end of file. "
			"Still unfinished tag \"firstTag\"." );

		return;
	}

	CHECK_CONDITION( false );
} // test_unexpectedEndOfFile

class empty_tag_t
	:	public cfgfile::tag_t<>
{
public:
	empty_tag_t( const std::string & name, bool is_mandatory = false )
		:	cfgfile::tag_t<> ( name, is_mandatory )
	{
	}

	empty_tag_t( cfgfile::tag_t<> & parent,
		const std::string & name, bool is_mandatory = false )
		:	cfgfile::tag_t<> ( parent, name, is_mandatory )
	{
	}

	virtual ~empty_tag_t()
	{
	}

	std::string print( int indent = 0 ) const override
	{
		(void) indent;

		return std::string();
	}

	void on_finish( const cfgfile::parser_info_t<> & ) override
	{
	}

	void on_string( const cfgfile::parser_info_t<> &,
		const typename std::string & ) override
	{
	}
};

TEST( Parser, test_undefinedFirstMandatoryTag )
{
	std::stringstream stream( "{cfg}" );

	cfgfile::input_stream_t<> input( "test_undefinedFirstMandatoryTag", stream );

	empty_tag_t tag( "cfg", true );

	cfgfile::parser_t<> parser( tag, input );

	try {
		parser.parse( "test_undefinedFirstMandatoryTag" );

		CHECK_CONDITION( false );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() ==
			"Undefined mandatory tag: \"cfg\"." );
	}
}

TEST( Parser, test_undefinedFirstTag )
{
	std::stringstream stream( "" );

	cfgfile::input_stream_t<> input( "test_undefinedFirstTag", stream );

	empty_tag_t tag( "cfg" );

	cfgfile::parser_t<> parser( tag, input );

	parser.parse( "test_undefinedFirstTag" );

	CHECK_CONDITION( true );
}

TEST( Parser, test_unexpectedContent )
{
	std::stringstream stream( "{cfg} abc" );

	cfgfile::input_stream_t<> input( "test_unexpectedContent", stream );

	empty_tag_t tag( "cfg" );

	cfgfile::parser_t<> parser( tag, input );

	try {
		parser.parse( "test_unexpectedContent" );

		CHECK_CONDITION( false );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() == "Unexpected content. "
			"We've finished parsing, but we've got this: \"abc\". "
			"In file \"test_unexpectedContent\" on line 1." )
	}
}

TEST( Parser, test_unexpectedContent2 )
{
	std::stringstream stream( "abc" );

	cfgfile::input_stream_t<> input( "test_unexpectedContent", stream );

	empty_tag_t tag( "cfg" );

	cfgfile::parser_t<> parser( tag, input );

	try {
		parser.parse( "test_unexpectedContent" );

		CHECK_CONDITION( false );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() == "Expected start curl brace, "
			"but we've got \"abc\". In file \"test_unexpectedContent\" "
			"on line 1." )
	}
}

TEST( Parser, test_unexpectedFinish )
{
	std::stringstream stream( "{}" );

	cfgfile::input_stream_t<> input( "test_unexpectedFinish", stream );

	empty_tag_t tag( "cfg" );

	cfgfile::parser_t<> parser( tag, input );

	try {
		parser.parse( "test_unexpectedFinish" );

		CHECK_CONDITION( false );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() == "Unexpected finish curl brace. "
			"We expected tag name, but we've got finish curl brace. "
			"In file \"test_unexpectedFinish\" on line 1." )
	}
}

TEST( Parser, test_unexpectedEndOfFile2 )
{
	std::stringstream stream( "{" );

	cfgfile::input_stream_t<> input( "test_unexpectedEndOfFile", stream );

	empty_tag_t tag( "cfg" );

	cfgfile::parser_t<> parser( tag, input );

	try {
		parser.parse( "test_unexpectedEndOfFile" );

		CHECK_CONDITION( false );
	}
	catch( cfgfile::exception_t<> & x )
	{
		CHECK_CONDITION( x.desc() == "Unexpected end of file. "
			"In file \"test_unexpectedEndOfFile\" on line 1." )
	}
}

int main()
{
	RUN_ALL_TESTS()

	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#include    <cstdlib>
#include    <cstring>
#include    <ctime>

#if     qPlatform_POSIX
#include    <time.h>
#endif

#include    "../Configuration/Common.h"
#include    "../Characters/String.h"
#include    "../Characters/String_Constant.h"
#include    "../Containers/Mapping.h"
#include    "../Debug/Assertions.h"
#include    "../Debug/Trace.h"
#include    "DateTime.h"
#include    "../IO/FileSystem/BinaryFileInputStream.h"
#include    "../Streams/TextInputStreamBinaryAdapter.h"

#include    "Timezone.h"

using   namespace   Stroika;
using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Characters;
using   namespace   Stroika::Foundation::Time;

/*
 ********************************************************************************
 ***************************** Time::GetTimezoneInfo ****************************
 ********************************************************************************
 */
TimeZoneInformationType    Time::GetTimezoneInfo ()
{
    TimeZoneInformationType result;
#if     qPlatform_POSIX
    try {
        result.fID = Streams::TextInputStreamBinaryAdapter (IO::FileSystem::BinaryFileInputStream::mk (String_Constant (L"/etc/timezone"))).ReadAll ().Trim ();
    }
    catch (...) {
        DbgTrace ("Ignoring missing ID from /etc/timezone");
    }
    // @see http://pubs.opengroup.org/onlinepubs/7908799/xsh/tzset.html
    result.fStandardTime.fName = String::FromSDKString (tzname[0]);
    result.fDaylightSavingsTime.fName = String::FromSDKString (tzname[1]);
#elif   qPlatform_Windows
    using   Containers::Mapping;
    using   Common::KeyValuePair;
    static const    Mapping<String, String> kWinDoze2OlsonName_ =  {
        KeyValuePair<String, String> { L"Afghanistan Standard Time", L"Asia/Kabul" },
        KeyValuePair<String, String> { L"Alaskan Standard Time", L"America/Juneau" },
        KeyValuePair<String, String> { L"Arab Standard Time", L"Asia/Riyadh" },
        KeyValuePair<String, String> { L"Arabian Standard Time", L"Asia/Muscat" },
        KeyValuePair<String, String> { L"Arabic Standard Time", L"Asia/Baghdad" },
        KeyValuePair<String, String> { L"Argentina Standard Time", L"America/Rosario" },
        KeyValuePair<String, String> { L"Atlantic Standard Time", L"America/Halifax" },
        KeyValuePair<String, String> { L"AUS Central Standard Time", L"Australia/Darwin" },
        KeyValuePair<String, String> { L"AUS Eastern Standard Time", L"Australia/Sydney" },
        KeyValuePair<String, String> { L"Azerbaijan Standard Time", L"Asia/Baku" },
        KeyValuePair<String, String> { L"Azores Standard Time", L"Atlantic/Azores" },
        KeyValuePair<String, String> { L"Bahia Standard Time", L"America/Maceio" },
        KeyValuePair<String, String> { L"Bangladesh Standard Time", L"Asia/Dhaka" },
        KeyValuePair<String, String> { L"Canada Central Standard Time", L"America/Swift_Current" },
        KeyValuePair<String, String> { L"Cape Verde Standard Time", L"Atlantic/Cape_Verde" },
        KeyValuePair<String, String> { L"Caucasus Standard Time", L"Asia/Yerevan" },
        KeyValuePair<String, String> { L"Cen. Australia Standard Time", L"Australia/Adelaide" },
        KeyValuePair<String, String> { L"Central America Standard Time", L"America/Tegucigalpa" },
        KeyValuePair<String, String> { L"Central Asia Standard Time", L"Asia/Almaty" },
        KeyValuePair<String, String> { L"Central Brazilian Standard Time", L"America/Cuiaba" },
        KeyValuePair<String, String> { L"Central Europe Standard Time", L"Europe/Prague" },
        KeyValuePair<String, String> { L"Central European Standard Time", L"Europe/Skopje" },
        KeyValuePair<String, String> { L"Central Pacific Standard Time", L"Pacific/Guadalcanal" },
        KeyValuePair<String, String> { L"Central Standard Time", L"America/Chicago" },
        KeyValuePair<String, String> { L"Central Standard Time (Mexico)", L"America/Monterrey" },
        KeyValuePair<String, String> { L"China Standard Time", L"Asia/Urumqi" },
        KeyValuePair<String, String> { L"E. Africa Standard Time", L"Africa/Nairobi" },
        KeyValuePair<String, String> { L"E. Australia Standard Time", L"Australia/Brisbane" },
        KeyValuePair<String, String> { L"E. Europe Standard Time", L"Europe/Bucharest" },
        KeyValuePair<String, String> { L"E. South America Standard Time", L"America/Sao_Paulo" },
        KeyValuePair<String, String> { L"Eastern Standard Time", L"America/New_York" },
        KeyValuePair<String, String> { L"Egypt Standard Time", L"Africa/Cairo" },
        KeyValuePair<String, String> { L"Ekaterinburg Standard Time", L"Asia/Yekaterinburg" },
        KeyValuePair<String, String> { L"Fiji Standard Time", L"Pacific/Fiji" },
        KeyValuePair<String, String> { L"FLE Standard Time", L"Europe/Helsinki" },
        KeyValuePair<String, String> { L"Georgian Standard Time", L"Asia/Tbilisi" },
        KeyValuePair<String, String> { L"GMT Standard Time", L"Europe/London" },
        KeyValuePair<String, String> { L"Greenland Standard Time", L"America/Godthab" },
        KeyValuePair<String, String> { L"Greenwich Standard Time", L"Atlantic/Reykjavik" },
        KeyValuePair<String, String> { L"GTB Standard Time", L"Europe/Bucharest" },
        KeyValuePair<String, String> { L"Hawaiian Standard Time", L"Pacific/Honolulu" },
        KeyValuePair<String, String> { L"India Standard Time", L"Asia/Calcutta" },
        KeyValuePair<String, String> { L"Iran Standard Time", L"Asia/Tehran" },
        KeyValuePair<String, String> { L"Jerusalem Standard Time", L"Asia/Jerusalem" },
        KeyValuePair<String, String> { L"Jordan Standard Time", L"Asia/Amman" },
        KeyValuePair<String, String> { L"Kaliningrad Standard Time", L"Europe/Kaliningrad" },
        KeyValuePair<String, String> { L"Korea Standard Time", L"Asia/Seoul" },
        KeyValuePair<String, String> { L"Libya Standard Time", L"Africa/Tripoli" },
        KeyValuePair<String, String> { L"Magadan Standard Time", L"Asia/Magadan" },
        KeyValuePair<String, String> { L"Mauritius Standard Time", L"Indian/Mauritius" },
        KeyValuePair<String, String> { L"Middle East Standard Time", L"Asia/Beirut" },
        KeyValuePair<String, String> { L"Montevideo Standard Time", L"America/Montevideo" },
        KeyValuePair<String, String> { L"Morocco Standard Time", L"Africa/Casablanca" },
        KeyValuePair<String, String> { L"Mountain Standard Time", L"America/Denver" },
        KeyValuePair<String, String> { L"Mountain Standard Time (Mexico)", L"America/Mazatlan" },
        KeyValuePair<String, String> { L"Myanmar Standard Time", L"Asia/Rangoon" },
        KeyValuePair<String, String> { L"N. Central Asia Standard Time", L"Asia/Novosibirsk" },
        KeyValuePair<String, String> { L"Namibia Standard Time", L"Africa/Windhoek" },
        KeyValuePair<String, String> { L"Nepal Standard Time", L"Asia/Katmandu" },
        KeyValuePair<String, String> { L"New Zealand Standard Time", L"Pacific/Auckland" },
        KeyValuePair<String, String> { L"Newfoundland Standard Time", L"America/St_Johns" },
        KeyValuePair<String, String> { L"North Asia East Standard Time", L"Asia/Irkutsk" },
        KeyValuePair<String, String> { L"North Asia Standard Time", L"Asia/Krasnoyarsk" },
        KeyValuePair<String, String> { L"Pacific SA Standard Time", L"America/Santiago" },
        KeyValuePair<String, String> { L"Pacific Standard Time", L"America/Los_Angeles" },
        KeyValuePair<String, String> { L"Pacific Standard Time (Mexico)", L"America/Tijuana" },
        KeyValuePair<String, String> { L"Pakistan Standard Time", L"Asia/Karachi" },
        KeyValuePair<String, String> { L"Paraguay Standard Time", L"America/Asuncion" },
        KeyValuePair<String, String> { L"Romance Standard Time", L"Europe/Paris" },
        KeyValuePair<String, String> { L"Russian Standard Time", L"Europe/Moscow" },
        KeyValuePair<String, String> { L"SA Eastern Standard Time", L"America/Cayenne" },
        KeyValuePair<String, String> { L"SA Pacific Standard Time", L"America/Lima" },
        KeyValuePair<String, String> { L"SA Western Standard Time", L"America/La_Paz" },
        KeyValuePair<String, String> { L"SE Asia Standard Time", L"Asia/Jakarta" },
        KeyValuePair<String, String> { L"Malay Peninsula Standard Time", L"Asia/Singapore" },
        KeyValuePair<String, String> { L"South Africa Standard Time", L"Africa/Harare" },
        KeyValuePair<String, String> { L"Syria Standard Time", L"Asia/Damascus" },
        KeyValuePair<String, String> { L"Taipei Standard Time", L"Asia/Taipei" },
        KeyValuePair<String, String> { L"Tasmania Standard Time", L"Australia/Hobart" },
        KeyValuePair<String, String> { L"Tokyo Standard Time", L"Asia/Tokyo" },
        KeyValuePair<String, String> { L"Tonga Standard Time", L"Pacific/Tongatapu" },
        KeyValuePair<String, String> { L"Turkey Standard Time", L"Asia/Istanbul" },
        KeyValuePair<String, String> { L"Ulaanbaatar Standard Time", L"Asia/Ulaanbaatar" },
        KeyValuePair<String, String> { L"US Eastern Standard Time", L"America/Indianapolis" },
        KeyValuePair<String, String> { L"US Mountain Standard Time", L"America/Denver" },
        KeyValuePair<String, String> { L"Venezuela Standard Time", L"America/Caracas" },
        KeyValuePair<String, String> { L"Vladivostok Standard Time", L"Asia/Vladivostok" },
        KeyValuePair<String, String> { L"W. Australia Standard Time", L"Australia/Perth" },
        KeyValuePair<String, String> { L"W. Central Africa Standard Time", L"Africa/Brazzaville" },
        KeyValuePair<String, String> { L"W. Europe Standard Time", L"Europe/Vienna" },
        KeyValuePair<String, String> { L"West Asia Standard Time", L"Asia/Tashkent" },
        KeyValuePair<String, String> { L"West Pacific Standard Time", L"Pacific/Port_Moresby" },
        KeyValuePair<String, String> { L"Yakutsk Standard Time", L"Asia/Yakutsk" }
    };
    TIME_ZONE_INFORMATION   tzInfo;
    memset (&tzInfo, 0, sizeof (tzInfo));
    (void)::GetTimeZoneInformation (&tzInfo);
    result.fStandardTime.fName = tzInfo.StandardName;
    result.fDaylightSavingsTime.fName = tzInfo.DaylightName;
    result.fID = kWinDoze2OlsonName_.LookupValue (tzInfo.StandardName, tzInfo.StandardName);
#else
    AssertNotImplemented ();
    return String ();
#endif
    return result;
}

/*
 ********************************************************************************
 ********************************* Time::GetTimezone ****************************
 ********************************************************************************
 */
String    Time::GetTimezone ()
{
    return GetTimezone (DateTime::Now ());
}

String    Time::GetTimezone (bool applyDST)
{
#if     qPlatform_Windows
    TIME_ZONE_INFORMATION   tzInfo;
    memset (&tzInfo, 0, sizeof (tzInfo));
    (void)::GetTimeZoneInformation (&tzInfo);
    return tzInfo.StandardName;
#elif   qPlatform_POSIX
    // @see http://pubs.opengroup.org/onlinepubs/7908799/xsh/tzset.html
    return String::FromSDKString (IsDaylightSavingsTime (DateTime::Now ()) ? tzname[1] : tzname[0]);
#else
    AssertNotImplemented ();
    return String ();
#endif
}

String    Time::GetTimezone (const DateTime& d)
{
    return GetTimezone (IsDaylightSavingsTime (d));
}

/*
 ********************************************************************************
 *********************** Time::IsDaylightSavingsTime ****************************
 ********************************************************************************
 */
bool    Time::IsDaylightSavingsTime (const DateTime& d)
{
    struct  tm  asTM    =   d.As<struct tm> ();
    asTM.tm_isdst = -1; // force calc of correct daylight savings time flag
    // THINK this is true - not totally clear - docs on mktime () don't specify unambiguously that this should work...
    // So far it seems too however, --LGP 2011-10-15
    time_t  result  =   mktime (&asTM);
    return asTM.tm_isdst >= 1;
}

/*
 ********************************************************************************
 ********************* Time::GetLocaltimeToGMTOffset ****************************
 ********************************************************************************
 */
time_t  Time::GetLocaltimeToGMTOffset (bool applyDST)
{
#if     0
    // WRONG - but COULD use this API - but not sure needed
#if     qPlatform_Windows
    TIME_ZONE_INFORMATION   tzInfo;
    memset (&tzInfo, 0, sizeof (tzInfo));
    (void)::GetTimeZoneInformation (&tzInfo);
    int unsignedBias    =   abs (tzInfo.Bias);
    int hrs =   unsignedBias / 60;
    int mins = unsignedBias - hrs * 60;
    tzBiasString = ::Format (L"%s%.2d:%.2d", (tzInfo.Bias >= 0 ? L"-" : L"+"), hrs, mins);
#endif
#endif

    /*
     * COULD this be cached? It SHOULD be - but what about when the timezone changes? there maybe a better way to compute this using the
     * timezone global var???
     */
    struct tm tm;
    memset (&tm, 0, sizeof(tm));
    tm.tm_year = 70;
    tm.tm_mon = 0;      // Jan
    tm.tm_mday = 1;
    tm.tm_isdst = applyDST;
    time_t  result  =   mktime (&tm);
    return result;
}

time_t  Time::GetLocaltimeToGMTOffset (const DateTime& forTime)
{
    return GetLocaltimeToGMTOffset (IsDaylightSavingsTime (forTime));
}<commit_msg>attempt at better handling missing /etc/timezone file on posix systems<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#include    <cstdlib>
#include    <cstring>
#include    <ctime>

#if     qPlatform_POSIX
#include    <time.h>
#endif

#include    "../Configuration/Common.h"
#include    "../Characters/String.h"
#include    "../Characters/String_Constant.h"
#include    "../Containers/Mapping.h"
#include    "../Debug/Assertions.h"
#include    "../Debug/Trace.h"
#include    "DateTime.h"
#include    "../Execution/ProcessRunner.h"
#include    "../IO/FileSystem/BinaryFileInputStream.h"
#include    "../Streams/TextInputStreamBinaryAdapter.h"

#include    "Timezone.h"

using   namespace   Stroika;
using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Characters;
using   namespace   Stroika::Foundation::Time;

/*
 ********************************************************************************
 ***************************** Time::GetTimezoneInfo ****************************
 ********************************************************************************
 */
TimeZoneInformationType    Time::GetTimezoneInfo ()
{
    TimeZoneInformationType result;
#if     qPlatform_POSIX
    try {
        result.fID = Streams::TextInputStreamBinaryAdapter (IO::FileSystem::BinaryFileInputStream::mk (String_Constant (L"/etc/timezone"))).ReadAll ().Trim ();
    }
    catch (...) {
        DbgTrace ("Ignoring missing ID from /etc/timezone");
    }
    if (result.fID.empty ()) {
        try {
            result.fID = Execution::ProcessRunner (L"date +%Z").Run (String ()).Trim ();
        }
        catch (...) {
            DbgTrace ("Ignoring missing ID from date +%Z");
        }
    }
    if (result.fID.empty ()) {
        // We could look to see if /etc/localtime is a symlink or a copy of any named file from /usr/share/zoneinfo, but
        // hope thats not needed!
    }
    // @see http://pubs.opengroup.org/onlinepubs/7908799/xsh/tzset.html
    result.fStandardTime.fName = String::FromSDKString (tzname[0]);
    result.fDaylightSavingsTime.fName = String::FromSDKString (tzname[1]);
#elif   qPlatform_Windows
    using   Containers::Mapping;
    using   Common::KeyValuePair;
    static const    Mapping<String, String> kWinDoze2OlsonName_ =  {
        KeyValuePair<String, String> { L"Afghanistan Standard Time", L"Asia/Kabul" },
        KeyValuePair<String, String> { L"Alaskan Standard Time", L"America/Juneau" },
        KeyValuePair<String, String> { L"Arab Standard Time", L"Asia/Riyadh" },
        KeyValuePair<String, String> { L"Arabian Standard Time", L"Asia/Muscat" },
        KeyValuePair<String, String> { L"Arabic Standard Time", L"Asia/Baghdad" },
        KeyValuePair<String, String> { L"Argentina Standard Time", L"America/Rosario" },
        KeyValuePair<String, String> { L"Atlantic Standard Time", L"America/Halifax" },
        KeyValuePair<String, String> { L"AUS Central Standard Time", L"Australia/Darwin" },
        KeyValuePair<String, String> { L"AUS Eastern Standard Time", L"Australia/Sydney" },
        KeyValuePair<String, String> { L"Azerbaijan Standard Time", L"Asia/Baku" },
        KeyValuePair<String, String> { L"Azores Standard Time", L"Atlantic/Azores" },
        KeyValuePair<String, String> { L"Bahia Standard Time", L"America/Maceio" },
        KeyValuePair<String, String> { L"Bangladesh Standard Time", L"Asia/Dhaka" },
        KeyValuePair<String, String> { L"Canada Central Standard Time", L"America/Swift_Current" },
        KeyValuePair<String, String> { L"Cape Verde Standard Time", L"Atlantic/Cape_Verde" },
        KeyValuePair<String, String> { L"Caucasus Standard Time", L"Asia/Yerevan" },
        KeyValuePair<String, String> { L"Cen. Australia Standard Time", L"Australia/Adelaide" },
        KeyValuePair<String, String> { L"Central America Standard Time", L"America/Tegucigalpa" },
        KeyValuePair<String, String> { L"Central Asia Standard Time", L"Asia/Almaty" },
        KeyValuePair<String, String> { L"Central Brazilian Standard Time", L"America/Cuiaba" },
        KeyValuePair<String, String> { L"Central Europe Standard Time", L"Europe/Prague" },
        KeyValuePair<String, String> { L"Central European Standard Time", L"Europe/Skopje" },
        KeyValuePair<String, String> { L"Central Pacific Standard Time", L"Pacific/Guadalcanal" },
        KeyValuePair<String, String> { L"Central Standard Time", L"America/Chicago" },
        KeyValuePair<String, String> { L"Central Standard Time (Mexico)", L"America/Monterrey" },
        KeyValuePair<String, String> { L"China Standard Time", L"Asia/Urumqi" },
        KeyValuePair<String, String> { L"E. Africa Standard Time", L"Africa/Nairobi" },
        KeyValuePair<String, String> { L"E. Australia Standard Time", L"Australia/Brisbane" },
        KeyValuePair<String, String> { L"E. Europe Standard Time", L"Europe/Bucharest" },
        KeyValuePair<String, String> { L"E. South America Standard Time", L"America/Sao_Paulo" },
        KeyValuePair<String, String> { L"Eastern Standard Time", L"America/New_York" },
        KeyValuePair<String, String> { L"Egypt Standard Time", L"Africa/Cairo" },
        KeyValuePair<String, String> { L"Ekaterinburg Standard Time", L"Asia/Yekaterinburg" },
        KeyValuePair<String, String> { L"Fiji Standard Time", L"Pacific/Fiji" },
        KeyValuePair<String, String> { L"FLE Standard Time", L"Europe/Helsinki" },
        KeyValuePair<String, String> { L"Georgian Standard Time", L"Asia/Tbilisi" },
        KeyValuePair<String, String> { L"GMT Standard Time", L"Europe/London" },
        KeyValuePair<String, String> { L"Greenland Standard Time", L"America/Godthab" },
        KeyValuePair<String, String> { L"Greenwich Standard Time", L"Atlantic/Reykjavik" },
        KeyValuePair<String, String> { L"GTB Standard Time", L"Europe/Bucharest" },
        KeyValuePair<String, String> { L"Hawaiian Standard Time", L"Pacific/Honolulu" },
        KeyValuePair<String, String> { L"India Standard Time", L"Asia/Calcutta" },
        KeyValuePair<String, String> { L"Iran Standard Time", L"Asia/Tehran" },
        KeyValuePair<String, String> { L"Jerusalem Standard Time", L"Asia/Jerusalem" },
        KeyValuePair<String, String> { L"Jordan Standard Time", L"Asia/Amman" },
        KeyValuePair<String, String> { L"Kaliningrad Standard Time", L"Europe/Kaliningrad" },
        KeyValuePair<String, String> { L"Korea Standard Time", L"Asia/Seoul" },
        KeyValuePair<String, String> { L"Libya Standard Time", L"Africa/Tripoli" },
        KeyValuePair<String, String> { L"Magadan Standard Time", L"Asia/Magadan" },
        KeyValuePair<String, String> { L"Mauritius Standard Time", L"Indian/Mauritius" },
        KeyValuePair<String, String> { L"Middle East Standard Time", L"Asia/Beirut" },
        KeyValuePair<String, String> { L"Montevideo Standard Time", L"America/Montevideo" },
        KeyValuePair<String, String> { L"Morocco Standard Time", L"Africa/Casablanca" },
        KeyValuePair<String, String> { L"Mountain Standard Time", L"America/Denver" },
        KeyValuePair<String, String> { L"Mountain Standard Time (Mexico)", L"America/Mazatlan" },
        KeyValuePair<String, String> { L"Myanmar Standard Time", L"Asia/Rangoon" },
        KeyValuePair<String, String> { L"N. Central Asia Standard Time", L"Asia/Novosibirsk" },
        KeyValuePair<String, String> { L"Namibia Standard Time", L"Africa/Windhoek" },
        KeyValuePair<String, String> { L"Nepal Standard Time", L"Asia/Katmandu" },
        KeyValuePair<String, String> { L"New Zealand Standard Time", L"Pacific/Auckland" },
        KeyValuePair<String, String> { L"Newfoundland Standard Time", L"America/St_Johns" },
        KeyValuePair<String, String> { L"North Asia East Standard Time", L"Asia/Irkutsk" },
        KeyValuePair<String, String> { L"North Asia Standard Time", L"Asia/Krasnoyarsk" },
        KeyValuePair<String, String> { L"Pacific SA Standard Time", L"America/Santiago" },
        KeyValuePair<String, String> { L"Pacific Standard Time", L"America/Los_Angeles" },
        KeyValuePair<String, String> { L"Pacific Standard Time (Mexico)", L"America/Tijuana" },
        KeyValuePair<String, String> { L"Pakistan Standard Time", L"Asia/Karachi" },
        KeyValuePair<String, String> { L"Paraguay Standard Time", L"America/Asuncion" },
        KeyValuePair<String, String> { L"Romance Standard Time", L"Europe/Paris" },
        KeyValuePair<String, String> { L"Russian Standard Time", L"Europe/Moscow" },
        KeyValuePair<String, String> { L"SA Eastern Standard Time", L"America/Cayenne" },
        KeyValuePair<String, String> { L"SA Pacific Standard Time", L"America/Lima" },
        KeyValuePair<String, String> { L"SA Western Standard Time", L"America/La_Paz" },
        KeyValuePair<String, String> { L"SE Asia Standard Time", L"Asia/Jakarta" },
        KeyValuePair<String, String> { L"Malay Peninsula Standard Time", L"Asia/Singapore" },
        KeyValuePair<String, String> { L"South Africa Standard Time", L"Africa/Harare" },
        KeyValuePair<String, String> { L"Syria Standard Time", L"Asia/Damascus" },
        KeyValuePair<String, String> { L"Taipei Standard Time", L"Asia/Taipei" },
        KeyValuePair<String, String> { L"Tasmania Standard Time", L"Australia/Hobart" },
        KeyValuePair<String, String> { L"Tokyo Standard Time", L"Asia/Tokyo" },
        KeyValuePair<String, String> { L"Tonga Standard Time", L"Pacific/Tongatapu" },
        KeyValuePair<String, String> { L"Turkey Standard Time", L"Asia/Istanbul" },
        KeyValuePair<String, String> { L"Ulaanbaatar Standard Time", L"Asia/Ulaanbaatar" },
        KeyValuePair<String, String> { L"US Eastern Standard Time", L"America/Indianapolis" },
        KeyValuePair<String, String> { L"US Mountain Standard Time", L"America/Denver" },
        KeyValuePair<String, String> { L"Venezuela Standard Time", L"America/Caracas" },
        KeyValuePair<String, String> { L"Vladivostok Standard Time", L"Asia/Vladivostok" },
        KeyValuePair<String, String> { L"W. Australia Standard Time", L"Australia/Perth" },
        KeyValuePair<String, String> { L"W. Central Africa Standard Time", L"Africa/Brazzaville" },
        KeyValuePair<String, String> { L"W. Europe Standard Time", L"Europe/Vienna" },
        KeyValuePair<String, String> { L"West Asia Standard Time", L"Asia/Tashkent" },
        KeyValuePair<String, String> { L"West Pacific Standard Time", L"Pacific/Port_Moresby" },
        KeyValuePair<String, String> { L"Yakutsk Standard Time", L"Asia/Yakutsk" }
    };
    TIME_ZONE_INFORMATION   tzInfo;
    memset (&tzInfo, 0, sizeof (tzInfo));
    (void)::GetTimeZoneInformation (&tzInfo);
    result.fStandardTime.fName = tzInfo.StandardName;
    result.fDaylightSavingsTime.fName = tzInfo.DaylightName;
    result.fID = kWinDoze2OlsonName_.LookupValue (tzInfo.StandardName, tzInfo.StandardName);
#else
    AssertNotImplemented ();
    return String ();
#endif
    return result;
}

/*
 ********************************************************************************
 ********************************* Time::GetTimezone ****************************
 ********************************************************************************
 */
String    Time::GetTimezone ()
{
    return GetTimezone (DateTime::Now ());
}

String    Time::GetTimezone (bool applyDST)
{
#if     qPlatform_Windows
    TIME_ZONE_INFORMATION   tzInfo;
    memset (&tzInfo, 0, sizeof (tzInfo));
    (void)::GetTimeZoneInformation (&tzInfo);
    return tzInfo.StandardName;
#elif   qPlatform_POSIX
    // @see http://pubs.opengroup.org/onlinepubs/7908799/xsh/tzset.html
    return String::FromSDKString (IsDaylightSavingsTime (DateTime::Now ()) ? tzname[1] : tzname[0]);
#else
    AssertNotImplemented ();
    return String ();
#endif
}

String    Time::GetTimezone (const DateTime& d)
{
    return GetTimezone (IsDaylightSavingsTime (d));
}

/*
 ********************************************************************************
 *********************** Time::IsDaylightSavingsTime ****************************
 ********************************************************************************
 */
bool    Time::IsDaylightSavingsTime (const DateTime& d)
{
    struct  tm  asTM    =   d.As<struct tm> ();
    asTM.tm_isdst = -1; // force calc of correct daylight savings time flag
    // THINK this is true - not totally clear - docs on mktime () don't specify unambiguously that this should work...
    // So far it seems too however, --LGP 2011-10-15
    time_t  result  =   mktime (&asTM);
    return asTM.tm_isdst >= 1;
}

/*
 ********************************************************************************
 ********************* Time::GetLocaltimeToGMTOffset ****************************
 ********************************************************************************
 */
time_t  Time::GetLocaltimeToGMTOffset (bool applyDST)
{
#if     0
    // WRONG - but COULD use this API - but not sure needed
#if     qPlatform_Windows
    TIME_ZONE_INFORMATION   tzInfo;
    memset (&tzInfo, 0, sizeof (tzInfo));
    (void)::GetTimeZoneInformation (&tzInfo);
    int unsignedBias    =   abs (tzInfo.Bias);
    int hrs =   unsignedBias / 60;
    int mins = unsignedBias - hrs * 60;
    tzBiasString = ::Format (L"%s%.2d:%.2d", (tzInfo.Bias >= 0 ? L"-" : L"+"), hrs, mins);
#endif
#endif

    /*
     * COULD this be cached? It SHOULD be - but what about when the timezone changes? there maybe a better way to compute this using the
     * timezone global var???
     */
    struct tm tm;
    memset (&tm, 0, sizeof(tm));
    tm.tm_year = 70;
    tm.tm_mon = 0;      // Jan
    tm.tm_mday = 1;
    tm.tm_isdst = applyDST;
    time_t  result  =   mktime (&tm);
    return result;
}

time_t  Time::GetLocaltimeToGMTOffset (const DateTime& forTime)
{
    return GetLocaltimeToGMTOffset (IsDaylightSavingsTime (forTime));
}<|endoftext|>


<commit_before>/*******************************************************************************/
/* Bela Csound Rendering functions                                             */
/*                                                                             */
/*******************************************************************************/

#include <Bela.h>
#include <Midi.h>
#include <csound/csound.hpp>
#include <vector>
#include <sstream>

static int OpenMidiInDevice(CSOUND *csound, void **userData, const char *dev);
static int CloseMidiInDevice(CSOUND *csound, void *userData);
static int ReadMidiData(CSOUND *csound, void *userData, unsigned char *mbuf,
			int nbytes);

struct csChan {
  std::vector<MYFLT> data;
  std::stringstream name;
};

struct csData{
  Csound *csound;
  int blocksize;
  int res;
  int count;
  std::vector<csChan> channel;
};

struct csMIDI {
  Midi midi;
};

csData* gCsData;

bool setup(BelaContext *context, void *userData)
{
  Csound *csound = new Csound();
  const char *csdfile = "my.csd"; /* CSD name */
  const char *midiDev = "-Mhw:1,0,0"; /* MIDI device */
  int numArgs = 8;
  const char *args[] = { "csound", csdfile, "-iadc", "-odac", "-+rtaudio=null",
		   "--realtime", "--daemon", midiDev};

  gCsData  = new csData;
  csound->SetHostImplementedAudioIO(1,0);
  csound->SetHostImplementedMIDIIO(1);
  csound->SetExternalMidiInOpenCallback(OpenMidiInDevice);
  csound->SetExternalMidiReadCallback(ReadMidiData);
  csound->SetExternalMidiInCloseCallback(CloseMidiInDevice);
  gCsData->res = csound->Compile(numArgs, args);
  gCsData->csound = csound;
  gCsData->blocksize =
    csound->GetKsmps()*csound->GetNchnls();
  gCsData->count = 0;

  /* set up the channels */
  gCsData->channel.resize(context->analogInChannels);
  for(int i; i < context->analogInChannels; i++) {
    gCsData->channel[i].data.resize(csound->GetKsmps());
    gCsData->channel[i].name << "analogue" << i+1;
  }

  if(gCsData->res != 0) return false;
  else return true;
}

void render(BelaContext *context, void *Data)
{
  csData *userData = gCsData;
  if(gCsData->res == 0) {
    int n,i,k,count, frmcount,blocksize,res;
    Csound *csound = userData->csound;
    MYFLT scal = csound->Get0dBFS();
    MYFLT* audioIn = csound->GetSpin();
    MYFLT* audioOut = csound->GetSpout();
    int nchnls = csound->GetNchnls();
    int chns = nchnls;
    int an_chns = context->analogInChannels;
    csChan *channel = &(userData->channel[0]);
    float frm = 0, incr = ((float) context->analogFrames)/context->audioFrames;
    int an_chans = context->analogInChannels;
    count = userData->count;
    blocksize = userData->blocksize;

    /* this is called when Csound is not running */
    if(count < 0) {
      for(n = 0; n < context->audioFrames; n++){
	for(i = 0; i < context->audioOutChannels; i++){
	  audioWrite(context,n,i,0);
	}
      }
      return;
    }

    if(chns > context->audioOutChannels)
      chns = context->audioOutChannels;

    /* this is where Csound is called */
    for(n = 0; n < context->audioFrames; n++, frm+=incr, count+=nchnls){
      if(count == blocksize) {
	/* set the channels */
	for(i = 0; i < an_chns; i++) {
          csound->SetChannel(channel[i].name.str().c_str(),
			     &(channel[i].data[0]));
	}
	/* run csound */
	if((res = csound->PerformKsmps()) == 0) count = 0;
	else {
	  count = -1;
	  break;
	}
      }
      /* read/write audio data */
      for(i = 0; i < chns; i++){
	audioIn[count+i] = audioRead(context,n,i);
	audioWrite(context,n,i,audioOut[count+i]/scal);
      }

      /* read analogue data
         analogue frame pos gets incremented according to the
         ratio analogFrames/audioFrames.
      */
      frmcount = count/nchnls;
      for(i = 0; i < an_chns; i++) {
	k = (int) frm;
        channel[i].data[frmcount] = analogRead(context,k,i);
      }
    }
    gCsData->res = res;
    userData->count = count;
  }
}

void cleanup(BelaContext *context, void *Data)
{
  csData *userData = gCsData;
  delete userData->csound;
  delete userData;
}

/** MIDI Input functions
 */
int OpenMidiInDevice(CSOUND *csound, void **userData, const char *dev) {
  csMIDI *midiData = new CsMIDI;
  Midi &midi = midiData->midi;
  midi.readFrom(dev);
  midi.enableParser(false);
  *userData = (void *) midiData;
}

int CloseMidiInDevice(CSOUND *csound, void *userData) {
  csMIDI *midiData = (csMIDI *) userData;
  delete midiData;
}

int ReadMidiData(CSOUND *csound, void *userData,
		 unsigned char *mbuf, int nbytes) {
  int n = 0;
  csMIDI *midiData = (csMIDI *) userData;
  Midi &midi = midiData->midi;

  while((byte = midi.getInput()) >= 0) {
    *mbuf++ = (unsigned char) byte;
    if(++n == nbytes) break;
  }

  return n;
}
<commit_msg>csdata on stack]<commit_after>/*******************************************************************************/
/* Bela Csound Rendering functions                                             */
/*                                                                             */
/*******************************************************************************/

#include <Bela.h>
#include <Midi.h>
#include <csound/csound.hpp>
#include <vector>
#include <sstream>

static int OpenMidiInDevice(CSOUND *csound, void **userData, const char *dev);
static int CloseMidiInDevice(CSOUND *csound, void *userData);
static int ReadMidiData(CSOUND *csound, void *userData, unsigned char *mbuf,
			int nbytes);

struct csChan {
  std::vector<MYFLT> data;
  std::stringstream name;
};

struct csData{
  Csound *csound;
  int blocksize;
  int res;
  int count;
  std::vector<csChan> channel;
};

struct csMIDI {
  Midi midi;
};

csData gCsData;

bool setup(BelaContext *context, void *userData)
{
  Csound *csound = new Csound();
  const char *csdfile = "my.csd"; /* CSD name */
  const char *midiDev = "-Mhw:1,0,0"; /* MIDI device */
  int numArgs = 8;
  const char *args[] = { "csound", csdfile, "-iadc", "-odac", "-+rtaudio=null",
		   "--realtime", "--daemon", midiDev};

  csound->SetHostImplementedAudioIO(1,0);
  csound->SetHostImplementedMIDIIO(1);
  csound->SetExternalMidiInOpenCallback(OpenMidiInDevice);
  csound->SetExternalMidiReadCallback(ReadMidiData);
  csound->SetExternalMidiInCloseCallback(CloseMidiInDevice);
  gCsData.res = csound->Compile(numArgs, args);
  gCsData.csound = csound;
  gCsData.blocksize =
    csound->GetKsmps()*csound->GetNchnls();
  gCsData.count = 0;

  /* set up the channels */
  gCsData.channel.resize(context->analogInChannels);
  for(int i; i < context->analogInChannels; i++) {
    gCsData.channel[i].data.resize(csound->GetKsmps());
    gCsData.channel[i].name << "analogue" << i+1;
  }

  if(gCsData.res != 0) return false;
  else return true;
}

void render(BelaContext *context, void *Data)
{
  if(gCsData.res == 0) {
    int n,i,k,count, frmcount,blocksize,res;
    Csound *csound = gCsData.csound;
    MYFLT scal = csound->Get0dBFS();
    MYFLT* audioIn = csound->GetSpin();
    MYFLT* audioOut = csound->GetSpout();
    int nchnls = csound->GetNchnls();
    int chns = nchnls;
    int an_chns = context->analogInChannels;
    csChan *channel = &(gCsData.channel[0]);
    float frm = 0, incr = ((float) context->analogFrames)/context->audioFrames;
    int an_chans = context->analogInChannels;
    count = gCsData.count;
    blocksize = gCsData.blocksize;

    /* this is called when Csound is not running */
    if(count < 0) {
      for(n = 0; n < context->audioFrames; n++){
	for(i = 0; i < context->audioOutChannels; i++){
	  audioWrite(context,n,i,0);
	}
      }
      return;
    }

    if(chns > context->audioOutChannels)
      chns = context->audioOutChannels;

    /* this is where Csound is called */
    for(n = 0; n < context->audioFrames; n++, frm+=incr, count+=nchnls){
      if(count == blocksize) {
	/* set the channels */
	for(i = 0; i < an_chns; i++) {
          csound->SetChannel(channel[i].name.str().c_str(),
			     &(channel[i].data[0]));
	}
	/* run csound */
	if((res = csound->PerformKsmps()) == 0) count = 0;
	else {
	  count = -1;
	  break;
	}
      }
      /* read/write audio data */
      for(i = 0; i < chns; i++){
	audioIn[count+i] = audioRead(context,n,i);
	audioWrite(context,n,i,audioOut[count+i]/scal);
      }

      /* read analogue data
         analogue frame pos gets incremented according to the
         ratio analogFrames/audioFrames.
      */
      frmcount = count/nchnls;
      for(i = 0; i < an_chns; i++) {
	k = (int) frm;
        channel[i].data[frmcount] = analogRead(context,k,i);
      }
    }
    gCsData.res = res;
    gCsData.count = count;
  }
}

void cleanup(BelaContext *context, void *Data)
{
  delete gCsData.csound;
}

/** MIDI Input functions
 */
int OpenMidiInDevice(CSOUND *csound, void **userData, const char *dev) {
  csMIDI *midiData = new csMIDI;
  Midi &midi = midiData->midi;
  midi.readFrom(dev);
  midi.enableParser(false);
  *userData = (void *) midiData;
}

int CloseMidiInDevice(CSOUND *csound, void *userData) {
  csMIDI *midiData = (csMIDI *) userData;
  delete midiData;
}

int ReadMidiData(CSOUND *csound, void *userData,
		 unsigned char *mbuf, int nbytes) {
  int n = 0;
  csMIDI *midiData = (csMIDI *) userData;
  Midi &midi = midiData->midi;

  while((byte = midi.getInput()) >= 0) {
    *mbuf++ = (unsigned char) byte;
    if(++n == nbytes) break;
  }

  return n;
}
<|endoftext|>


<commit_before>// Fill out your copyright notice in the Description page of Project Settings.

#include "MeshGenerator.h"
#include "MeshImporter.h"

MeshImporter::MeshImporter(const char* path)
{
	ReadFile(path);
}

MeshImporter::~MeshImporter()
{
}

void MeshImporter::ReadFile(const char* filename)
{
	Assimp::Importer importer;

	importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,
		aiComponent_TANGENTS_AND_BITANGENTS |
		aiComponent_MATERIALS |
		aiComponent_BONEWEIGHTS |
		aiComponent_ANIMATIONS |
		aiComponent_LIGHTS |
		aiComponent_CAMERAS |
		aiComponent_TEXTURES |
		aiComponent_TEXCOORDS
	);

#define max_Quality_Preset ( \
	aiProcess_CalcTangentSpace				|  \
	aiProcess_GenSmoothNormals				|  \
	aiProcess_JoinIdenticalVertices			|  \
	aiProcess_ImproveCacheLocality			|  \
	aiProcess_LimitBoneWeights				|  \
	aiProcess_RemoveRedundantMaterials      |  \
	aiProcess_SplitLargeMeshes				|  \
	aiProcess_Triangulate					|  \
	aiProcess_GenUVCoords                   |  \
	aiProcess_SortByPType                   |  \
	aiProcess_FindDegenerates               |  \
	aiProcess_FindInvalidData               |  \
	aiProcess_FindInstances                 |  \
	aiProcess_ValidateDataStructure         |  \
	aiProcess_OptimizeMeshes                |  \
	aiProcess_OptimizeGraph					|  \
	0 )

#define molecule_Preset ( \
	aiProcess_RemoveComponent				|  \
	aiProcess_GenSmoothNormals				|  \
	aiProcess_Triangulate					|  \
	aiProcess_JoinIdenticalVertices			|  \
	aiProcess_OptimizeMeshes                |  \
	0 )

	// TODO revert last two presets to gather color
	const aiScene* scene = importer.ReadFile(filename, molecule_Preset);
	int face_index = 0;

	for (unsigned int m = 0; m < scene->mNumMeshes; ++m) {
		const struct aiMesh* mesh = scene->mMeshes[m];

		for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
			aiVector3D vertex = mesh->mVertices[i];
			vertices_.push_back(vertex.x);
			vertices_.push_back(vertex.y);
			vertices_.push_back(vertex.z);

			aiColor4t<float> color = mesh->mColors[0][i];
			colors_.push_back((uint32_t)color.r * 100);
			colors_.push_back((uint32_t)color.g * 100);
			colors_.push_back((uint32_t)color.b * 100);
		}

		for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
			aiVector3D normal = mesh->mNormals[i];
			normals_.push_back(normal.x);
			normals_.push_back(normal.y);
			normals_.push_back(normal.z);
		}

		for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
			aiFace face = mesh->mFaces[i];
			for (int j = 0; j < 3; ++j) {
				faces_.push_back(face.mIndices[j] + face_index);
			}
		}

		face_index += mesh->mNumVertices;
	}
}

vector<float>& MeshImporter::GetVertices()
{
	return vertices_;
}

vector<float>& MeshImporter::GetNormals()
{
	return normals_;
}

vector<uint8_t>& MeshImporter::GetColors()
{
	return colors_;
}

vector<uint32_t>& MeshImporter::GetFaces()
{
	return faces_;
}

<commit_msg>fix colors<commit_after>// Fill out your copyright notice in the Description page of Project Settings.

#include "MeshGenerator.h"
#include "MeshImporter.h"

MeshImporter::MeshImporter(const char* path)
{
	ReadFile(path);
}

MeshImporter::~MeshImporter()
{
}

void MeshImporter::ReadFile(const char* filename)
{
	Assimp::Importer importer;

	importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,
		aiComponent_TANGENTS_AND_BITANGENTS |
		aiComponent_MATERIALS |
		aiComponent_BONEWEIGHTS |
		aiComponent_ANIMATIONS |
		aiComponent_LIGHTS |
		aiComponent_CAMERAS |
		aiComponent_TEXTURES |
		aiComponent_TEXCOORDS
	);

#define max_Quality_Preset ( \
	aiProcess_CalcTangentSpace				|  \
	aiProcess_GenSmoothNormals				|  \
	aiProcess_JoinIdenticalVertices			|  \
	aiProcess_ImproveCacheLocality			|  \
	aiProcess_LimitBoneWeights				|  \
	aiProcess_RemoveRedundantMaterials      |  \
	aiProcess_SplitLargeMeshes				|  \
	aiProcess_Triangulate					|  \
	aiProcess_GenUVCoords                   |  \
	aiProcess_SortByPType                   |  \
	aiProcess_FindDegenerates               |  \
	aiProcess_FindInvalidData               |  \
	aiProcess_FindInstances                 |  \
	aiProcess_ValidateDataStructure         |  \
	aiProcess_OptimizeMeshes                |  \
	aiProcess_OptimizeGraph					|  \
	0 )

#define molecule_Preset ( \
	aiProcess_RemoveComponent				|  \
	aiProcess_GenSmoothNormals				|  \
	aiProcess_Triangulate					|  \
	aiProcess_JoinIdenticalVertices			|  \
	aiProcess_OptimizeMeshes                |  \
	aiProcess_OptimizeGraph					|  \
	0 )

	// TODO revert last two presets to gather color
	const aiScene* scene = importer.ReadFile(filename, molecule_Preset);
	int face_index = 0;

	for (unsigned int m = 0; m < scene->mNumMeshes; ++m) {
		const struct aiMesh* mesh = scene->mMeshes[m];

		for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
			aiVector3D vertex = mesh->mVertices[i];
			vertices_.push_back(vertex.x);
			vertices_.push_back(vertex.y);
			vertices_.push_back(vertex.z);

			aiColor4t<float> color = mesh->mColors[0][i];
			colors_.push_back((int)(color.r * 255));
			colors_.push_back((int)(color.g * 255));
			colors_.push_back((int)(color.b * 255));
		}

		for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
			aiVector3D normal = mesh->mNormals[i];
			normals_.push_back(normal.x);
			normals_.push_back(normal.y);
			normals_.push_back(normal.z);
		}

		for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
			aiFace face = mesh->mFaces[i];
			for (int j = 0; j < 3; ++j) {
				faces_.push_back(face.mIndices[j] + face_index);
			}
		}

		face_index += mesh->mNumVertices;
	}
}

vector<float>& MeshImporter::GetVertices()
{
	return vertices_;
}

vector<float>& MeshImporter::GetNormals()
{
	return normals_;
}

vector<uint8_t>& MeshImporter::GetColors()
{
	return colors_;
}

vector<uint32_t>& MeshImporter::GetFaces()
{
	return faces_;
}

<|endoftext|>


<commit_before>/*******************************************************************************/
/* Bela Csound Rendering functions                                             */
/*                                                                           */
/*******************************************************************************/

#include <Bela.h>
#include <csound/csound.hpp>
#include <vector>
#include <sstream>

struct csChan {
  std::vector<MYFLT> data;
  std::stringstream name;
};

struct csData{
  Csound *csound;
  int blocksize;
  int res;
  int count;
  csChan channel[8];
};

csData* gCsData;

bool setup(BelaContext *context, void *userData)
{
  Csound *csound = new Csound();
  const char *csdfile = "my.csd"; /* CSD name */
  int numArgs = 6;
  char *args[] = { "csound", csdfile, "-iadc", "-odac","-+rtaudio=null",
		   "--realtime", "--daemon"};

  gCsData  = new csData;
  csound->SetHostImplementedAudioIO(1,0);
  gCsData->res = csound->Compile(numArgs, args);
  gCsData->csound = csound;
  gCsData->blocksize =
    csound->GetKsmps()*userData->csound->GetNchnls();
  gCsData->count = 0;

  /* set up the channels */
  for(int i; i < context->analogInChannels; i++) {
    gCsData.channel[i].data.resize(csound->GetKsmps());
    gCsData.channel[i].name << "analogue" << i+1;
  }

  if(gCsData->res != 0) return false;
  else return true;
}

void render(BelaContext *context, void *Data)
{
  csData *userData = gCsData;
  if(gCsData->res == 0) {
    int n,i,k,count, frmcount,blocksize,res;
    MYFLT scal = userData->csound->Get0dBFS();
    MYFLT* audioIn = userData->csound->GetSpin();
    MYFLT* audioOut = userData->csound->GetSpout();
    int nchnls = userData->csound->GetNchnls();
    int chns = nchnls;
    int an_chns = context->analogInChannels;
    CsChan *channel = userData->channel;
    float frm = 0, incr = ((float) context->analogFrames)/context->audioFrames;
    int an_chans = context->analogInChannels;
    count = userData->count;
    blocksize = userData->blocksize;

    /* this is called when Csound is not running */
    if(count < 0) {
      for(n = 0; n < context->audioFrames; n++){
	for(i = 0; i < context->audioOutChannels; i++){
	  audioWrite(context,n,i,0);
	}
      }
      return;
    }

    if(chns > context->audioOutChannels)
      chns = context->audioOutChannels;

    /* this is where Csound is called */
    for(n = 0; n < context->audioFrames; n++, frm+=incr, count+=nchnls){
      if(count == blocksize) {
	/* set the channels */
	for(i = 0; i < an_chns; i++) {
          csound->SetChannel(channel[i].name.str().c_str(),
			     &(channel[i].data[0]));
	}
	if((res = userData->csound->PerformKsmps()) == 0) count = 0;
	else {
	  count = -1;
	  break;
	}
      }
      /* read/write audio data */
      for(i = 0; i < chns; i++){
	audioIn[count+i] = audioRead(context,n,i);
	audioWrite(context,n,i,audioOut[count+i]/scal);
      }

      /* read analogue data
         analogue frame pos gets incremented according to the
         ratio analogFrames/audioFrames.
      */
      frmcount = count/nchnls;
      for(i = 0; i < an_chns; i++) {
	k = (int) frm;
        channel[i].data[frmcount] = analogRead(context,k,i);
      }

    }
    gCsData->res = res;
    userData->count = count;
  }
}

void cleanup(BelaContext *context, void *Data)
{
  csData *userData = gCsData;
  delete userData->csound;
  delete userData;
}

<commit_msg>bela MIDI<commit_after>/*******************************************************************************/
/* Bela Csound Rendering functions                                             */
/*                                                                           */
/*******************************************************************************/

#include <Bela.h>
#include <csound/csound.hpp>
#include <vector>
#include <sstream>

static int OpenMidiInDevice(CSOUND *csound, void **userData, const char *dev);
static int CloseMidiInDevice(CSOUND *csound, void *userData);
static int ReadMidiData(CSOUND *csound, void *userData, unsigned char *mbuf,
			int nbytes);

struct csChan {
  std::vector<MYFLT> data;
  std::stringstream name;
};

struct csData{
  Csound *csound;
  int blocksize;
  int res;
  int count;
  csChan channel[8];
};

csData* gCsData;

bool setup(BelaContext *context, void *userData)
{
  Csound *csound = new Csound();
  const char *csdfile = "my.csd"; /* CSD name */
  int numArgs = 8;
  char *args[] = { "csound", csdfile, "-iadc", "-odac", "-+rtaudio=null",
		   "--realtime", "--daemon", "-Mhw:1,0,0"};

  gCsData  = new csData;
  csound->SetHostImplementedAudioIO(1,0);
  csound>SetHostImplementedMIDIIO(1);
  csound->SetExternalMidiInOpenCallback(OpenMidiInDevice);
  csound->SetExternalMidiReadCallback(ReadMidiData);
  csound->SetExternalMidiInCloseCallback(CloseMidiInDevice);
  gCsData->res = csound->Compile(numArgs, args);
  gCsData->csound = csound;
  gCsData->blocksize =
    csound->GetKsmps()*userData->csound->GetNchnls();
  gCsData->count = 0;

  /* set up the channels */
  for(int i; i < context->analogInChannels; i++) {
    gCsData.channel[i].data.resize(csound->GetKsmps());
    gCsData.channel[i].name << "analogue" << i+1;
  }

  if(gCsData->res != 0) return false;
  else return true;
}

void render(BelaContext *context, void *Data)
{
  csData *userData = gCsData;
  if(gCsData->res == 0) {
    int n,i,k,count, frmcount,blocksize,res;
    MYFLT scal = userData->csound->Get0dBFS();
    MYFLT* audioIn = userData->csound->GetSpin();
    MYFLT* audioOut = userData->csound->GetSpout();
    int nchnls = userData->csound->GetNchnls();
    int chns = nchnls;
    int an_chns = context->analogInChannels;
    CsChan *channel = userData->channel;
    float frm = 0, incr = ((float) context->analogFrames)/context->audioFrames;
    int an_chans = context->analogInChannels;
    count = userData->count;
    blocksize = userData->blocksize;

    /* this is called when Csound is not running */
    if(count < 0) {
      for(n = 0; n < context->audioFrames; n++){
	for(i = 0; i < context->audioOutChannels; i++){
	  audioWrite(context,n,i,0);
	}
      }
      return;
    }

    if(chns > context->audioOutChannels)
      chns = context->audioOutChannels;

    /* this is where Csound is called */
    for(n = 0; n < context->audioFrames; n++, frm+=incr, count+=nchnls){
      if(count == blocksize) {
	/* set the channels */
	for(i = 0; i < an_chns; i++) {
          csound->SetChannel(channel[i].name.str().c_str(),
			     &(channel[i].data[0]));
	}
	/* run csound */
	if((res = userData->csound->PerformKsmps()) == 0) count = 0;
	else {
	  count = -1;
	  break;
	}
      }
      /* read/write audio data */
      for(i = 0; i < chns; i++){
	audioIn[count+i] = audioRead(context,n,i);
	audioWrite(context,n,i,audioOut[count+i]/scal);
      }

      /* read analogue data
         analogue frame pos gets incremented according to the
         ratio analogFrames/audioFrames.
      */
      frmcount = count/nchnls;
      for(i = 0; i < an_chns; i++) {
	k = (int) frm;
        channel[i].data[frmcount] = analogRead(context,k,i);
      }
    }
    gCsData->res = res;
    userData->count = count;
  }
}

void cleanup(BelaContext *context, void *Data)
{
  csData *userData = gCsData;
  delete userData->csound;
  delete userData;
}

/** MIDI Input functions
 */
int OpenMidiInDevice(CSOUND *csound, void **userData, const char *dev) {
  CsMIDI *midiData = new CsMIDI;
  Midi &midi = midiData->midi;
  midi.readFrom(dev);
  midi.enableParser(false);
  *userData = (void *) midiData;
}

int CloseMidiInDevice(CSOUND *csound, void *userData) {
  CsMIDI *midiData = (CsMIDI *) userData;
  delete midiData;
}

int ReadMidiData(CSOUND *csound, void *userData,
                         unsigned char *mbuf, int nbytes) {
  int n = 0;
  CsMIDI *midiData = (CsMIDI *) userData;
  Midi &midi = midiData->midi;

  while((byte = midi.getInput()) > 0) {
    *mbuf++ = (unsigned char) byte;
    if(++n == nbytes) break;
  }

  return n;
}
<|endoftext|>


<commit_before>#include "pch.h"
#include "axl_sys_Time.h"
#include "axl_mt_CallOnce.h"

namespace axl {
namespace sys {

//.............................................................................

#if (_AXL_ENV == AXL_ENV_WIN)

static uint64_t g_qpcBaseTimestamp;
static uint64_t g_qpcBaseCounter;
static uint64_t g_qpcFrequency;

void
initQpc ()
{
	::GetSystemTimeAsFileTime ((FILETIME*) &g_qpcBaseTimestamp);
	::QueryPerformanceCounter ((LARGE_INTEGER*) &g_qpcBaseCounter);
	::QueryPerformanceFrequency ((LARGE_INTEGER*) &g_qpcFrequency);
}

#endif

uint64_t
getTimestamp ()
{
	uint64_t timestamp;

#if (_AXL_ENV == AXL_ENV_WIN)
	::GetSystemTimeAsFileTime ((FILETIME*) &timestamp);
#elif (_AXL_ENV == AXL_ENV_POSIX)
	timespec tspec;
#	if (_AXL_POSIX == AXL_POSIX_DARWIN)
	timeval tval;
	gettimeofday (&tval, NULL);
	tspec.tv_sec = tval.tv_sec;
	tspec.tv_nsec = tval.tv_usec * 1000;
#	else
	clock_gettime (CLOCK_REALTIME_COARSE, &tspec);
#	endif
	timestamp = (uint64_t) tspec.tv_sec * 10000000 + tspec.tv_nsec / 100;
#endif

	return timestamp;
}

uint64_t
getPreciseTimestamp ()
{
#if (_AXL_ENV == AXL_ENV_WIN)
	uint64_t counter;
	::QueryPerformanceCounter ((LARGE_INTEGER*) &counter);
	return g_qpcBaseTimestamp + (uint64_t) ((double) (counter - g_qpcBaseCounter) * 10000000 / g_qpcFrequency);
#elif (_AXL_ENV == AXL_ENV_POSIX)
	timespec tspec;
#	if (_AXL_POSIX == AXL_POSIX_DARWIN)
	timeval tval;
	gettimeofday (&tval, NULL);
	tspec.tv_sec = tval.tv_sec;
	tspec.tv_nsec = tval.tv_usec * 1000;
#	else
	clock_gettime (CLOCK_REALTIME, &tspec);
#	endif
	return (uint64_t) tspec.tv_sec * 10000000 + tspec.tv_nsec / 100;
#endif
}

//. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

void
sleep (uint32_t msCount)
{
#if (_AXL_ENV == AXL_ENV_WIN)
	::Sleep (msCount);
#else
	timespec timespec;
	getTimespecFromTimeout (msCount, &timespec);
	nanosleep (&timespec, NULL);
#endif
}

//.............................................................................

uint64_t
Time::getTimestampImpl (
	bool isLocal,
	int timeZone
	) const
{
	uint64_t timestamp = 0;

#if (_AXL_ENV == AXL_ENV_WIN)
	SYSTEMTIME sysTime = { 0 };
	sysTime.wYear   = m_year;
	sysTime.wMonth  = m_month + 1;
	sysTime.wDay    = m_monthDay;
	sysTime.wHour   = m_hour;
	sysTime.wMinute = m_minute;
	sysTime.wSecond = m_second;

	::SystemTimeToFileTime (&sysTime, (FILETIME*) &timestamp);

	if (isLocal)
		::FileTimeToLocalFileTime ((const FILETIME*) &timestamp, (FILETIME*) &timestamp);
	else
		timestamp += (int64_t) getTimeZoneOffsetInMinutes (timeZone) * 60 * 10000000;

#else
	tm tmStruct = { 0 };
	tmStruct.tm_year = m_year - 1900;
	tmStruct.tm_mon  = m_month;
	tmStruct.tm_mday = m_monthDay;
	tmStruct.tm_hour = m_hour;
	tmStruct.tm_min  = m_minute;
	tmStruct.tm_sec  = m_second;

	time_t posixTime = isLocal ?
		mktime (&tmStruct) :
		timegm (&tmStruct) + getTimeZoneOffsetInMinutes (timeZone) * 60;

	timestamp = (uint64_t) posixTime * 10000000;
#endif

	return
		timestamp +
		m_milliSecond * 10000 +
		m_microSecond * 10 +
		m_nanoSecond / 100;
}

void
Time::setTimestampImpl (
	uint64_t timestamp,
	bool isLocal,
	int timeZone
	)
{
#if (_AXL_ENV == AXL_ENV_WIN)
	SYSTEMTIME sysTime = { 0 };

	if (isLocal)
		::FileTimeToLocalFileTime ((const FILETIME*) &timestamp, (FILETIME*) &timestamp);
	else
		timestamp += (int64_t) getTimeZoneOffsetInMinutes (timeZone) * 60 * 10000000;

	::FileTimeToSystemTime ((const FILETIME*) &timestamp, &sysTime);

	m_year        = sysTime.wYear;
	m_month       = sysTime.wMonth - 1;
	m_monthDay    = sysTime.wDay;
	m_dayOfWeek   = sysTime.wDayOfWeek;
	m_hour        = sysTime.wHour;
	m_minute      = sysTime.wMinute;
	m_second      = sysTime.wSecond;

#else
	tm* tmStruct;

	time_t posixTime = timestamp / 10000000;

	if (isLocal)
	{
		tmStruct = localtime (&posixTime);
	}
	else
	{
		posixTime += getTimeZoneOffsetInMinutes (timeZone) * 60;
		tmStruct = gmtime (&posixTime);
	}

	m_year        = tmStruct->tm_year + 1900;
	m_month       = tmStruct->tm_mon;
	m_monthDay    = tmStruct->tm_mday;
	m_dayOfWeek   = tmStruct->tm_wday;
	m_hour        = tmStruct->tm_hour;
	m_minute      = tmStruct->tm_min;
	m_second      = tmStruct->tm_sec;
#endif

	m_milliSecond = (timestamp / 10000) % 1000;
	m_microSecond = (timestamp / 10) % 1000;
	m_nanoSecond  = (timestamp % 10) * 100;

}

/*
	%h	24-hour
	%H	12-hour
	%m	minute
	%s	second
	%l	millisecond
	%c	microsecond
	%p	p/a (lower-case pm/am)
	%P	P/A (upper-case PM/AM)
	%y	2-digit year
	%Y	4-digit year
	%D	day of month (leading zero if one-digit)
	%d	day of month (no leading-zero)
	%M	month number (leading zero if one-digit)
	%o	month number (no leading-zero)
	%n	month name (short)
	%N	month name (full)
	%w	day of week (short)
	%W	day of week (full)
*/

size_t
Time::format (
	sl::String* string,
	const char* formatString
	) const
{
	static const char* weekDayShortNameTable [7] =
	{
		"Sun",
		"Mon",
		"Tue",
		"Wed",
		"Thu",
		"Fri",
		"Sat",
	};

	static const char* weekDayFullNameTable [7] =
	{
		"Sunday",
		"Monday",
		"Tuesday",
		"Wednsday",
		"Thursday",
		"Friday",
		"Saturday",
	};

	static const char* monthShortNameTable [12] =
	{
		"Jan",
		"Feb",
		"Mar",
		"Apr",
		"May",
		"Jun",
		"Jul",
		"Aug",
		"Sep",
		"Oct",
		"Nov",
		"Dec",
	};

	static const char* monthFullNameTable [12] =
	{
		"January",
		"February",
		"March",
		"April",
		"May",
		"June",
		"July",
		"August",
		"September",
		"October",
		"November",
		"December",
	};

	string->clear ();

	const char* p = formatString;
	const char* p0 = p;

	for (; *p; p++)
	{
		if (*p != '%')
			continue;

		string->append (p0, p - p0);

		p++;
		if (!*p)
			return string->getLength ();

		int h12;

		switch (*p)
		{
		case 'h':
			string->appendFormat ("%02d", m_hour);
			break;

		case 'H':
			h12 = m_hour % 12;
			string->appendFormat ("%d", h12 ? h12 : 12);
			break;

		case 'm':
			string->appendFormat ("%02d", m_minute);
			break;

		case 's':
			string->appendFormat ("%02d", m_second);
			break;

		case 'l':
			string->appendFormat ("%03d", m_milliSecond);
			break;

		case 'c':
			string->appendFormat ("%03d", m_microSecond);
			break;

		case 'p':
			string->append (m_hour >= 12 ? 'p' : 'a');
			break;

		case 'P':
			string->append (m_hour >= 12 ? 'P' : 'A');
			break;

		case 'y':
			string->appendFormat ("%02d", m_year % 100);
			break;

		case 'Y':
			string->appendFormat ("%04d", m_year);
			break;

		case 'D':
			string->appendFormat ("%02d", m_monthDay);
			break;

		case 'd':
			string->appendFormat ("%d", m_monthDay);
			break;

		case 'M':
			string->appendFormat ("%02d", m_month);
			break;

		case 'o':
			string->appendFormat ("%d", m_month);
			break;

		case 'n':
			string->append (monthShortNameTable [m_month % 12]);
			break;

		case 'N':
			string->append (monthFullNameTable [m_month % 12]);
			break;

		case 'w':
			string->append (weekDayShortNameTable [m_dayOfWeek % 7]);
			break;

		case 'W':
			string->append (weekDayFullNameTable [m_dayOfWeek % 7]);
			break;

		default:
			string->append (*p);
		}

		p0 = p + 1;
	}

	string->append (p0, p - p0);
	return string->getLength ();
}

//.............................................................................

} // namespace sys
} // namespace axl
<commit_msg>[axl] use CLOCK_REALTIME_COARSE only if it's available (fallback to CLOCK_REALTIME otherwise)<commit_after>#include "pch.h"
#include "axl_sys_Time.h"
#include "axl_mt_CallOnce.h"

namespace axl {
namespace sys {

//.............................................................................

#if (_AXL_ENV == AXL_ENV_WIN)

static uint64_t g_qpcBaseTimestamp;
static uint64_t g_qpcBaseCounter;
static uint64_t g_qpcFrequency;

void
initQpc ()
{
	::GetSystemTimeAsFileTime ((FILETIME*) &g_qpcBaseTimestamp);
	::QueryPerformanceCounter ((LARGE_INTEGER*) &g_qpcBaseCounter);
	::QueryPerformanceFrequency ((LARGE_INTEGER*) &g_qpcFrequency);
}

#endif

uint64_t
getTimestamp ()
{
	uint64_t timestamp;

#if (_AXL_ENV == AXL_ENV_WIN)
	::GetSystemTimeAsFileTime ((FILETIME*) &timestamp);
#elif (_AXL_ENV == AXL_ENV_POSIX)
	timespec tspec;
#	if (_AXL_POSIX == AXL_POSIX_DARWIN)
	timeval tval;
	gettimeofday (&tval, NULL);
	tspec.tv_sec = tval.tv_sec;
	tspec.tv_nsec = tval.tv_usec * 1000;
#	elif (defined CLOCK_REALTIME_COARSE)
	clock_gettime (CLOCK_REALTIME_COARSE, &tspec);
#	else
	clock_gettime (CLOCK_REALTIME, &tspec);
#	endif
	timestamp = (uint64_t) tspec.tv_sec * 10000000 + tspec.tv_nsec / 100;
#endif

	return timestamp;
}

uint64_t
getPreciseTimestamp ()
{
#if (_AXL_ENV == AXL_ENV_WIN)
	uint64_t counter;
	::QueryPerformanceCounter ((LARGE_INTEGER*) &counter);
	return g_qpcBaseTimestamp + (uint64_t) ((double) (counter - g_qpcBaseCounter) * 10000000 / g_qpcFrequency);
#elif (_AXL_ENV == AXL_ENV_POSIX)
	timespec tspec;
#	if (_AXL_POSIX == AXL_POSIX_DARWIN)
	timeval tval;
	gettimeofday (&tval, NULL);
	tspec.tv_sec = tval.tv_sec;
	tspec.tv_nsec = tval.tv_usec * 1000;
#	else
	clock_gettime (CLOCK_REALTIME, &tspec);
#	endif
	return (uint64_t) tspec.tv_sec * 10000000 + tspec.tv_nsec / 100;
#endif
}

//. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

void
sleep (uint32_t msCount)
{
#if (_AXL_ENV == AXL_ENV_WIN)
	::Sleep (msCount);
#else
	timespec timespec;
	getTimespecFromTimeout (msCount, &timespec);
	nanosleep (&timespec, NULL);
#endif
}

//.............................................................................

uint64_t
Time::getTimestampImpl (
	bool isLocal,
	int timeZone
	) const
{
	uint64_t timestamp = 0;

#if (_AXL_ENV == AXL_ENV_WIN)
	SYSTEMTIME sysTime = { 0 };
	sysTime.wYear   = m_year;
	sysTime.wMonth  = m_month + 1;
	sysTime.wDay    = m_monthDay;
	sysTime.wHour   = m_hour;
	sysTime.wMinute = m_minute;
	sysTime.wSecond = m_second;

	::SystemTimeToFileTime (&sysTime, (FILETIME*) &timestamp);

	if (isLocal)
		::FileTimeToLocalFileTime ((const FILETIME*) &timestamp, (FILETIME*) &timestamp);
	else
		timestamp += (int64_t) getTimeZoneOffsetInMinutes (timeZone) * 60 * 10000000;

#else
	tm tmStruct = { 0 };
	tmStruct.tm_year = m_year - 1900;
	tmStruct.tm_mon  = m_month;
	tmStruct.tm_mday = m_monthDay;
	tmStruct.tm_hour = m_hour;
	tmStruct.tm_min  = m_minute;
	tmStruct.tm_sec  = m_second;

	time_t posixTime = isLocal ?
		mktime (&tmStruct) :
		timegm (&tmStruct) + getTimeZoneOffsetInMinutes (timeZone) * 60;

	timestamp = (uint64_t) posixTime * 10000000;
#endif

	return
		timestamp +
		m_milliSecond * 10000 +
		m_microSecond * 10 +
		m_nanoSecond / 100;
}

void
Time::setTimestampImpl (
	uint64_t timestamp,
	bool isLocal,
	int timeZone
	)
{
#if (_AXL_ENV == AXL_ENV_WIN)
	SYSTEMTIME sysTime = { 0 };

	if (isLocal)
		::FileTimeToLocalFileTime ((const FILETIME*) &timestamp, (FILETIME*) &timestamp);
	else
		timestamp += (int64_t) getTimeZoneOffsetInMinutes (timeZone) * 60 * 10000000;

	::FileTimeToSystemTime ((const FILETIME*) &timestamp, &sysTime);

	m_year        = sysTime.wYear;
	m_month       = sysTime.wMonth - 1;
	m_monthDay    = sysTime.wDay;
	m_dayOfWeek   = sysTime.wDayOfWeek;
	m_hour        = sysTime.wHour;
	m_minute      = sysTime.wMinute;
	m_second      = sysTime.wSecond;

#else
	tm* tmStruct;

	time_t posixTime = timestamp / 10000000;

	if (isLocal)
	{
		tmStruct = localtime (&posixTime);
	}
	else
	{
		posixTime += getTimeZoneOffsetInMinutes (timeZone) * 60;
		tmStruct = gmtime (&posixTime);
	}

	m_year        = tmStruct->tm_year + 1900;
	m_month       = tmStruct->tm_mon;
	m_monthDay    = tmStruct->tm_mday;
	m_dayOfWeek   = tmStruct->tm_wday;
	m_hour        = tmStruct->tm_hour;
	m_minute      = tmStruct->tm_min;
	m_second      = tmStruct->tm_sec;
#endif

	m_milliSecond = (timestamp / 10000) % 1000;
	m_microSecond = (timestamp / 10) % 1000;
	m_nanoSecond  = (timestamp % 10) * 100;

}

/*
	%h	24-hour
	%H	12-hour
	%m	minute
	%s	second
	%l	millisecond
	%c	microsecond
	%p	p/a (lower-case pm/am)
	%P	P/A (upper-case PM/AM)
	%y	2-digit year
	%Y	4-digit year
	%D	day of month (leading zero if one-digit)
	%d	day of month (no leading-zero)
	%M	month number (leading zero if one-digit)
	%o	month number (no leading-zero)
	%n	month name (short)
	%N	month name (full)
	%w	day of week (short)
	%W	day of week (full)
*/

size_t
Time::format (
	sl::String* string,
	const char* formatString
	) const
{
	static const char* weekDayShortNameTable [7] =
	{
		"Sun",
		"Mon",
		"Tue",
		"Wed",
		"Thu",
		"Fri",
		"Sat",
	};

	static const char* weekDayFullNameTable [7] =
	{
		"Sunday",
		"Monday",
		"Tuesday",
		"Wednsday",
		"Thursday",
		"Friday",
		"Saturday",
	};

	static const char* monthShortNameTable [12] =
	{
		"Jan",
		"Feb",
		"Mar",
		"Apr",
		"May",
		"Jun",
		"Jul",
		"Aug",
		"Sep",
		"Oct",
		"Nov",
		"Dec",
	};

	static const char* monthFullNameTable [12] =
	{
		"January",
		"February",
		"March",
		"April",
		"May",
		"June",
		"July",
		"August",
		"September",
		"October",
		"November",
		"December",
	};

	string->clear ();

	const char* p = formatString;
	const char* p0 = p;

	for (; *p; p++)
	{
		if (*p != '%')
			continue;

		string->append (p0, p - p0);

		p++;
		if (!*p)
			return string->getLength ();

		int h12;

		switch (*p)
		{
		case 'h':
			string->appendFormat ("%02d", m_hour);
			break;

		case 'H':
			h12 = m_hour % 12;
			string->appendFormat ("%d", h12 ? h12 : 12);
			break;

		case 'm':
			string->appendFormat ("%02d", m_minute);
			break;

		case 's':
			string->appendFormat ("%02d", m_second);
			break;

		case 'l':
			string->appendFormat ("%03d", m_milliSecond);
			break;

		case 'c':
			string->appendFormat ("%03d", m_microSecond);
			break;

		case 'p':
			string->append (m_hour >= 12 ? 'p' : 'a');
			break;

		case 'P':
			string->append (m_hour >= 12 ? 'P' : 'A');
			break;

		case 'y':
			string->appendFormat ("%02d", m_year % 100);
			break;

		case 'Y':
			string->appendFormat ("%04d", m_year);
			break;

		case 'D':
			string->appendFormat ("%02d", m_monthDay);
			break;

		case 'd':
			string->appendFormat ("%d", m_monthDay);
			break;

		case 'M':
			string->appendFormat ("%02d", m_month);
			break;

		case 'o':
			string->appendFormat ("%d", m_month);
			break;

		case 'n':
			string->append (monthShortNameTable [m_month % 12]);
			break;

		case 'N':
			string->append (monthFullNameTable [m_month % 12]);
			break;

		case 'w':
			string->append (weekDayShortNameTable [m_dayOfWeek % 7]);
			break;

		case 'W':
			string->append (weekDayFullNameTable [m_dayOfWeek % 7]);
			break;

		default:
			string->append (*p);
		}

		p0 = p + 1;
	}

	string->append (p0, p - p0);
	return string->getLength ();
}

//.............................................................................

} // namespace sys
} // namespace axl
<|endoftext|>