<commit_before>#include "include.h"

#include <string>
#include <vector>

#include "leveldb/db.h"
#include "leveldb/options.h"
#include "leveldb/slice.h"
#include "leveldb/iterator.h"

#include "link.h"
#include "util/log.h"
#include "util/file.h"
#include "util/strings.h"

template<class T>
static std::string serialize_req(T &req){
	std::string ret;
	char buf[50];
	for(int i=0; i<req.size(); i++){
		if(i >= 5 && i < req.size() - 1){
			sprintf(buf, "[%d more...]", (int)req.size() - i - 1);
			ret.append(buf);
			break;
		}
		if(((req[0] == "get" || req[0] == "set") && i == 1) || req[i].size() < 30){
			std::string h = hexmem(req[i].data(), req[i].size());
			ret.append(h);
		}else{
			sprintf(buf, "[%d bytes]", (int)req[i].size());
			ret.append(buf);
		}
		if(i < req.size() - 1){
			ret.append(" ");
		}
	}
	return ret;
}

void welcome(){
	printf("leveldb-import - Import existing leveldb into ssdb\n");
	printf("Copyright (c) 2013 ideawu.com\n");
	printf("\n");
}

void usage(int argc, char **argv){
	printf("Usage:\n");
	printf("    %s ip port input_folder\n", argv[0]);
	printf("\n");
	printf("Options:\n");
	printf("    ip - ssdb server ip address\n");
	printf("    port - ssdb server port number\n");
	printf("    input_folder - local leveldb folder\n");
}

int main(int argc, char **argv){
	welcome();

	set_log_level(Logger::LEVEL_MIN);

	if(argc <= 3){
		usage(argc, argv);
		return 0;
	}
	char *ip = argv[1];
	int port = atoi(argv[2]);
	char *input_folder = argv[3];

	if(!file_exists(input_folder)){
		printf("input_folder[%s] not exists!\n", input_folder);
		return 0;
	}

	std::string data_dir = "";
	data_dir.append(input_folder);

	// connect to server
	Link *link = Link::connect(ip, port);
	if(link == NULL){
		printf("error connecting to server!\n");
		return 0;
	}

	leveldb::DB* db;
	leveldb::Options options;
	leveldb::Status status;
	//options.create_if_missing = true;
	status = leveldb::DB::Open(options, data_dir.c_str(), &db);
	if(!status.ok()){
		printf("open leveldb: %s error!\n", input_folder);
		return 0;
	}

	printf("importing data...\n");
	leveldb::Iterator *it;
	it = db->NewIterator(leveldb::ReadOptions());
	int save_count = 0;
	for(it->SeekToFirst(); it->Valid(); it->Next()){
		std::string key = it->key().ToString();
		std::string val = it->value().ToString();

		const std::vector<Bytes> *req = link->request("set", key, val);
		if(req == NULL){
			printf("error\n");
			exit(0);
		}else if(req->empty()){
			if(link->read() <= 0){
				printf("server disconnected.\n");
				exit(0);
			}
		}else{
			if(req->at(0) != "ok"){
				printf("server response error: %s\n", req->at(0).String().c_str());
				exit(0);
			}
		}
		save_count ++;
	}
	printf("importing done.\n");
	printf("\n");
	printf("total %d item(s) imported.\n", save_count);

	delete link;
	delete db;
	return 0;
}
<commit_msg>update leveldb-import.cpp<commit_after>#include "include.h"

#include <string>
#include <vector>

#include "leveldb/db.h"
#include "leveldb/options.h"
#include "leveldb/slice.h"
#include "leveldb/iterator.h"

#include "link.h"
#include "util/log.h"
#include "util/file.h"
#include "util/strings.h"

void welcome(){
	printf("leveldb-import - Import existing leveldb into ssdb\n");
	printf("Copyright (c) 2013 ideawu.com\n");
	printf("\n");
}

void usage(int argc, char **argv){
	printf("Usage:\n");
	printf("    %s ip port input_folder\n", argv[0]);
	printf("\n");
	printf("Options:\n");
	printf("    ip - ssdb server ip address\n");
	printf("    port - ssdb server port number\n");
	printf("    input_folder - local leveldb folder\n");
}

int main(int argc, char **argv){
	welcome();

	set_log_level(Logger::LEVEL_MIN);

	if(argc <= 3){
		usage(argc, argv);
		return 0;
	}
	char *ip = argv[1];
	int port = atoi(argv[2]);
	char *input_folder = argv[3];

	if(!file_exists(input_folder)){
		printf("input_folder[%s] not exists!\n", input_folder);
		return 0;
	}

	std::string data_dir = "";
	data_dir.append(input_folder);

	// connect to server
	Link *link = Link::connect(ip, port);
	if(link == NULL){
		printf("error connecting to server!\n");
		return 0;
	}

	leveldb::DB* db;
	leveldb::Options options;
	leveldb::Status status;
	//options.create_if_missing = true;
	status = leveldb::DB::Open(options, data_dir.c_str(), &db);
	if(!status.ok()){
		printf("open leveldb: %s error!\n", input_folder);
		return 0;
	}

	printf("importing data...\n");
	leveldb::Iterator *it;
	it = db->NewIterator(leveldb::ReadOptions());
	int save_count = 0;
	for(it->SeekToFirst(); it->Valid(); it->Next()){
		std::string key = it->key().ToString();
		std::string val = it->value().ToString();

		const std::vector<Bytes> *req = link->request("set", key, val);
		if(req == NULL){
			printf("error\n");
			exit(0);
		}else{
			if(req->at(0) != "ok"){
				printf("server response error: %s\n", req->at(0).String().c_str());
				exit(0);
			}
		}
		save_count ++;
	}
	printf("importing done.\n");
	printf("\n");
	printf("total %d item(s) imported.\n", save_count);

	delete link;
	delete db;
	return 0;
}
<|endoftext|>


<commit_before>// Copyright 2007-2009 David Roberts <dvdr18@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library.  If not, see <http://www.gnu.org/licenses/>.

#include "SunLocator.h"
#include "ExtDateTime.h"
#include "PlanetaryConstants.h"
#include "MarbleMath.h"

#include <QtCore/QDebug>

#include <cmath>
// M_PI is sometimes defined in <cmath>
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288419717
#endif

namespace Marble {

using std::sin;
using std::cos;
using std::asin;
using std::abs;

qreal deg2rad(qreal x) { return x*M_PI/180.0; }
qreal rad2deg(qreal x) { return x*180.0/M_PI; }

const int J2000 = 2451545; // epoch J2000 = 1 January 2000, noon Terrestrial Time (11:58:55.816 UTC)

// taking the full moon of 15 January 1900 19:07 UTC as the epoch for the moon
const qreal MOON_EPOCH = 2415035.297; // value from http://home.hiwaay.net/~krcool/Astro/moon/fullmoon.htm
const qreal MOON_SYNODIC_PERIOD = 29.530588;

const int update_interval = 60000; // emit updateSun() every update_interval ms

class SunLocatorPrivate
{
public:
    explicit SunLocatorPrivate(ExtDateTime *dateTime)
        : m_lon( 0.0 ),
          m_lat( 0.0 ),
          m_datetime( dateTime ),
          m_show( false ),
          m_citylights( false ),
          m_centered( false ),
          m_body( "" )
    {
    }

    qreal m_lon;
    qreal m_lat;

    ExtDateTime* m_datetime;
    bool m_show;
    bool m_citylights;
    bool m_centered;
    QString m_body;
};

SunLocator::SunLocator(ExtDateTime *dateTime)
  : QObject(),
    d( new SunLocatorPrivate( dateTime ))
{
}

SunLocator::~SunLocator()
{
    delete d;
}

void SunLocator::updatePosition()
{
    if( d->m_body == "moon" ) {
        qreal days = (qreal)d->m_datetime->toJDN() + d->m_datetime->dayFraction() - MOON_EPOCH; // days since the first full moon of the 20th century
        days /= MOON_SYNODIC_PERIOD; // number of orbits the moon has made (relative to the sun as observed from earth)
        days = days - (int)days; // take fractional part
        if(days < 0.0) days += 1.0; // for dates before MOON_EPOCH

        qDebug() << "MOON:" << (int)(days*100) << "% of orbit completed and" << (int)(abs((days-0.5)*2) * 100) << "% illuminated";

        d->m_lon = (1-days) * 2*M_PI;
        d->m_lat = 0.0; // not necessarily accurate but close enough (only differs by about +-6 degrees of this value)

	return;
    }

    PlanetaryConstants pc = PC_EARTH; // default to the earth
    // planets
         if ( d->m_body == "mercury" ) pc = PC_MERCURY;
    else if ( d->m_body == "venus" )   pc = PC_VENUS;
    else if ( d->m_body == "earth" )   pc = PC_EARTH;
    else if ( d->m_body == "mars" )    pc = PC_MARS;
    else if ( d->m_body == "jupiter" ) pc = PC_JUPITER;
    else if ( d->m_body == "saturn" )  pc = PC_SATURN;
    else if ( d->m_body == "uranus" )  pc = PC_URANUS;
    else if ( d->m_body == "neptune" ) pc = PC_NEPTUNE;
    // dwarf planets ... (everybody likes pluto)
    else if ( d->m_body == "pluto" )   pc = PC_PLUTO;

    long day = d->m_datetime->toJDN() - J2000; // find current Julian day number relative to epoch J2000

    // from http://www.astro.uu.nl/~strous/AA/en/reken/zonpositie.html
    qreal M = pc.M_0 + pc.M_1*day; // mean anomaly
    qreal C = pc.C_1*sin(M) + pc.C_2*sin(2*M) + pc.C_3*sin(3*M) + pc.C_4*sin(4*M) + pc.C_5*sin(5*M) + pc.C_6*sin(6*M); // equation of center
    qreal nu = M + C; // true anomaly
    qreal lambda_sun = nu + pc.Pi + M_PI; // ecliptic longitude of sun as seen from planet
    qreal delta_sun = asin(sin(pc.epsilon)*sin(lambda_sun)); // declination of sun as seen from planet
    qreal alpha_sun = atan2(cos(pc.epsilon)*sin(lambda_sun), cos(lambda_sun)); // right ascension of sun as seen from planet

    qreal theta = alpha_sun; // solar noon occurs when sidereal time is equal to alpha_sun
    d->m_lon = M_PI - (pc.theta_0 + pc.theta_1 * (day + d->m_datetime->dayFraction()) - theta); // convert sidereal time to geographic longitude
    while(d->m_lon < 0) d->m_lon += 2*M_PI;
    d->m_lat = -delta_sun; // convert positive north to positive south

    qDebug() << "alpha_sun =" << rad2deg(alpha_sun);
    qDebug() << "delta_sun =" << rad2deg(delta_sun);
    qDebug() << "d->m_lon =" << rad2deg(d->m_lon);
    qDebug() << "d->m_lat =" << rad2deg(d->m_lat);
}

qreal SunLocator::shading(qreal lon, qreal lat) const
{

    // haversine formula
    qreal a = sin((lat-d->m_lat)/2.0);
    qreal b = sin((lon-d->m_lon)/2.0);
    qreal h = (a*a)+cos(lat)*cos(d->m_lat)*(b*b);

    /*
      h = 0.0 // directly beneath sun
      h = 0.5 // sunrise/sunset line
      h = 1.0 // opposite side of earth to the sun
      theta = 2*asin(sqrt(h))
    */

    qreal twilightZone = 0.0;

    if ( d->m_body == "earth" || d->m_body == "venus" ) {
        twilightZone = 0.1; // this equals 18 deg astronomical twilight.
    }

    qreal brightness;
    if ( h <= 0.5 - twilightZone / 2.0 )
        brightness = 1.0;
    else if ( h >= 0.5 + twilightZone / 2.0 )
        brightness = 0.0;
    else
        brightness = ( 0.5 + twilightZone/2.0 - h ) / twilightZone;

    return brightness;
}

void SunLocator::shadePixel(QRgb& pixcol, qreal brightness) const
{
    // daylight - no change
    if ( brightness > 0.99999 )
        return;

    if ( brightness < 0.00001 ) {
        // night
//      Doing  "pixcol = qRgb(r/2, g/2, b/2);" by shifting some electrons around ;)
        pixcol = qRgb(qRed(pixcol) * 0.35, qGreen(pixcol) * 0.35, qBlue(pixcol)  * 0.35); // by shifting some electrons around ;)
        // pixcol = (pixcol & 0xff000000) | ((pixcol >> 1) & 0x7f7f7f);
    } else {
        // gradual shadowing
        int r = qRed( pixcol );
        int g = qGreen( pixcol );
        int b = qBlue( pixcol );
        qreal  d = 0.65 * brightness + 0.35;
        pixcol = qRgb((int)(d * r), (int)(d * g), (int)(d * b));
    }
}

void SunLocator::shadePixelComposite(QRgb& pixcol, QRgb& dpixcol,
                                     qreal brightness) const
{
    // daylight - no change
    if ( brightness > 0.99999 )
        return;

    if ( brightness < 0.00001 ) {
        // night
        pixcol = dpixcol;
    } else {
        // gradual shadowing
        qreal& d = brightness;

        int r = qRed( pixcol );
        int g = qGreen( pixcol );
        int b = qBlue( pixcol );

        int dr = qRed( dpixcol );
        int dg = qGreen( dpixcol );
        int db = qBlue( dpixcol );

        pixcol = qRgb( (int)( d * r + (1 - d) * dr ),
                       (int)( d * g + (1 - d) * dg ),
                       (int)( d * b + (1 - d) * db ) );
    }
}

void SunLocator::update()
{
    qDebug() << "void SunLocator::update()";
    updatePosition();
    if ( d->m_show || d->m_centered )
    {
        if ( d->m_show )
            emit updateSun();
        if ( d->m_centered )
            emit centerSun();
        return;
    }

    emit updateStars();
}

void SunLocator::setShow(bool show)
{
    if ( show == d->m_show ) {
        return;
    }

    qDebug() << "void SunLocator::setShow( bool )";
    d->m_show = show;
    updatePosition();

    emit updateSun();
}

void SunLocator::setCentered(bool centered)
{
    if ( centered == d->m_centered ) {
        return;
    }

    qDebug() << "SunLocator::setCentered";
    qDebug() << "sunLocator =" << this;
    d->m_centered = centered;
    if ( d->m_centered ) {
        updatePosition();
        emit centerSun();
    } else
        emit reenableWidgetInput();
}

void SunLocator::setBody(QString body)
{
    if ( body == d->m_body ) {
        return;
    }

    QString previousBody = d->m_body;

    qDebug() << "SunLocator::setBody( QString )";
    d->m_body = body;
    updatePosition();

    if ( !previousBody.isEmpty() ) {
        emit updateSun();
    }
}

void SunLocator::setCitylights(bool show)
{
    d->m_citylights = show;
}

bool SunLocator::getShow() const
{
    return d->m_show;
}

bool SunLocator::getCitylights() const
{
    return d->m_citylights;
}

bool SunLocator::getCentered() const
{
    return d->m_centered;
}

qreal SunLocator::getLon() const
{
    return d->m_lon * 180.0 / M_PI;
}

qreal SunLocator::getLat() const
{
    return -d->m_lat * 180.0 / M_PI;
}

ExtDateTime* SunLocator::datetime() const
{
    return d->m_datetime;
}

}

#include "SunLocator.moc"
<commit_msg>coding style<commit_after>// Copyright 2007-2009 David Roberts <dvdr18@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library.  If not, see <http://www.gnu.org/licenses/>.

#include "SunLocator.h"
#include "ExtDateTime.h"
#include "PlanetaryConstants.h"
#include "MarbleMath.h"

#include <QtCore/QDebug>

#include <cmath>
// M_PI is sometimes defined in <cmath>
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288419717
#endif

namespace Marble {

using std::sin;
using std::cos;
using std::asin;
using std::abs;

qreal deg2rad(qreal x) { return x*M_PI/180.0; }
qreal rad2deg(qreal x) { return x*180.0/M_PI; }

// epoch J2000 = 1 January 2000, noon Terrestrial Time (11:58:55.816 UTC)
const int J2000 = 2451545;

// taking the full moon of 15 January 1900 19:07 UTC as the epoch for the moon
// value from http://home.hiwaay.net/~krcool/Astro/moon/fullmoon.htm
const qreal MOON_EPOCH = 2415035.297;
const qreal MOON_SYNODIC_PERIOD = 29.530588;

// emit updateSun() every update_interval ms
const int update_interval = 60000;

class SunLocatorPrivate
{
public:
    explicit SunLocatorPrivate(ExtDateTime *dateTime)
        : m_lon( 0.0 ),
          m_lat( 0.0 ),
          m_datetime( dateTime ),
          m_show( false ),
          m_citylights( false ),
          m_centered( false ),
          m_body( "" )
    {
    }

    qreal m_lon;
    qreal m_lat;

    ExtDateTime* m_datetime;
    bool m_show;
    bool m_citylights;
    bool m_centered;
    QString m_body;
};

SunLocator::SunLocator(ExtDateTime *dateTime)
  : QObject(),
    d( new SunLocatorPrivate( dateTime ))
{
}

SunLocator::~SunLocator()
{
    delete d;
}

void SunLocator::updatePosition()
{
    if( d->m_body == "moon" ) {
        // days since the first full moon of the 20th century
        qreal days = (qreal)d->m_datetime->toJDN() + d->m_datetime->dayFraction() - MOON_EPOCH;

        // number of orbits the moon has made (relative to the sun as observed from earth)
        days /= MOON_SYNODIC_PERIOD;

        // take fractional part
        days = days - (int)days;

        // for dates before MOON_EPOCH
        if (days < 0.0)
            days += 1.0;

        qDebug() << "MOON:" << (int)(days*100) << "% of orbit completed and"
                 << (int)(abs((days-0.5)*2) * 100) << "% illuminated";

        d->m_lon = (1-days) * 2*M_PI;

        // not necessarily accurate but close enough
        // (only differs by about +-6 degrees of this value)
        d->m_lat = 0.0;
	return;
    }

    // default to the earth
    PlanetaryConstants pc = PC_EARTH;
    // planets
    if ( d->m_body == "mercury" ) pc = PC_MERCURY;
    else if ( d->m_body == "venus" )   pc = PC_VENUS;
    else if ( d->m_body == "earth" )   pc = PC_EARTH;
    else if ( d->m_body == "mars" )    pc = PC_MARS;
    else if ( d->m_body == "jupiter" ) pc = PC_JUPITER;
    else if ( d->m_body == "saturn" )  pc = PC_SATURN;
    else if ( d->m_body == "uranus" )  pc = PC_URANUS;
    else if ( d->m_body == "neptune" ) pc = PC_NEPTUNE;
    else if ( d->m_body == "pluto" )   pc = PC_PLUTO;

    // find current Julian day number relative to epoch J2000
    long day = d->m_datetime->toJDN() - J2000;

    // from http://www.astro.uu.nl/~strous/AA/en/reken/zonpositie.html
    // mean anomaly
    qreal M = pc.M_0 + pc.M_1*day;

    // equation of center
    qreal C = pc.C_1*sin(M) + pc.C_2*sin(2*M) + pc.C_3*sin(3*M) + pc.C_4*sin(4*M)
        + pc.C_5*sin(5*M) + pc.C_6*sin(6*M);

    // true anomaly
    qreal nu = M + C;

    // ecliptic longitude of sun as seen from planet
    qreal lambda_sun = nu + pc.Pi + M_PI;

    // declination of sun as seen from planet
    qreal delta_sun = asin(sin(pc.epsilon)*sin(lambda_sun));

    // right ascension of sun as seen from planet
    qreal alpha_sun = atan2(cos(pc.epsilon)*sin(lambda_sun), cos(lambda_sun));

    // solar noon occurs when sidereal time is equal to alpha_sun
    qreal theta = alpha_sun;

    // convert sidereal time to geographic longitude
    d->m_lon = M_PI - (pc.theta_0 + pc.theta_1 * (day + d->m_datetime->dayFraction()) - theta);

    while(d->m_lon < 0)
        d->m_lon += 2*M_PI;

    // convert positive north to positive south
    d->m_lat = -delta_sun;

    qDebug() << "alpha_sun =" << rad2deg(alpha_sun);
    qDebug() << "delta_sun =" << rad2deg(delta_sun);
    qDebug() << "d->m_lon =" << rad2deg(d->m_lon);
    qDebug() << "d->m_lat =" << rad2deg(d->m_lat);
}

qreal SunLocator::shading(qreal lon, qreal lat) const
{
    // haversine formula
    qreal a = sin((lat-d->m_lat)/2.0);
    qreal b = sin((lon-d->m_lon)/2.0);
    qreal h = (a*a)+cos(lat)*cos(d->m_lat)*(b*b);

    /*
      h = 0.0 // directly beneath sun
      h = 0.5 // sunrise/sunset line
      h = 1.0 // opposite side of earth to the sun
      theta = 2*asin(sqrt(h))
    */

    qreal twilightZone = 0.0;

    if ( d->m_body == "earth" || d->m_body == "venus" ) {
        twilightZone = 0.1; // this equals 18 deg astronomical twilight.
    }

    qreal brightness;
    if ( h <= 0.5 - twilightZone / 2.0 )
        brightness = 1.0;
    else if ( h >= 0.5 + twilightZone / 2.0 )
        brightness = 0.0;
    else
        brightness = ( 0.5 + twilightZone/2.0 - h ) / twilightZone;

    return brightness;
}

void SunLocator::shadePixel(QRgb& pixcol, qreal brightness) const
{
    // daylight - no change
    if ( brightness > 0.99999 )
        return;

    if ( brightness < 0.00001 ) {
        // night
        //      Doing  "pixcol = qRgb(r/2, g/2, b/2);" by shifting some electrons around ;)
        // by shifting some electrons around ;)
        pixcol = qRgb(qRed(pixcol) * 0.35, qGreen(pixcol) * 0.35, qBlue(pixcol)  * 0.35);
        // pixcol = (pixcol & 0xff000000) | ((pixcol >> 1) & 0x7f7f7f);
    } else {
        // gradual shadowing
        int r = qRed( pixcol );
        int g = qGreen( pixcol );
        int b = qBlue( pixcol );
        qreal  d = 0.65 * brightness + 0.35;
        pixcol = qRgb((int)(d * r), (int)(d * g), (int)(d * b));
    }
}

void SunLocator::shadePixelComposite(QRgb& pixcol, QRgb& dpixcol,
                                     qreal brightness) const
{
    // daylight - no change
    if ( brightness > 0.99999 )
        return;

    if ( brightness < 0.00001 ) {
        // night
        pixcol = dpixcol;
    } else {
        // gradual shadowing
        qreal& d = brightness;

        int r = qRed( pixcol );
        int g = qGreen( pixcol );
        int b = qBlue( pixcol );

        int dr = qRed( dpixcol );
        int dg = qGreen( dpixcol );
        int db = qBlue( dpixcol );

        pixcol = qRgb( (int)( d * r + (1 - d) * dr ),
                       (int)( d * g + (1 - d) * dg ),
                       (int)( d * b + (1 - d) * db ) );
    }
}

void SunLocator::update()
{
    qDebug() << "void SunLocator::update()";
    updatePosition();
    if ( d->m_show || d->m_centered ) {
        if ( d->m_show )
            emit updateSun();
        if ( d->m_centered )
            emit centerSun();
        return;
    }

    emit updateStars();
}

void SunLocator::setShow(bool show)
{
    if ( show == d->m_show ) {
        return;
    }

    qDebug() << "void SunLocator::setShow( bool )";
    d->m_show = show;
    updatePosition();

    emit updateSun();
}

void SunLocator::setCentered(bool centered)
{
    if ( centered == d->m_centered ) {
        return;
    }

    qDebug() << "SunLocator::setCentered";
    qDebug() << "sunLocator =" << this;
    d->m_centered = centered;
    if ( d->m_centered ) {
        updatePosition();
        emit centerSun();
    } else
        emit reenableWidgetInput();
}

void SunLocator::setBody(QString body)
{
    if ( body == d->m_body ) {
        return;
    }

    QString previousBody = d->m_body;

    qDebug() << "SunLocator::setBody( QString )";
    d->m_body = body;
    updatePosition();

    if ( !previousBody.isEmpty() ) {
        emit updateSun();
    }
}

void SunLocator::setCitylights(bool show)
{
    d->m_citylights = show;
}

bool SunLocator::getShow() const
{
    return d->m_show;
}

bool SunLocator::getCitylights() const
{
    return d->m_citylights;
}

bool SunLocator::getCentered() const
{
    return d->m_centered;
}

qreal SunLocator::getLon() const
{
    return d->m_lon * 180.0 / M_PI;
}

qreal SunLocator::getLat() const
{
    return -d->m_lat * 180.0 / M_PI;
}

ExtDateTime* SunLocator::datetime() const
{
    return d->m_datetime;
}

}

#include "SunLocator.moc"
<|endoftext|>


<commit_before>// Copyright 2007-2008 David Roberts <dvdr18@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library.  If not, see <http://www.gnu.org/licenses/>.

#include "SunLocator.h"
#include "ExtDateTime.h"

#include <QtCore/QDebug>

using namespace Marble;

using std::sin;
using std::cos;
using std::asin;
using std::abs;

const int J2000 = 2451545; // epoch J2000 = 1 January 2000, noon Terrestrial Time (11:58:55.816 UTC)

// taking the full moon of 15 January 1900 19:07 UTC as the epoch for the moon
const qreal MOON_EPOCH = 2415035.297; // value from http://home.hiwaay.net/~krcool/Astro/moon/fullmoon.htm
const qreal MOON_SYNODIC_PERIOD = 29.530588;

const int update_interval = 60000; // emit updateSun() every update_interval ms

namespace Marble {

class SunLocatorPrivate { };

}

SunLocator::SunLocator(ExtDateTime *dateTime)
  : QObject(),
    d( new SunLocatorPrivate ),
    m_datetime( dateTime ),
    m_show( false ),
    m_citylights( false ),
    m_centered( false ),
    m_body( "" )
{
}

SunLocator::~SunLocator() {
//     delete m_datetime;
    delete d;
}

void SunLocator::updatePosition()
{
    // Find the orientation of the sun.
    if( m_body == "moon" ) {
        qreal d = (qreal)m_datetime->toJDN() + m_datetime->dayFraction() - MOON_EPOCH; // days since the first full moon of the 20th century
        d /= MOON_SYNODIC_PERIOD; // number of orbits the moon has made (relative to the sun as observed from earth)
        d = d - (int)d; // take fractional part
        if(d < 0.0) d += 1.0; // for dates before MOON_EPOCH

        qDebug() << "MOON:" << (int)(d*100) << "% of orbit completed and" << (int)(abs((d-0.5)*2) * 100) << "% illuminated";

        m_lon = (1-d) * 2*M_PI;
        m_lat = 0.0; // not necessarily accurate but close enough (only differs by about +-6 degrees of this value)
    } else { // default to the earth
        // Find current Julian day number relative to epoch J2000.
        long d = m_datetime->toJDN() - J2000;

        // Adapted from http://www.stargazing.net/kepler/sun.html
        qreal       L = 4.89497 + 0.0172028 * d;                  // mean longitude
        qreal       g = 6.24004 + 0.0172020 * d;                  // mean anomaly
        qreal  lambda = L + 0.0334 * sin(g) + 3.49e-4 * sin(2*g); // ecliptic longitude
        qreal epsilon = 0.40909 - 7e-9 * d;                       // obliquity of the ecliptic plane
        qreal   delta = asin(sin(epsilon)*sin(lambda));           // declination

        // Convert position of sun to coordinates.
        m_lon = M_PI - m_datetime->dayFraction() * 2*M_PI;
        m_lat = -delta;
    }
}

qreal SunLocator::shading(qreal lon, qreal lat)
{
    // haversine formula
    qreal a = sin((lat-m_lat)/2.0);
    qreal b = sin((lon-m_lon)/2.0);
    qreal h = (a*a)+cos(lat)*cos(m_lat)*(b*b);

    /*
      h = 0.0 // directly beneath sun
      h = 0.5 // sunrise/sunset line
      h = 1.0 // opposite side of earth to the sun
      theta = 2*asin(sqrt(h))
    */

    qreal twilightZone = 0.0;

    if ( m_body == "earth" || m_body == "venus" ) {
        twilightZone = 0.1; // this equals 18 deg astronomical twilight.
    }

    qreal brightness;
    if ( h <= 0.5 - twilightZone / 2.0 )
        brightness = 1.0;
    else if ( h >= 0.5 + twilightZone / 2.0 )
        brightness = 0.0;
    else
        brightness = ( 0.5 + twilightZone/2.0 - h ) / twilightZone;

    return brightness;
}

void SunLocator::shadePixel(QRgb& pixcol, qreal brightness)
{
    // daylight - no change
    if ( brightness > 0.99999 )
        return;

    if ( brightness < 0.00001 ) {
        // night
//      Doing  "pixcol = qRgb(r/2, g/2, b/2);" by shifting some electrons around ;)
        pixcol = qRgb(qRed(pixcol) * 0.35, qGreen(pixcol) * 0.35, qBlue(pixcol)  * 0.35); // by shifting some electrons around ;)
        // pixcol = (pixcol & 0xff000000) | ((pixcol >> 1) & 0x7f7f7f);
    } else {
        // gradual shadowing
        int r = qRed( pixcol );
        int g = qGreen( pixcol );
        int b = qBlue( pixcol );
        qreal  d = 0.65 * brightness + 0.35;
        pixcol = qRgb((int)(d * r), (int)(d * g), (int)(d * b));
    }
}

void SunLocator::shadePixelComposite(QRgb& pixcol, QRgb& dpixcol,
                                     qreal brightness)
{
    // daylight - no change
    if ( brightness > 0.99999 )
        return;

    if ( brightness < 0.00001 ) {
        // night
        pixcol = dpixcol;
    } else {
        // gradual shadowing
        qreal& d = brightness;

        int r = qRed( pixcol );
        int g = qGreen( pixcol );
        int b = qBlue( pixcol );

        int dr = qRed( dpixcol );
        int dg = qGreen( dpixcol );
        int db = qBlue( dpixcol );

        pixcol = qRgb( (int)( d * r + (1 - d) * dr ),
                       (int)( d * g + (1 - d) * dg ),
                       (int)( d * b + (1 - d) * db ) );
    }
}

void SunLocator::update()
{
    qDebug() << "void SunLocator::update()";
    updatePosition();
    if ( m_show || m_centered )
    {
        if ( m_show )
            emit updateSun();
        if ( m_centered )
            emit centerSun();
        return;
    }

    emit updateStars();
}

void SunLocator::setShow(bool show)
{
    if ( show == m_show ) {
        return;
    }

    qDebug() << "void SunLocator::setShow( bool )";
    m_show = show;
    updatePosition();

    emit updateSun();
}

void SunLocator::setCentered(bool centered)
{
    if ( centered == m_centered ) {
        return;
    }

    qDebug() << "SunLocator::setCentered";
    qDebug() << "sunLocator =" << this;
    m_centered = centered;
    if ( m_centered ) {
        updatePosition();
        emit centerSun();
    } else
        emit reenableWidgetInput();
}

void SunLocator::setBody(QString body)
{
    if ( body == m_body ) {
        return;
    }

    QString previousBody = m_body;

    qDebug() << "SunLocator::setBody( QString )";
    m_body = body;
    updatePosition();

    if ( previousBody != "" ) {
        emit updateSun();
    }
}

#include "SunLocator.moc"
<commit_msg>krazy: Check for QString compares to "" (1 issue)<commit_after>// Copyright 2007-2008 David Roberts <dvdr18@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library.  If not, see <http://www.gnu.org/licenses/>.

#include "SunLocator.h"
#include "ExtDateTime.h"

#include <QtCore/QDebug>

using namespace Marble;

using std::sin;
using std::cos;
using std::asin;
using std::abs;

const int J2000 = 2451545; // epoch J2000 = 1 January 2000, noon Terrestrial Time (11:58:55.816 UTC)

// taking the full moon of 15 January 1900 19:07 UTC as the epoch for the moon
const qreal MOON_EPOCH = 2415035.297; // value from http://home.hiwaay.net/~krcool/Astro/moon/fullmoon.htm
const qreal MOON_SYNODIC_PERIOD = 29.530588;

const int update_interval = 60000; // emit updateSun() every update_interval ms

namespace Marble {

class SunLocatorPrivate { };

}

SunLocator::SunLocator(ExtDateTime *dateTime)
  : QObject(),
    d( new SunLocatorPrivate ),
    m_datetime( dateTime ),
    m_show( false ),
    m_citylights( false ),
    m_centered( false ),
    m_body( "" )
{
}

SunLocator::~SunLocator() {
//     delete m_datetime;
    delete d;
}

void SunLocator::updatePosition()
{
    // Find the orientation of the sun.
    if( m_body == "moon" ) {
        qreal d = (qreal)m_datetime->toJDN() + m_datetime->dayFraction() - MOON_EPOCH; // days since the first full moon of the 20th century
        d /= MOON_SYNODIC_PERIOD; // number of orbits the moon has made (relative to the sun as observed from earth)
        d = d - (int)d; // take fractional part
        if(d < 0.0) d += 1.0; // for dates before MOON_EPOCH

        qDebug() << "MOON:" << (int)(d*100) << "% of orbit completed and" << (int)(abs((d-0.5)*2) * 100) << "% illuminated";

        m_lon = (1-d) * 2*M_PI;
        m_lat = 0.0; // not necessarily accurate but close enough (only differs by about +-6 degrees of this value)
    } else { // default to the earth
        // Find current Julian day number relative to epoch J2000.
        long d = m_datetime->toJDN() - J2000;

        // Adapted from http://www.stargazing.net/kepler/sun.html
        qreal       L = 4.89497 + 0.0172028 * d;                  // mean longitude
        qreal       g = 6.24004 + 0.0172020 * d;                  // mean anomaly
        qreal  lambda = L + 0.0334 * sin(g) + 3.49e-4 * sin(2*g); // ecliptic longitude
        qreal epsilon = 0.40909 - 7e-9 * d;                       // obliquity of the ecliptic plane
        qreal   delta = asin(sin(epsilon)*sin(lambda));           // declination

        // Convert position of sun to coordinates.
        m_lon = M_PI - m_datetime->dayFraction() * 2*M_PI;
        m_lat = -delta;
    }
}

qreal SunLocator::shading(qreal lon, qreal lat)
{
    // haversine formula
    qreal a = sin((lat-m_lat)/2.0);
    qreal b = sin((lon-m_lon)/2.0);
    qreal h = (a*a)+cos(lat)*cos(m_lat)*(b*b);

    /*
      h = 0.0 // directly beneath sun
      h = 0.5 // sunrise/sunset line
      h = 1.0 // opposite side of earth to the sun
      theta = 2*asin(sqrt(h))
    */

    qreal twilightZone = 0.0;

    if ( m_body == "earth" || m_body == "venus" ) {
        twilightZone = 0.1; // this equals 18 deg astronomical twilight.
    }

    qreal brightness;
    if ( h <= 0.5 - twilightZone / 2.0 )
        brightness = 1.0;
    else if ( h >= 0.5 + twilightZone / 2.0 )
        brightness = 0.0;
    else
        brightness = ( 0.5 + twilightZone/2.0 - h ) / twilightZone;

    return brightness;
}

void SunLocator::shadePixel(QRgb& pixcol, qreal brightness)
{
    // daylight - no change
    if ( brightness > 0.99999 )
        return;

    if ( brightness < 0.00001 ) {
        // night
//      Doing  "pixcol = qRgb(r/2, g/2, b/2);" by shifting some electrons around ;)
        pixcol = qRgb(qRed(pixcol) * 0.35, qGreen(pixcol) * 0.35, qBlue(pixcol)  * 0.35); // by shifting some electrons around ;)
        // pixcol = (pixcol & 0xff000000) | ((pixcol >> 1) & 0x7f7f7f);
    } else {
        // gradual shadowing
        int r = qRed( pixcol );
        int g = qGreen( pixcol );
        int b = qBlue( pixcol );
        qreal  d = 0.65 * brightness + 0.35;
        pixcol = qRgb((int)(d * r), (int)(d * g), (int)(d * b));
    }
}

void SunLocator::shadePixelComposite(QRgb& pixcol, QRgb& dpixcol,
                                     qreal brightness)
{
    // daylight - no change
    if ( brightness > 0.99999 )
        return;

    if ( brightness < 0.00001 ) {
        // night
        pixcol = dpixcol;
    } else {
        // gradual shadowing
        qreal& d = brightness;

        int r = qRed( pixcol );
        int g = qGreen( pixcol );
        int b = qBlue( pixcol );

        int dr = qRed( dpixcol );
        int dg = qGreen( dpixcol );
        int db = qBlue( dpixcol );

        pixcol = qRgb( (int)( d * r + (1 - d) * dr ),
                       (int)( d * g + (1 - d) * dg ),
                       (int)( d * b + (1 - d) * db ) );
    }
}

void SunLocator::update()
{
    qDebug() << "void SunLocator::update()";
    updatePosition();
    if ( m_show || m_centered )
    {
        if ( m_show )
            emit updateSun();
        if ( m_centered )
            emit centerSun();
        return;
    }

    emit updateStars();
}

void SunLocator::setShow(bool show)
{
    if ( show == m_show ) {
        return;
    }

    qDebug() << "void SunLocator::setShow( bool )";
    m_show = show;
    updatePosition();

    emit updateSun();
}

void SunLocator::setCentered(bool centered)
{
    if ( centered == m_centered ) {
        return;
    }

    qDebug() << "SunLocator::setCentered";
    qDebug() << "sunLocator =" << this;
    m_centered = centered;
    if ( m_centered ) {
        updatePosition();
        emit centerSun();
    } else
        emit reenableWidgetInput();
}

void SunLocator::setBody(QString body)
{
    if ( body == m_body ) {
        return;
    }

    QString previousBody = m_body;

    qDebug() << "SunLocator::setBody( QString )";
    m_body = body;
    updatePosition();

    if ( !previousBody.isEmpty() ) {
        emit updateSun();
    }
}

#include "SunLocator.moc"
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2003-2006 Funambol
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <sys/stat.h>
#include <unistd.h>

#include "base/Log.h"
#include "base/util/utils.h"

long utf8len(const char* s) {
	 return s ? wcslen(s) : 0;
}

char* wc2utf8(const char* s, char* d, unsigned long dsize) {

    //
    // First of all, if s is NULL, just return NULL.
    // Then, if d is NULL, let's allocate the required memory to contain the
    // utf8 string.
    //
    if (s == NULL) {
        return NULL;
    }

    if (d == NULL) {
        dsize = utf8len(s);
        d = new char[dsize+1];
    }

	 wcscpy( d, s );

    return d;
}

char* utf82wc(const char* s, char* d, unsigned long dsize) {

    //
    // First of all, if s is NULL, just return NULL.
    // Then, if d is NULL, let's allocate the required memory to contain the
    // wchar_t string.
    //
    if (s == NULL) {
        return NULL;
    }

    if (d == NULL) {
        // get the right lenght with a NULL dest
        dsize = strlen (s);
        d = new wchar_t[dsize+1];
    }

    wcscpy(d, s);

    return d;

}

bool saveFile(const char *filename, const char *buffer, size_t len, bool binary)
{
	const char *mode = binary ? "wb" : "w" ;

    FILE *f = fopen(filename, "w");

    if(!f)
        return false;

    if (fwrite(buffer, len, sizeof(char), f) != len) {
        fclose(f);
        return false;
    }
    fclose(f);

    return true;
}

bool readFile(const char* path, char **message, size_t *len, bool binary)
{
    FILE *f = NULL;
    size_t msglen=0;
    char *msg=0;
    const char *mode = binary ? "rb" : "r" ;
    struct stat buf;
    bool res = false;

    f = fopen(path, mode);
    if ( !f ) {
        goto done;
    }
    if ( fstat(fileno(f), &buf) ) {
        goto done;
    }

    msglen = buf.st_size;
    msg = new char[msglen+1];
    msg[msglen] = 0;

    *len=fread(msg, sizeof(char), msglen, f);
    if ( ferror(f) || *len < msglen ){
        goto done;
    }

    // Set return parameters
    *message=msg;
    msg = 0;
    res = true;

  done:
    if (f) {
        fclose(f);
    }
    if (msg) {
        delete [] msg;
    }

    return res;
}

// TODO: convert to the specified encoding, assuming wc is UTF-8
char* toMultibyte(const WCHAR *wc, const BCHAR *encoding)
{
    return stringdup(wc);
}

// TODO: convert to UTF-8 from the specified encoding
wchar_t* toWideChar(const char *mb, const BCHAR *encoding)
{
    return stringdup(mb);
}

<commit_msg>added the missing mkTempFileName()<commit_after>/*
 * Copyright (C) 2003-2006 Funambol
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <sys/stat.h>
#include <unistd.h>

#include "base/Log.h"
#include "base/util/utils.h"

long utf8len(const char* s) {
	 return s ? wcslen(s) : 0;
}

char* wc2utf8(const char* s, char* d, unsigned long dsize) {

    //
    // First of all, if s is NULL, just return NULL.
    // Then, if d is NULL, let's allocate the required memory to contain the
    // utf8 string.
    //
    if (s == NULL) {
        return NULL;
    }

    if (d == NULL) {
        dsize = utf8len(s);
        d = new char[dsize+1];
    }

	 wcscpy( d, s );

    return d;
}

char* utf82wc(const char* s, char* d, unsigned long dsize) {

    //
    // First of all, if s is NULL, just return NULL.
    // Then, if d is NULL, let's allocate the required memory to contain the
    // wchar_t string.
    //
    if (s == NULL) {
        return NULL;
    }

    if (d == NULL) {
        // get the right lenght with a NULL dest
        dsize = strlen (s);
        d = new wchar_t[dsize+1];
    }

    wcscpy(d, s);

    return d;

}

bool saveFile(const char *filename, const char *buffer, size_t len, bool binary)
{
	const char *mode = binary ? "wb" : "w" ;

    FILE *f = fopen(filename, "w");

    if(!f)
        return false;

    if (fwrite(buffer, len, sizeof(char), f) != len) {
        fclose(f);
        return false;
    }
    fclose(f);

    return true;
}

bool readFile(const char* path, char **message, size_t *len, bool binary)
{
    FILE *f = NULL;
    size_t msglen=0;
    char *msg=0;
    const char *mode = binary ? "rb" : "r" ;
    struct stat buf;
    bool res = false;

    f = fopen(path, mode);
    if ( !f ) {
        goto done;
    }
    if ( fstat(fileno(f), &buf) ) {
        goto done;
    }

    msglen = buf.st_size;
    msg = new char[msglen+1];
    msg[msglen] = 0;

    *len=fread(msg, sizeof(char), msglen, f);
    if ( ferror(f) || *len < msglen ){
        goto done;
    }

    // Set return parameters
    *message=msg;
    msg = 0;
    res = true;

  done:
    if (f) {
        fclose(f);
    }
    if (msg) {
        delete [] msg;
    }

    return res;
}

// TODO: convert to the specified encoding, assuming wc is UTF-8
char* toMultibyte(const WCHAR *wc, const BCHAR *encoding)
{
    return stringdup(wc);
}

// TODO: convert to UTF-8 from the specified encoding
wchar_t* toWideChar(const char *mb, const BCHAR *encoding)
{
    return stringdup(mb);
}

// Implemented using mkstemp() with a template hard-coded
// to /tmp. Because the API of mkTempFileName() cannot return
// an open file, the file has to be closed. This exposes
// the possibility for an attacker to replace the file
// before it is opened again if /tmp has incorrect permissions.
BCHAR *mkTempFileName(const BCHAR *name)
{
    BCHAR *filename = new BCHAR[strlen("/tmp/") + strlen(name) + strlen(".XXXXXX") + 1];
    int fd;

    sprintf(filename, "/tmp/%s.XXXXXX", name );
    fd = mkstemp(filename);
    if (fd == -1) {
        delete [] filename;
        return NULL;
    } else {
        close(fd);
        return filename;
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 gencache authors
 * This file is released under the MIT License
 * http://opensource.org/licenses/MIT
 */

#include <unicode/normalizer2.h>
#include <unicode/unistr.h>
#ifdef _WIN32
#  define VC_EXTRALEAN
#  define WIN32_LEAN_AND_MEAN
#  ifndef NOMINMAX
#    define NOMINMAX
#  endif
#  include <Windows.h>
#  include "dirent_win.h"
#else
#  include <dirent.h>
#endif
#include <iostream>
#include <fstream>
#include <sstream>
#include <sys/types.h>
#include <sys/stat.h>

#include "json.hpp"

/* legacy mode, linear list */
#define LEGACY 1

using json = nlohmann::json;

const icu::Normalizer2* icu_normalizer;
#ifdef _WIN32
const char* codepage;
#endif

json parse_dir_recursive(const std::string& path, const int depth) {
	DIR *dir;
	struct dirent *dent;
	json r;
	UErrorCode icu_error = U_ZERO_ERROR;

	/* do not recurse any further */
	if(depth == 0)
		return r;

	dir = opendir(path.c_str());
	if(dir != nullptr) {
		while((dent = readdir(dir)) != nullptr) {
			std::string dirname;
			std::string lower_dirname;
			icu::UnicodeString uni_lower_dirname;

			/* unicode aware lowercase conversion */
#ifdef _WIN32
			icu::UnicodeString(dent->d_name, codepage).toUTF8String(dirname);
			uni_lower_dirname = icu::UnicodeString(dent->d_name, codepage).toLower();
#else
			dirname = std::string(dent->d_name);
			uni_lower_dirname = icu::UnicodeString(dent->d_name, "utf-8").toLower();
#endif
			/* normalization */
			icu::UnicodeString normalized_dirname =
				icu_normalizer->normalize(uni_lower_dirname, icu_error);
			if (U_FAILURE(icu_error)) {
				uni_lower_dirname.toUTF8String(lower_dirname);
				std::cerr << "Failed to normalize \"" << lower_dirname << "\"! Using lowercase conversion." << std::endl;
			} else {
				normalized_dirname.toUTF8String(lower_dirname);
			}

			/* dig deeper, but skip upper and current directory */
			if(dent->d_type == DT_DIR && dirname != ".." && dirname != ".") {
				json temp = parse_dir_recursive(path + "/" + dirname, depth - 1);
				if (!temp.empty()) {
#if LEGACY
					for (json::iterator it = temp.begin(); it != temp.end(); ++it) {
						std::string val = it.value();
						std::string key = it.key();
						r[lower_dirname + "/" + key.substr(0, key.find_last_of("."))] = dirname + "/" + val;
					}
#else
					r[lower_dirname] = temp;
#endif
				}
			}

			/* add files */
			if(dent->d_type == DT_REG || dent->d_type == DT_LNK) {
				/* ExFont is a special file in the main directory, needs to be renamed */
				if (lower_dirname.substr(0, lower_dirname.find_last_of(".")) == "exfont")
					lower_dirname = "exfont";

				r[lower_dirname] = dirname;
			}
		}
	}
	closedir(dir);

	return r;
}

int main(int argc, const char* argv[]) {
	struct stat path_info;
	UErrorCode icu_error = U_ZERO_ERROR;

	/* defaults */
	int recursion_depth = 3;
	bool pretty_print = false;
	std::string path = ".";
	std::string output = "index.json";

	/* parse command line arguments */
	for (int i = 1; i < argc; ++i) {
		std::string arg = argv[i];

		if ((arg == "--help") || (arg == "-h")) {
			std::cout << "gencache " PACKAGE_VERSION " - JSON cache generator for EasyRPG Player ports" << std::endl << std::endl;
			std::cout << "Usage: gencache [ Options ] [ Directory ]" << std::endl;
			std::cout << "Options:" << std::endl;
			std::cout << "  -h, --help             This usage message" << std::endl;
			std::cout << "  -p, --pretty           Pretty print the JSON contents" << std::endl;
			std::cout << "  -o, --output <file>    Output file name (default: \"" << output << "\")" << std::endl;
			std::cout << "  -r, --recurse <depth>  Recursion depth (default: " << std::to_string(recursion_depth) << ")" << std::endl << std::endl;
			std::cout << "It uses the current directory if not given as argument." << std::endl;
			return 0;
		} else if((arg == "--pretty") || (arg == "-p")) {
			pretty_print = true;
		} else if((arg == "--output") || (arg == "-o")) {
			if (i + 1 < argc) {
				output = argv[++i];
			} else {
				std::cerr << "--output without file name argument." << std::endl;
				return 1;
			}
		} else if((arg == "--recurse") || (arg == "-r")) {
			if (i + 1 < argc) {
				std::istringstream iss(argv[++i]);
				if (!(iss >> recursion_depth)) {
					std::cerr << "--recurse option needs a number argument." << std::endl;
					return 1;
				}
			} else {
				std::cerr << "--recurse without depth argument." << std::endl;
				return 1;
			}
		} else {
			if (path == ".") {
				if(stat(arg.c_str(), &path_info) != 0) {
					std::cerr << "Cannot access directory: \"" << arg << "\"" << std::endl;
					return 1;
				} else if(!(path_info.st_mode & S_IFDIR)) {
					std::cerr << "Not a directory: \"" << arg << "\"" << std::endl;
					return 1;
				} else {
					path = arg;
				}
			} else {
				std::cerr << "Skipping additional argument: \"" << arg << "\"..." << std::endl;
			}
		}
	}

	icu_normalizer = icu::Normalizer2::getNFKCInstance(icu_error);
	if (U_FAILURE(icu_error)) {
		std::cerr << "Failed to initialize ICU NFKC Normalizer!" << std::endl;
		return 1;
	}

#ifdef _WIN32
	// Will only work when the game has files in the current codepage
	// but should be good enough for the typical use case
	codepage = std::string("cp" + std::to_string(GetACP())).c_str();
#endif

	/* get directory contents */
	json cache = parse_dir_recursive(path, recursion_depth);

	/* write to cache file */
	std::ofstream cache_file;
	cache_file.open(output);
	cache_file << cache.dump(pretty_print ? 2 : -1);
	cache_file.close();
	std::cout << "JSON cache has been written to \"" << output << "\"." << std::endl;

	return 0;
}
<commit_msg>gencache: Let ICU handle codepage selection on Windows<commit_after>/*
 * Copyright (c) 2016 gencache authors
 * This file is released under the MIT License
 * http://opensource.org/licenses/MIT
 */

#include <unicode/normalizer2.h>
#include <unicode/unistr.h>
#ifdef _WIN32
#  define VC_EXTRALEAN
#  define WIN32_LEAN_AND_MEAN
#  define NOMINMAX
#  include <Windows.h>
#  include "dirent_win.h"
#else
#  include <dirent.h>
#endif
#include <iostream>
#include <fstream>
#include <sstream>
#include <sys/types.h>
#include <sys/stat.h>

#include "json.hpp"

/* legacy mode, linear list */
#define LEGACY 1

using json = nlohmann::json;

const icu::Normalizer2* icu_normalizer;

json parse_dir_recursive(const std::string& path, const int depth) {
	DIR *dir;
	struct dirent *dent;
	json r;
	UErrorCode icu_error = U_ZERO_ERROR;

	/* do not recurse any further */
	if(depth == 0)
		return r;

	dir = opendir(path.c_str());
	if(dir != nullptr) {
		while((dent = readdir(dir)) != nullptr) {
			std::string dirname;
			std::string lower_dirname;
			icu::UnicodeString uni_lower_dirname;

			/* unicode aware lowercase conversion */
#ifdef _WIN32
			icu::UnicodeString(dent->d_name).toUTF8String(dirname);
			uni_lower_dirname = icu::UnicodeString(dent->d_name).toLower();
#else
			dirname = std::string(dent->d_name);
			uni_lower_dirname = icu::UnicodeString(dent->d_name, "utf-8").toLower();
#endif
			/* normalization */
			icu::UnicodeString normalized_dirname =
				icu_normalizer->normalize(uni_lower_dirname, icu_error);
			if (U_FAILURE(icu_error)) {
				uni_lower_dirname.toUTF8String(lower_dirname);
				std::cerr << "Failed to normalize \"" << lower_dirname << "\"! Using lowercase conversion." << std::endl;
			} else {
				normalized_dirname.toUTF8String(lower_dirname);
			}

			/* dig deeper, but skip upper and current directory */
			if(dent->d_type == DT_DIR && dirname != ".." && dirname != ".") {
				json temp = parse_dir_recursive(path + "/" + dirname, depth - 1);
				if (!temp.empty()) {
#if LEGACY
					for (json::iterator it = temp.begin(); it != temp.end(); ++it) {
						std::string val = it.value();
						std::string key = it.key();
						r[lower_dirname + "/" + key.substr(0, key.find_last_of("."))] = dirname + "/" + val;
					}
#else
					r[lower_dirname] = temp;
#endif
				}
			}

			/* add files */
			if(dent->d_type == DT_REG || dent->d_type == DT_LNK) {
				/* ExFont is a special file in the main directory, needs to be renamed */
				if (lower_dirname.substr(0, lower_dirname.find_last_of(".")) == "exfont")
					lower_dirname = "exfont";

				r[lower_dirname] = dirname;
			}
		}
	}
	closedir(dir);

	return r;
}

int main(int argc, const char* argv[]) {
	struct stat path_info;
	UErrorCode icu_error = U_ZERO_ERROR;

	/* defaults */
	int recursion_depth = 3;
	bool pretty_print = false;
	std::string path = ".";
	std::string output = "index.json";

	/* parse command line arguments */
	for (int i = 1; i < argc; ++i) {
		std::string arg = argv[i];

		if ((arg == "--help") || (arg == "-h")) {
			std::cout << "gencache " PACKAGE_VERSION " - JSON cache generator for EasyRPG Player ports" << std::endl << std::endl;
			std::cout << "Usage: gencache [ Options ] [ Directory ]" << std::endl;
			std::cout << "Options:" << std::endl;
			std::cout << "  -h, --help             This usage message" << std::endl;
			std::cout << "  -p, --pretty           Pretty print the JSON contents" << std::endl;
			std::cout << "  -o, --output <file>    Output file name (default: \"" << output << "\")" << std::endl;
			std::cout << "  -r, --recurse <depth>  Recursion depth (default: " << std::to_string(recursion_depth) << ")" << std::endl << std::endl;
			std::cout << "It uses the current directory if not given as argument." << std::endl;
			return 0;
		} else if((arg == "--pretty") || (arg == "-p")) {
			pretty_print = true;
		} else if((arg == "--output") || (arg == "-o")) {
			if (i + 1 < argc) {
				output = argv[++i];
			} else {
				std::cerr << "--output without file name argument." << std::endl;
				return 1;
			}
		} else if((arg == "--recurse") || (arg == "-r")) {
			if (i + 1 < argc) {
				std::istringstream iss(argv[++i]);
				if (!(iss >> recursion_depth)) {
					std::cerr << "--recurse option needs a number argument." << std::endl;
					return 1;
				}
			} else {
				std::cerr << "--recurse without depth argument." << std::endl;
				return 1;
			}
		} else {
			if (path == ".") {
				if(stat(arg.c_str(), &path_info) != 0) {
					std::cerr << "Cannot access directory: \"" << arg << "\"" << std::endl;
					return 1;
				} else if(!(path_info.st_mode & S_IFDIR)) {
					std::cerr << "Not a directory: \"" << arg << "\"" << std::endl;
					return 1;
				} else {
					path = arg;
				}
			} else {
				std::cerr << "Skipping additional argument: \"" << arg << "\"..." << std::endl;
			}
		}
	}

	icu_normalizer = icu::Normalizer2::getNFKCInstance(icu_error);
	if (U_FAILURE(icu_error)) {
		std::cerr << "Failed to initialize ICU NFKC Normalizer!" << std::endl;
		return 1;
	}

	/* get directory contents */
	json cache = parse_dir_recursive(path, recursion_depth);

	/* write to cache file */
	std::ofstream cache_file;
	cache_file.open(output);
	cache_file << cache.dump(pretty_print ? 2 : -1);
	cache_file.close();
	std::cout << "JSON cache has been written to \"" << output << "\"." << std::endl;

	return 0;
}
<|endoftext|>


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

#include "libmv/simple_pipeline/uncalibrated_reconstructor.h"

#include <cmath>
#include <cstdio>

#include "libmv/numeric/numeric.h"
#include "libmv/logging/logging.h"
#include "libmv/simple_pipeline/autocalibrate.h"
#include "libmv/simple_pipeline/camera_intrinsics.h"
#include "libmv/simple_pipeline/bundle.h"
#include "libmv/simple_pipeline/initialize_reconstruction.h"
#include "libmv/simple_pipeline/pipeline.h"
#include "libmv/simple_pipeline/reconstruction.h"

namespace libmv {

// Make a matrix to normalize image coordinates for "approximate" calibration.
// This takes the heursitic that the width and height of an image in pixels are
// approximately related to the focal length, and that the center of an image
// is the center of projection.
Mat3 NormalizerMatrix(int width, int height) {
  Mat3 M;
  double s = hypot(width, height);
  M << s, 0, width,
       0, s, height,
       0, 0, 2.0;
  M /= 2.0;
  return M.inverse();
}

// Normalizes a set of tracks according to the normalizer matrix.
void TransformTracks(Mat3 transform, const Tracks &tracks,
                     Tracks *normalized_tracks) {
  vector<Marker> markers = tracks.AllMarkers();
  for (int i = 0; i < markers.size(); ++i) {
    Vec3 a = Vec3(markers[i].x, markers[i].y, 1.0);
    Vec3 b = transform * a;
    markers[i].x = a(0) / a(2);
    markers[i].y = a(1) / a(2);
  }
  *normalized_tracks = Tracks(markers);
}

UncalibratedReconstructor::UncalibratedReconstructor(int width,
                                                     int height,
                                                     int keyframe1,
                                                     int keyframe2,
                                                     const Tracks &tracks) {
  // Save the raw tracks for later use.
  raw_tracks_ = tracks;

  LG << "Normalize all tracks with an approximate calibration.";
  getchar();
  Mat3 normalizer_matrix = NormalizerMatrix(width, height);
  TransformTracks(normalizer_matrix, tracks, &normalized_tracks_);

  LG << "Initialize the reconstruction; bundle (not implemented yet).";
  getchar();
  vector<Marker> initial_markers =
      normalized_tracks_.MarkersForTracksInBothImages(keyframe1, keyframe2);
  ProjectiveReconstructTwoFrames(initial_markers, &projective_reconstruction_);
  CameraIntrinsics default_intrinsics;
  ProjectiveReprojectionError(normalized_tracks_,
                              projective_reconstruction_,
                              default_intrinsics);

  LG << "Complete the projective reconstruction.";
  getchar();
  ReconstructionOptions reconstruction_options;
  reconstruction_options.success_threshold = 1e-3;
  reconstruction_options.use_fallback_reconstruction = true;
  ProjectiveCompleteReconstruction(reconstruction_options, normalized_tracks_, &projective_reconstruction_);
  ProjectiveReprojectionError(normalized_tracks_,
                              projective_reconstruction_,
                              default_intrinsics);

  LG << "Upgrade the reconstruction to Euclidean.";
  getchar();
  UpgradeProjectiveReconstructionToEuclidean(keyframe1,
                                             keyframe2,
                                             projective_reconstruction_,
                                             &euclidean_reconstruction_,
                                             &camera_intrinsics_);

  LG << "Multiply the normalizer matrix into the calibration matrix and "
     << "update the intrinsic parameters.";
  getchar();
  Mat3 K = camera_intrinsics_.K();
  camera_intrinsics_.SetK(K * NormalizerMatrix(width, height).inverse());
  camera_intrinsics_.SetImageSize(width, height);
  LG << "Got K matrix: " << camera_intrinsics_.K();

  LG << "Invert the intrinsics to get calibrated tracks.";
  getchar();
  InvertIntrinsicsForTracks(raw_tracks_,
                            camera_intrinsics_,
                            &calibrated_tracks_);

  LG << "Bundle adjust the final result.";
  getchar();
  EuclideanBundle(calibrated_tracks_, &euclidean_reconstruction_);
}

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

#include "libmv/simple_pipeline/uncalibrated_reconstructor.h"

#include <cmath>
#include <cstdio>

#include "libmv/numeric/numeric.h"
#include "libmv/logging/logging.h"
#include "libmv/simple_pipeline/autocalibrate.h"
#include "libmv/simple_pipeline/camera_intrinsics.h"
#include "libmv/simple_pipeline/bundle.h"
#include "libmv/simple_pipeline/initialize_reconstruction.h"
#include "libmv/simple_pipeline/pipeline.h"
#include "libmv/simple_pipeline/reconstruction.h"

namespace libmv {

// Make a matrix to normalize image coordinates for "approximate" calibration.
// This takes the heursitic that the width and height of an image in pixels are
// approximately related to the focal length, and that the center of an image
// is the center of projection.
Mat3 NormalizerMatrix(int width, int height) {
  Mat3 M;
  double s = hypot(width, height);
  M << s, 0, width,
       0, s, height,
       0, 0, 2.0;
  M /= 2.0;
  return M.inverse();
}

// Normalizes a set of tracks according to the normalizer matrix.
void TransformTracks(Mat3 transform, const Tracks &tracks,
                     Tracks *normalized_tracks) {
  vector<Marker> markers = tracks.AllMarkers();
  for (int i = 0; i < markers.size(); ++i) {
    Vec3 a = Vec3(markers[i].x, markers[i].y, 1.0);
    Vec3 b = transform * a;
    markers[i].x = b(0) / b(2);
    markers[i].y = b(1) / b(2);
  }
  *normalized_tracks = Tracks(markers);
}

UncalibratedReconstructor::UncalibratedReconstructor(int width,
                                                     int height,
                                                     int keyframe1,
                                                     int keyframe2,
                                                     const Tracks &tracks) {
  // Save the raw tracks for later use.
  raw_tracks_ = tracks;

  LG << "Normalize all tracks with an approximate calibration.";
  getchar();
  Mat3 normalizer_matrix = NormalizerMatrix(width, height);
  TransformTracks(normalizer_matrix, tracks, &normalized_tracks_);

  LG << "Initialize the reconstruction; bundle (not implemented yet).";
  getchar();
  vector<Marker> initial_markers =
      normalized_tracks_.MarkersForTracksInBothImages(keyframe1, keyframe2);
  ProjectiveReconstructTwoFrames(initial_markers, &projective_reconstruction_);
  CameraIntrinsics default_intrinsics;
  ProjectiveReprojectionError(normalized_tracks_,
                              projective_reconstruction_,
                              default_intrinsics);

  LG << "Complete the projective reconstruction.";
  getchar();
  ReconstructionOptions reconstruction_options;
  reconstruction_options.success_threshold = 1e-3;
  reconstruction_options.use_fallback_reconstruction = true;
  ProjectiveCompleteReconstruction(reconstruction_options, normalized_tracks_, &projective_reconstruction_);
  ProjectiveReprojectionError(normalized_tracks_,
                              projective_reconstruction_,
                              default_intrinsics);

  LG << "Upgrade the reconstruction to Euclidean.";
  getchar();
  UpgradeProjectiveReconstructionToEuclidean(keyframe1,
                                             keyframe2,
                                             projective_reconstruction_,
                                             &euclidean_reconstruction_,
                                             &camera_intrinsics_);

  LG << "Multiply the normalizer matrix into the calibration matrix and "
     << "update the intrinsic parameters.";
  getchar();
  Mat3 K = camera_intrinsics_.K();
  camera_intrinsics_.SetK(K * NormalizerMatrix(width, height).inverse());
  camera_intrinsics_.SetImageSize(width, height);
  LG << "Got K matrix: " << camera_intrinsics_.K();

  LG << "Invert the intrinsics to get calibrated tracks.";
  getchar();
  InvertIntrinsicsForTracks(raw_tracks_,
                            camera_intrinsics_,
                            &calibrated_tracks_);

  LG << "Bundle adjust the final result.";
  getchar();
  EuclideanBundle(calibrated_tracks_, &euclidean_reconstruction_);
}

}  // namespace libmv
<|endoftext|>


<commit_before>#include "remote.hh"

#include "display_buffer.hh"
#include "debug.hh"
#include "client_manager.hh"
#include "event_manager.hh"
#include "buffer_manager.hh"
#include "command_manager.hh"

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>

namespace Kakoune
{

enum class RemoteUIMsg
{
    PrintStatus,
    MenuShow,
    MenuSelect,
    MenuHide,
    InfoShow,
    InfoHide,
    Draw
};

struct socket_error{};

class Message
{
public:
    Message(int sock) : m_socket(sock) {}
    ~Message()
    {
        if (m_stream.size() == 0)
            return;
        int res = ::write(m_socket, m_stream.data(), m_stream.size());
        if (res == 0)
            throw peer_disconnected{};
    }

    void write(const char* val, size_t size)
    {
        m_stream.insert(m_stream.end(), val, val + size);
    }

    template<typename T>
    void write(const T& val)
    {
        write((const char*)&val, sizeof(val));
    };

    void write(const String& str)
    {
        write(str.length());
        write(str.c_str(), (int)str.length());
    };

    template<typename T>
    void write(const memoryview<T>& view)
    {
        write<uint32_t>(view.size());
        for (auto& val : view)
            write(val);
    };

    template<typename T>
    void write(const std::vector<T>& vec)
    {
        write(memoryview<T>(vec));
    }

    void write(const DisplayAtom& atom)
    {
        write(atom.colors.first);
        write(atom.colors.second);
        write(atom.attribute);
        write(atom.content.content());
    }

    void write(const DisplayLine& line)
    {
        write(line.atoms());
    }

    void write(const DisplayBuffer& display_buffer)
    {
        write(display_buffer.lines());
    }

private:
    std::vector<char> m_stream;
    int m_socket;
};

void read(int socket, char* buffer, size_t size)
{
    while (size)
    {
        int res = ::read(socket, buffer, size);
        if (res == 0)
            throw peer_disconnected{};
        if (res < 0)
            throw socket_error{};

        buffer += res;
        size   -= res;
    }
}

template<typename T>
T read(int socket)
{
    char value[sizeof(T)];
    read(socket, value, sizeof(T));
    return *(T*)(value);
};

template<>
String read<String>(int socket)
{
    ByteCount length = read<ByteCount>(socket);
    if (length == 0)
        return String{};
    char buffer[2048];
    assert(length < 2048);
    read(socket, buffer, (int)length);
    return String(buffer, buffer+(int)length);
};

template<typename T>
std::vector<T> read_vector(int socket)
{
    uint32_t size = read<uint32_t>(socket);
    std::vector<T> res;
    res.reserve(size);
    while (size--)
        res.push_back(read<T>(socket));
    return res;
};

template<>
DisplayAtom read<DisplayAtom>(int socket)
{
    Color fg_color = read<Color>(socket);
    Color bg_color = read<Color>(socket);
    Attribute attribute = read<Attribute>(socket);
    DisplayAtom atom(AtomContent(read<String>(socket)));
    atom.colors = { fg_color, bg_color };
    atom.attribute = attribute;
    return atom;
}
template<>
DisplayLine read<DisplayLine>(int socket)
{
    return DisplayLine(0, read_vector<DisplayAtom>(socket));
}

template<>
DisplayBuffer read<DisplayBuffer>(int socket)
{
    DisplayBuffer db;
    db.lines() = read_vector<DisplayLine>(socket);
    return db;
}

class RemoteUI : public UserInterface
{
public:
    RemoteUI(int socket);
    ~RemoteUI();

    void print_status(const String& status, CharCount cursor_pos) override;

    void menu_show(const memoryview<String>& choices,
                   const DisplayCoord& anchor, MenuStyle style) override;
    void menu_select(int selected) override;
    void menu_hide() override;

    void info_show(const String& content,
                   const DisplayCoord& anchor, MenuStyle style) override;
    void info_hide() override;

    void draw(const DisplayBuffer& display_buffer,
              const String& mode_line) override;

    bool is_key_available() override;
    Key  get_key() override;
    DisplayCoord dimensions() override;

    void set_input_callback(InputCallback callback) override;

private:
    FDWatcher    m_socket_watcher;
    DisplayCoord m_dimensions;
    InputCallback m_input_callback;
};

RemoteUI::RemoteUI(int socket)
    : m_socket_watcher(socket, [this](FDWatcher&) { if (m_input_callback) m_input_callback(); })
{
    write_debug("remote client connected: " + int_to_str(m_socket_watcher.fd()));
}

RemoteUI::~RemoteUI()
{
    write_debug("remote client disconnected: " + int_to_str(m_socket_watcher.fd()));
    close(m_socket_watcher.fd());
}

void RemoteUI::print_status(const String& status, CharCount cursor_pos)
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::PrintStatus);
    msg.write(status);
    msg.write(cursor_pos);
}

void RemoteUI::menu_show(const memoryview<String>& choices,
                         const DisplayCoord& anchor, MenuStyle style)
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::MenuShow);
    msg.write(choices);
    msg.write(anchor);
    msg.write(style);
}

void RemoteUI::menu_select(int selected)
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::MenuSelect);
    msg.write(selected);
}

void RemoteUI::menu_hide()
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::MenuHide);
}

void RemoteUI::info_show(const String& content,
                         const DisplayCoord& anchor, MenuStyle style)
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::InfoShow);
    msg.write(content);
    msg.write(anchor);
    msg.write(style);
}

void RemoteUI::info_hide()
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::InfoHide);
}

void RemoteUI::draw(const DisplayBuffer& display_buffer,
                    const String& mode_line)
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::Draw);
    msg.write(display_buffer);
    msg.write(mode_line);
}

static const Key::Modifiers resize_modifier = (Key::Modifiers)0x80;

bool RemoteUI::is_key_available()
{
    timeval tv;
    fd_set  rfds;

    int sock = m_socket_watcher.fd();
    FD_ZERO(&rfds);
    FD_SET(sock, &rfds);

    tv.tv_sec = 0;
    tv.tv_usec = 0;
    int res = select(sock+1, &rfds, NULL, NULL, &tv);
    return res == 1;
}

Key RemoteUI::get_key()
{
    Key key = read<Key>(m_socket_watcher.fd());
    if (key.modifiers == resize_modifier)
    {
        m_dimensions = { (int)(key.key >> 16), (int)(key.key & 0xFFFF) };
        return Key::Invalid;
    }
    return key;
}

DisplayCoord RemoteUI::dimensions()
{
    return m_dimensions;
}

void RemoteUI::set_input_callback(InputCallback callback)
{
    m_input_callback = std::move(callback);
}

RemoteClient::RemoteClient(int socket, std::unique_ptr<UserInterface>&& ui,
                           const String& init_command)
    : m_ui(std::move(ui)), m_dimensions(m_ui->dimensions()),
      m_socket_watcher{socket, [this](FDWatcher&){ process_next_message(); }}
{
    Message msg(socket);
    msg.write(init_command.c_str(), (int)init_command.length()+1);
    Key key{ resize_modifier, Codepoint(((int)m_dimensions.line << 16) | (int)m_dimensions.column) };
    msg.write(key);

    m_ui->set_input_callback([this]{ write_next_key(); });
}

void RemoteClient::process_next_message()
{
    int socket = m_socket_watcher.fd();
    RemoteUIMsg msg = read<RemoteUIMsg>(socket);
    switch (msg)
    {
    case RemoteUIMsg::PrintStatus:
    {
        auto status = read<String>(socket);
        auto cursor_pos = read<CharCount>(socket);
        m_ui->print_status(status, cursor_pos);
        break;
    }
    case RemoteUIMsg::MenuShow:
    {
        auto choices = read_vector<String>(socket);
        auto anchor = read<DisplayCoord>(socket);
        auto style = read<MenuStyle>(socket);
        m_ui->menu_show(choices, anchor, style);
        break;
    }
    case RemoteUIMsg::MenuSelect:
        m_ui->menu_select(read<int>(socket));
        break;
    case RemoteUIMsg::MenuHide:
        m_ui->menu_hide();
        break;
    case RemoteUIMsg::InfoShow:
    {
        auto choices = read<String>(socket);
        auto anchor = read<DisplayCoord>(socket);
        auto style = read<MenuStyle>(socket);
        m_ui->info_show(choices, anchor, style);
        break;
    }
    case RemoteUIMsg::InfoHide:
        m_ui->info_hide();
        break;
    case RemoteUIMsg::Draw:
    {
        DisplayBuffer display_buffer = read<DisplayBuffer>(socket);
        String mode_line = read<String>(socket);
        m_ui->draw(display_buffer, mode_line);
        break;
    }
    }
}

void RemoteClient::write_next_key()
{
    Message msg(m_socket_watcher.fd());
    // do that before checking dimensions as get_key may
    // handle a resize event.
    msg.write(m_ui->get_key());

    DisplayCoord dimensions = m_ui->dimensions();
    if (dimensions != m_dimensions)
    {
        m_dimensions = dimensions;
        Key key{ resize_modifier, Codepoint(((int)dimensions.line << 16) | (int)dimensions.column) };
        msg.write(key);
    }
}

std::unique_ptr<RemoteClient> connect_to(const String& pid, std::unique_ptr<UserInterface>&& ui,
                                         const String& init_command)
{
    auto filename = "/tmp/kak-" + pid;

    int sock = socket(AF_UNIX, SOCK_STREAM, 0);
    fcntl(sock, F_SETFD, FD_CLOEXEC);
    sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, filename.c_str(), sizeof(addr.sun_path) - 1);
    if (connect(sock, (sockaddr*)&addr, sizeof(addr.sun_path)) == -1)
        throw runtime_error("connect to " + filename + " failed");

    return std::unique_ptr<RemoteClient>{new RemoteClient{sock, std::move(ui), init_command}};
}

// A client accepter handle a connection until it closes or a nul byte is
// recieved. Everything recieved before is considered to be a command.
//
// * When a nul byte is recieved, the socket is handed to a new Client along
//   with the command.
// * When the connection is closed, the command is run in an empty context.
class ClientAccepter
{
public:
    ClientAccepter(int socket)
        : m_socket_watcher(socket, [this](FDWatcher&) { handle_available_input(); }) {}

private:
    void handle_available_input()
    {
        int socket = m_socket_watcher.fd();
        timeval tv{ 0, 0 };
        fd_set  rfds;
        do
        {
            char c;
            int res = ::read(socket, &c, 1);
            if (res <= 0)
            {
                if (not m_buffer.empty()) try
                {
                    Context context{};
                    CommandManager::instance().execute(m_buffer, context);
                }
                catch (runtime_error& e)
                {
                    write_debug("error running command '" + m_buffer + "' : " + e.description());
                }
                ClientManager::instance().redraw_clients();
                delete this;
                return;
            }
            if (c == 0) // end of initial command stream, go to interactive ui mode
            {
                ClientManager::instance().create_client(
                    std::unique_ptr<UserInterface>{new RemoteUI{socket}}, m_buffer);
                delete this;
                return;
            }
            else
                m_buffer += c;

            FD_ZERO(&rfds);
            FD_SET(socket, &rfds);
        }
        while (select(socket+1, &rfds, NULL, NULL, &tv) == 1);
    }

    String    m_buffer;
    FDWatcher m_socket_watcher;
};

Server::Server()
    : m_filename{"/tmp/kak-" + int_to_str(getpid())}
{
    int listen_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    fcntl(listen_sock, F_SETFD, FD_CLOEXEC);
    sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, m_filename.c_str(), sizeof(addr.sun_path) - 1);

    if (bind(listen_sock, (sockaddr*) &addr, sizeof(sockaddr_un)) == -1)
       throw runtime_error("unable to bind listen socket " + m_filename);

    if (listen(listen_sock, 4) == -1)
       throw runtime_error("unable to listen on socket " + m_filename);

    auto accepter = [](FDWatcher& watcher) {
        sockaddr_un client_addr;
        socklen_t   client_addr_len = sizeof(sockaddr_un);
        int sock = accept(watcher.fd(), (sockaddr*) &client_addr, &client_addr_len);
        if (sock == -1)
            throw runtime_error("accept failed");
        fcntl(sock, F_SETFD, FD_CLOEXEC);

        new ClientAccepter{sock};
    };
    m_listener.reset(new FDWatcher{listen_sock, accepter});
}

Server::~Server()
{
    unlink(m_filename.c_str());
    close(m_listener->fd());
}

}
<commit_msg>ConnectionAccepter: fix socket fd leak<commit_after>#include "remote.hh"

#include "display_buffer.hh"
#include "debug.hh"
#include "client_manager.hh"
#include "event_manager.hh"
#include "buffer_manager.hh"
#include "command_manager.hh"

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>

namespace Kakoune
{

enum class RemoteUIMsg
{
    PrintStatus,
    MenuShow,
    MenuSelect,
    MenuHide,
    InfoShow,
    InfoHide,
    Draw
};

struct socket_error{};

class Message
{
public:
    Message(int sock) : m_socket(sock) {}
    ~Message()
    {
        if (m_stream.size() == 0)
            return;
        int res = ::write(m_socket, m_stream.data(), m_stream.size());
        if (res == 0)
            throw peer_disconnected{};
    }

    void write(const char* val, size_t size)
    {
        m_stream.insert(m_stream.end(), val, val + size);
    }

    template<typename T>
    void write(const T& val)
    {
        write((const char*)&val, sizeof(val));
    };

    void write(const String& str)
    {
        write(str.length());
        write(str.c_str(), (int)str.length());
    };

    template<typename T>
    void write(const memoryview<T>& view)
    {
        write<uint32_t>(view.size());
        for (auto& val : view)
            write(val);
    };

    template<typename T>
    void write(const std::vector<T>& vec)
    {
        write(memoryview<T>(vec));
    }

    void write(const DisplayAtom& atom)
    {
        write(atom.colors.first);
        write(atom.colors.second);
        write(atom.attribute);
        write(atom.content.content());
    }

    void write(const DisplayLine& line)
    {
        write(line.atoms());
    }

    void write(const DisplayBuffer& display_buffer)
    {
        write(display_buffer.lines());
    }

private:
    std::vector<char> m_stream;
    int m_socket;
};

void read(int socket, char* buffer, size_t size)
{
    while (size)
    {
        int res = ::read(socket, buffer, size);
        if (res == 0)
            throw peer_disconnected{};
        if (res < 0)
            throw socket_error{};

        buffer += res;
        size   -= res;
    }
}

template<typename T>
T read(int socket)
{
    char value[sizeof(T)];
    read(socket, value, sizeof(T));
    return *(T*)(value);
};

template<>
String read<String>(int socket)
{
    ByteCount length = read<ByteCount>(socket);
    if (length == 0)
        return String{};
    char buffer[2048];
    assert(length < 2048);
    read(socket, buffer, (int)length);
    return String(buffer, buffer+(int)length);
};

template<typename T>
std::vector<T> read_vector(int socket)
{
    uint32_t size = read<uint32_t>(socket);
    std::vector<T> res;
    res.reserve(size);
    while (size--)
        res.push_back(read<T>(socket));
    return res;
};

template<>
DisplayAtom read<DisplayAtom>(int socket)
{
    Color fg_color = read<Color>(socket);
    Color bg_color = read<Color>(socket);
    Attribute attribute = read<Attribute>(socket);
    DisplayAtom atom(AtomContent(read<String>(socket)));
    atom.colors = { fg_color, bg_color };
    atom.attribute = attribute;
    return atom;
}
template<>
DisplayLine read<DisplayLine>(int socket)
{
    return DisplayLine(0, read_vector<DisplayAtom>(socket));
}

template<>
DisplayBuffer read<DisplayBuffer>(int socket)
{
    DisplayBuffer db;
    db.lines() = read_vector<DisplayLine>(socket);
    return db;
}

class RemoteUI : public UserInterface
{
public:
    RemoteUI(int socket);
    ~RemoteUI();

    void print_status(const String& status, CharCount cursor_pos) override;

    void menu_show(const memoryview<String>& choices,
                   const DisplayCoord& anchor, MenuStyle style) override;
    void menu_select(int selected) override;
    void menu_hide() override;

    void info_show(const String& content,
                   const DisplayCoord& anchor, MenuStyle style) override;
    void info_hide() override;

    void draw(const DisplayBuffer& display_buffer,
              const String& mode_line) override;

    bool is_key_available() override;
    Key  get_key() override;
    DisplayCoord dimensions() override;

    void set_input_callback(InputCallback callback) override;

private:
    FDWatcher    m_socket_watcher;
    DisplayCoord m_dimensions;
    InputCallback m_input_callback;
};

RemoteUI::RemoteUI(int socket)
    : m_socket_watcher(socket, [this](FDWatcher&) { if (m_input_callback) m_input_callback(); })
{
    write_debug("remote client connected: " + int_to_str(m_socket_watcher.fd()));
}

RemoteUI::~RemoteUI()
{
    write_debug("remote client disconnected: " + int_to_str(m_socket_watcher.fd()));
    close(m_socket_watcher.fd());
}

void RemoteUI::print_status(const String& status, CharCount cursor_pos)
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::PrintStatus);
    msg.write(status);
    msg.write(cursor_pos);
}

void RemoteUI::menu_show(const memoryview<String>& choices,
                         const DisplayCoord& anchor, MenuStyle style)
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::MenuShow);
    msg.write(choices);
    msg.write(anchor);
    msg.write(style);
}

void RemoteUI::menu_select(int selected)
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::MenuSelect);
    msg.write(selected);
}

void RemoteUI::menu_hide()
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::MenuHide);
}

void RemoteUI::info_show(const String& content,
                         const DisplayCoord& anchor, MenuStyle style)
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::InfoShow);
    msg.write(content);
    msg.write(anchor);
    msg.write(style);
}

void RemoteUI::info_hide()
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::InfoHide);
}

void RemoteUI::draw(const DisplayBuffer& display_buffer,
                    const String& mode_line)
{
    Message msg(m_socket_watcher.fd());
    msg.write(RemoteUIMsg::Draw);
    msg.write(display_buffer);
    msg.write(mode_line);
}

static const Key::Modifiers resize_modifier = (Key::Modifiers)0x80;

bool RemoteUI::is_key_available()
{
    timeval tv;
    fd_set  rfds;

    int sock = m_socket_watcher.fd();
    FD_ZERO(&rfds);
    FD_SET(sock, &rfds);

    tv.tv_sec = 0;
    tv.tv_usec = 0;
    int res = select(sock+1, &rfds, NULL, NULL, &tv);
    return res == 1;
}

Key RemoteUI::get_key()
{
    Key key = read<Key>(m_socket_watcher.fd());
    if (key.modifiers == resize_modifier)
    {
        m_dimensions = { (int)(key.key >> 16), (int)(key.key & 0xFFFF) };
        return Key::Invalid;
    }
    return key;
}

DisplayCoord RemoteUI::dimensions()
{
    return m_dimensions;
}

void RemoteUI::set_input_callback(InputCallback callback)
{
    m_input_callback = std::move(callback);
}

RemoteClient::RemoteClient(int socket, std::unique_ptr<UserInterface>&& ui,
                           const String& init_command)
    : m_ui(std::move(ui)), m_dimensions(m_ui->dimensions()),
      m_socket_watcher{socket, [this](FDWatcher&){ process_next_message(); }}
{
    Message msg(socket);
    msg.write(init_command.c_str(), (int)init_command.length()+1);
    Key key{ resize_modifier, Codepoint(((int)m_dimensions.line << 16) | (int)m_dimensions.column) };
    msg.write(key);

    m_ui->set_input_callback([this]{ write_next_key(); });
}

void RemoteClient::process_next_message()
{
    int socket = m_socket_watcher.fd();
    RemoteUIMsg msg = read<RemoteUIMsg>(socket);
    switch (msg)
    {
    case RemoteUIMsg::PrintStatus:
    {
        auto status = read<String>(socket);
        auto cursor_pos = read<CharCount>(socket);
        m_ui->print_status(status, cursor_pos);
        break;
    }
    case RemoteUIMsg::MenuShow:
    {
        auto choices = read_vector<String>(socket);
        auto anchor = read<DisplayCoord>(socket);
        auto style = read<MenuStyle>(socket);
        m_ui->menu_show(choices, anchor, style);
        break;
    }
    case RemoteUIMsg::MenuSelect:
        m_ui->menu_select(read<int>(socket));
        break;
    case RemoteUIMsg::MenuHide:
        m_ui->menu_hide();
        break;
    case RemoteUIMsg::InfoShow:
    {
        auto choices = read<String>(socket);
        auto anchor = read<DisplayCoord>(socket);
        auto style = read<MenuStyle>(socket);
        m_ui->info_show(choices, anchor, style);
        break;
    }
    case RemoteUIMsg::InfoHide:
        m_ui->info_hide();
        break;
    case RemoteUIMsg::Draw:
    {
        DisplayBuffer display_buffer = read<DisplayBuffer>(socket);
        String mode_line = read<String>(socket);
        m_ui->draw(display_buffer, mode_line);
        break;
    }
    }
}

void RemoteClient::write_next_key()
{
    Message msg(m_socket_watcher.fd());
    // do that before checking dimensions as get_key may
    // handle a resize event.
    msg.write(m_ui->get_key());

    DisplayCoord dimensions = m_ui->dimensions();
    if (dimensions != m_dimensions)
    {
        m_dimensions = dimensions;
        Key key{ resize_modifier, Codepoint(((int)dimensions.line << 16) | (int)dimensions.column) };
        msg.write(key);
    }
}

std::unique_ptr<RemoteClient> connect_to(const String& pid, std::unique_ptr<UserInterface>&& ui,
                                         const String& init_command)
{
    auto filename = "/tmp/kak-" + pid;

    int sock = socket(AF_UNIX, SOCK_STREAM, 0);
    fcntl(sock, F_SETFD, FD_CLOEXEC);
    sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, filename.c_str(), sizeof(addr.sun_path) - 1);
    if (connect(sock, (sockaddr*)&addr, sizeof(addr.sun_path)) == -1)
        throw runtime_error("connect to " + filename + " failed");

    return std::unique_ptr<RemoteClient>{new RemoteClient{sock, std::move(ui), init_command}};
}

// A client accepter handle a connection until it closes or a nul byte is
// recieved. Everything recieved before is considered to be a command.
//
// * When a nul byte is recieved, the socket is handed to a new Client along
//   with the command.
// * When the connection is closed, the command is run in an empty context.
class ClientAccepter
{
public:
    ClientAccepter(int socket)
        : m_socket_watcher(socket, [this](FDWatcher&) { handle_available_input(); }) {}

private:
    void handle_available_input()
    {
        int socket = m_socket_watcher.fd();
        timeval tv{ 0, 0 };
        fd_set  rfds;
        do
        {
            char c;
            int res = ::read(socket, &c, 1);
            if (res <= 0)
            {
                if (not m_buffer.empty()) try
                {
                    Context context{};
                    CommandManager::instance().execute(m_buffer, context);
                }
                catch (runtime_error& e)
                {
                    write_debug("error running command '" + m_buffer + "' : " + e.description());
                }
                ClientManager::instance().redraw_clients();
                close(socket);
                delete this;
                return;
            }
            if (c == 0) // end of initial command stream, go to interactive ui mode
            {
                ClientManager::instance().create_client(
                    std::unique_ptr<UserInterface>{new RemoteUI{socket}}, m_buffer);
                delete this;
                return;
            }
            else
                m_buffer += c;

            FD_ZERO(&rfds);
            FD_SET(socket, &rfds);
        }
        while (select(socket+1, &rfds, NULL, NULL, &tv) == 1);
    }

    String    m_buffer;
    FDWatcher m_socket_watcher;
};

Server::Server()
    : m_filename{"/tmp/kak-" + int_to_str(getpid())}
{
    int listen_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    fcntl(listen_sock, F_SETFD, FD_CLOEXEC);
    sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, m_filename.c_str(), sizeof(addr.sun_path) - 1);

    if (bind(listen_sock, (sockaddr*) &addr, sizeof(sockaddr_un)) == -1)
       throw runtime_error("unable to bind listen socket " + m_filename);

    if (listen(listen_sock, 4) == -1)
       throw runtime_error("unable to listen on socket " + m_filename);

    auto accepter = [](FDWatcher& watcher) {
        sockaddr_un client_addr;
        socklen_t   client_addr_len = sizeof(sockaddr_un);
        int sock = accept(watcher.fd(), (sockaddr*) &client_addr, &client_addr_len);
        if (sock == -1)
            throw runtime_error("accept failed");
        fcntl(sock, F_SETFD, FD_CLOEXEC);

        new ClientAccepter{sock};
    };
    m_listener.reset(new FDWatcher{listen_sock, accepter});
}

Server::~Server()
{
    unlink(m_filename.c_str());
    close(m_listener->fd());
}

}
<|endoftext|>