<commit_before>/* Copyright (C) 2012, dark_skeleton (d-rez) <dark.skeleton@gmail.com>

   All rights reserved.

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

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

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

#include "../mumble_plugin_win32.h"

static BYTE *posptr;
static BYTE *camptr;
static BYTE *camfrontptr;
static BYTE *camtopptr;
static BYTE *afrontptr;
static BYTE *atopptr;

static BYTE *hostipptr;
static BYTE *hostportptr;
static BYTE *summonerptr;

static BYTE *gameptr;

static char prev_hostip[16]; // These should never change while the game is running, but just in case...
static int prev_hostport;
static char prev_summoner[17];

static bool calcout(float *pos, float *cam, float *opos, float *ocam) {
	// Seems League of Legends is in centimeters? ;o Well it's not inches for sure :)
	for (int i = 0; i < 3; i++) {
		opos[i] = pos[i] / 100.00f;
		ocam[i] = cam[i] / 100.00f;
	}

	return true;
}

static bool refreshPointers(void) {
	/* Arrays of bytes to find addresses accessed by respective functions so we don't have to blindly search for addresses after every update
	Remember to disable scanning writable memory only in CE! We're searching for functions here, not values!
	Current addresses as of version 1.0.0.142

	Camera position vector address: F3 0F 11 03 F3 0F 10 44 24 14 D9 5C 24 28			:00B4B858
	Camera front vector address: campos+0x14 (offset, not pointer!)
	Camera top vector address: campos+0x20 (offset, not pointer!)

	D9 5F 40 D9 46 04 D9 5F 44 D9 46 08 D9 5F 48 59 C3 CC (non-static! NEEDS POINTER)	:00DFA4E8
	Avatar front vector address: 		+0x2ab4
	Avatar top vector address: 		+0x2ac0

	D9 9E E8 01 00 00 D9 40 70 D9 9E EC 01 00 00 D9 40 74 D9 9E F0 01 00 00				:02F2DE68
	Avatar position vector address:		+0x1e8

	IP: Look for a non-unicode string that will contain server's IP. 28 bytes further from IP, there should be server's port
																						:0AF395B8
	PORT:					+0x1C (offset, not pointer!)
	IDENTITY: Just look for your nickname saved in non-unicode that is static. Length is  16
																						:0AF3957C
	*/

	posptr = camptr = camfrontptr = camtopptr = afrontptr = atopptr = NULL;

	// Camera position
	camptr = (BYTE *)0xB4B858;

	// Camera front
	camfrontptr = camptr + 0x14;

	// Camera top
	camtopptr = camptr + 0x20;

	// Avatar front vector pointer
	BYTE *tmpptr = NULL;
	gameptr = (BYTE *)0xDFA4E8;
	tmpptr = peekProc<BYTE *>(gameptr);

	if (!tmpptr)
		return false;				// Something went wrong, unlink

	afrontptr = tmpptr + 0x2ab4;
	atopptr = tmpptr + 0x2ac0;

	// Avatar position vector
	tmpptr = peekProc<BYTE *>((BYTE *)0x2F2DE68);
	if (!tmpptr)
		return false;				// Something went wrong, unlink

	posptr = tmpptr + 0x1e8;

	// Host IP:PORT. It is kept in 3 places in memory, but 1 of them looks the coolest, so let's use it, ha!
	// IP is kept as text @ hostipptr
	// PORT is kept as a 4-byte decimal value @ hostportptr

	hostipptr = (BYTE *)0xAF395B8;
	hostportptr = hostipptr + 0x1C;

	summonerptr = (BYTE *)0xAF3957C;

	return true;
}

static int fetch(float *avatar_pos, float *avatar_front, float *avatar_top, float *camera_pos, float *camera_front, float *camera_top, std::string &context, std::wstring &identity) {
	for (int i = 0; i < 3; i++)
		avatar_pos[i] = avatar_front[i] = avatar_top[i] = camera_pos[i] = camera_front[i] = camera_top[i] = 0.0f;

	float ipos[3], cam[3];
	int hostport;
	char hostip[16];
	char summoner[17];
	bool ok;

	// Player not in game (or something broke), unlink
	if (!peekProc<BYTE *>(gameptr))
		return false;

	ok = peekProc(camfrontptr, camera_front, 12) &&
		 peekProc(camtopptr, camera_top, 12) &&
		 peekProc(camptr, cam, 12) &&
		 peekProc(posptr, ipos, 12) &&
		 peekProc(afrontptr, avatar_front, 12) &&
		 peekProc(atopptr, avatar_top, 12) &&
		 peekProc(hostipptr, hostip) &&
		 peekProc(hostportptr, &hostport, 4) &&
		 peekProc(summonerptr, summoner);

	if (ok) {
		int res = calcout(ipos, cam, avatar_pos, camera_pos);
		if (res) {
			if (strcmp(hostip, prev_hostip) != 0 || hostport != prev_hostport) {
				context.clear();
				memcpy(prev_hostip, hostip, 16);
				prev_hostport = hostport;

				if (strcmp(hostip, "") != 0) {
					char buffer[50];
					sprintf_s(buffer, 50, "{\"ipport\": \"%s:%d\"}", hostip, hostport);
					context.assign(buffer);
				}
			}
			if (strcmp(summoner, prev_summoner) != 0) {
				identity.clear();
				memcpy(prev_summoner,summoner,17);

				if (strcmp(summoner, "") != 0) {
					wchar_t tmp[sizeof(summoner)];
					mbstowcs_s(NULL,tmp,summoner,sizeof(summoner));
					wchar_t buffer[50];
					swprintf_s(buffer, 50, L"{\"summoner\": \"%s\"}", tmp);
					identity.assign(buffer);
				}
			}
		}
		return res;
	}

	return false;
}

static int trylock(const std::multimap<std::wstring, unsigned long long int> &pids) {
	if (! initialize(pids, L"League of Legends.exe"))
		return false;

	float pos[3], opos[3];
	float cam[3], ocam[3];

	// unlink plugin if this fails
	if (!refreshPointers()) {
		generic_unlock();
		return false;
	}

	if (calcout(pos,cam,opos,ocam)) { // make sure values are OK
		*prev_hostip = '\0';
		prev_hostport = 0;
		*prev_summoner = '\0';
		return true;
	}

	generic_unlock();
	return false;
}

static const std::wstring longdesc() {
	return std::wstring(L"Supports League of Legends v1.0.0.142 with context and identity support.");
}

static std::wstring description(L"League of Legends (v1.0.0.142)");
static std::wstring shortname(L"League of Legends");

static int trylock1() {
	return trylock(std::multimap<std::wstring, unsigned long long int>());
}

static MumblePlugin lolplug = {
	MUMBLE_PLUGIN_MAGIC,
	description,
	shortname,
	NULL,
	NULL,
	trylock1,
	generic_unlock,
	longdesc,
	fetch
};

static MumblePlugin2 lolplug2 = {
	MUMBLE_PLUGIN_MAGIC_2,
	MUMBLE_PLUGIN_VERSION,
	trylock
};

extern "C" __declspec(dllexport) MumblePlugin *getMumblePlugin() {
	return &lolplug;
}

extern "C" __declspec(dllexport) MumblePlugin2 *getMumblePlugin2() {
	return &lolplug2;
}
<commit_msg>Minor modifications for lol plugin.<commit_after>/* Copyright (C) 2012, dark_skeleton (d-rez) <dark.skeleton@gmail.com>
   Copyright (C) 2005-2012, Thorvald Natvig <thorvald@natvig.com>

   All rights reserved.

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

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

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

#include "../mumble_plugin_win32.h"

static BYTE *posptr;
static BYTE *camptr;
static BYTE *camfrontptr;
static BYTE *camtopptr;
static BYTE *afrontptr;
static BYTE *atopptr;

static BYTE *hostipptr;
static BYTE *hostportptr;
static BYTE *summonerptr;

static BYTE *gameptr;

static char prev_hostip[16]; // These should never change while the game is running, but just in case...
static int prev_hostport;
static char prev_summoner[17];

static bool calcout(float *pos, float *cam, float *opos, float *ocam) {
	// Seems League of Legends is in centimeters? ;o Well it's not inches for sure :)
	for (int i = 0; i < 3; i++) {
		opos[i] = pos[i] / 100.00f;
		ocam[i] = cam[i] / 100.00f;
	}

	return true;
}

static bool refreshPointers(void) {
	/* Arrays of bytes to find addresses accessed by respective functions so we don't have to blindly search for addresses after every update
	Remember to disable scanning writable memory only in CE! We're searching for functions here, not values!
	Current addresses as of version 1.0.0.142

	Camera position vector address: F3 0F 11 03 F3 0F 10 44 24 14 D9 5C 24 28			:00B4B858
	Camera front vector address: campos+0x14 (offset, not pointer!)
	Camera top vector address: campos+0x20 (offset, not pointer!)

	D9 5F 40 D9 46 04 D9 5F 44 D9 46 08 D9 5F 48 59 C3 CC (non-static! NEEDS POINTER)	:00DFA4E8
	Avatar front vector address: 		+0x2ab4
	Avatar top vector address: 		+0x2ac0

	D9 9E E8 01 00 00 D9 40 70 D9 9E EC 01 00 00 D9 40 74 D9 9E F0 01 00 00				:02F2DE68
	Avatar position vector address:		+0x1e8

	IP: Look for a non-unicode string that will contain server's IP. 28 bytes further from IP, there should be server's port
																						:0AF395B8
	PORT:					+0x1C (offset, not pointer!)
	IDENTITY: Just look for your nickname saved in non-unicode that is static. Length is  16
																						:0AF3957C
	*/

	posptr = camptr = camfrontptr = camtopptr = afrontptr = atopptr = NULL;

	// Camera position
	camptr = (BYTE *)0xB4B858;

	// Camera front
	camfrontptr = camptr + 0x14;

	// Camera top
	camtopptr = camptr + 0x20;

	// Avatar front vector pointer
	BYTE *tmpptr = NULL;
	gameptr = (BYTE *)0xDFA4E8;
	tmpptr = peekProc<BYTE *>(gameptr);

	if (!tmpptr)
		return false;				// Something went wrong, unlink

	afrontptr = tmpptr + 0x2ab4;
	atopptr = tmpptr + 0x2ac0;

	// Avatar position vector
	tmpptr = peekProc<BYTE *>((BYTE *)0x2F2DE68);
	if (!tmpptr)
		return false;				// Something went wrong, unlink

	posptr = tmpptr + 0x1e8;

	// Host IP:PORT. It is kept in 3 places in memory, but 1 of them looks the coolest, so let's use it, ha!
	// IP is kept as text @ hostipptr
	// PORT is kept as a 4-byte decimal value @ hostportptr

	hostipptr = (BYTE *)0xAF395B8;
	hostportptr = hostipptr + 0x1C;

	summonerptr = (BYTE *)0xAF3957C;

	return true;
}

static int fetch(float *avatar_pos, float *avatar_front, float *avatar_top, float *camera_pos, float *camera_front, float *camera_top, std::string &context, std::wstring &identity) {
	for (int i = 0; i < 3; i++)
		avatar_pos[i] = avatar_front[i] = avatar_top[i] = camera_pos[i] = camera_front[i] = camera_top[i] = 0.0f;

	float ipos[3], cam[3];
	int hostport;
	char hostip[16];
	char summoner[17];
	bool ok;

	// Player not in game (or something broke), unlink
	if (!peekProc<BYTE *>(gameptr))
		return false;

	ok = peekProc(camfrontptr, camera_front, 12) &&
		 peekProc(camtopptr, camera_top, 12) &&
		 peekProc(camptr, cam, 12) &&
		 peekProc(posptr, ipos, 12) &&
		 peekProc(afrontptr, avatar_front, 12) &&
		 peekProc(atopptr, avatar_top, 12) &&
		 peekProc(hostipptr, hostip) &&
		 peekProc(hostportptr, &hostport, 4) &&
		 peekProc(summonerptr, summoner);

	if (ok) {
		// Ensure strings are zero terminated
		summoner[sizeof(summoner) - 1] = '\0';
		hostip[sizeof(hostip) - 1] = '\0';

		int res = calcout(ipos, cam, avatar_pos, camera_pos);
		if (res) {
			if (strcmp(hostip, prev_hostip) != 0 || hostport != prev_hostport) {
				context.clear();

				strcpy_s(prev_hostip, sizeof(prev_hostip), hostip);
				prev_hostport = hostport;

				if (strcmp(hostip, "") != 0) {
					char buffer[50];
					sprintf_s(buffer, sizeof(buffer), "{\"ipport\": \"%s:%d\"}", hostip, hostport);
					context.assign(buffer);
				}
			}
			if (strcmp(summoner, prev_summoner) != 0) {
				identity.clear();

				strcpy_s(prev_summoner, sizeof(prev_summoner), summoner);

				if (strcmp(summoner, "") != 0) {
					wchar_t tmp[sizeof(summoner)];
					mbstowcs_s(NULL, tmp, summoner, sizeof(summoner));
					wchar_t buffer[50];
					swprintf_s(buffer, 50, L"{\"summoner\": \"%s\"}", tmp);
					identity.assign(buffer);
				}
			}
		}
		return res;
	}

	return false;
}

static int trylock(const std::multimap<std::wstring, unsigned long long int> &pids) {
	if (! initialize(pids, L"League of Legends.exe"))
		return false;

	float pos[3], opos[3];
	float cam[3], ocam[3];

	// unlink plugin if this fails
	if (!refreshPointers()) {
		generic_unlock();
		return false;
	}

	if (calcout(pos, cam, opos, ocam)) { // make sure values are OK
		*prev_hostip = '\0';
		prev_hostport = 0;
		*prev_summoner = '\0';
		return true;
	}

	generic_unlock();
	return false;
}

static const std::wstring longdesc() {
	return std::wstring(L"Supports League of Legends v1.0.0.142 with context and identity support.");
}

static std::wstring description(L"League of Legends (v1.0.0.142)");
static std::wstring shortname(L"League of Legends");

static int trylock1() {
	return trylock(std::multimap<std::wstring, unsigned long long int>());
}

static MumblePlugin lolplug = {
	MUMBLE_PLUGIN_MAGIC,
	description,
	shortname,
	NULL,
	NULL,
	trylock1,
	generic_unlock,
	longdesc,
	fetch
};

static MumblePlugin2 lolplug2 = {
	MUMBLE_PLUGIN_MAGIC_2,
	MUMBLE_PLUGIN_VERSION,
	trylock
};

extern "C" __declspec(dllexport) MumblePlugin *getMumblePlugin() {
	return &lolplug;
}

extern "C" __declspec(dllexport) MumblePlugin2 *getMumblePlugin2() {
	return &lolplug2;
}
<|endoftext|>


<commit_before>#define ENABLE_PREMATURE_CLOSE_HEADERS
#define ENABLE_PREMATURE_CLOSE_BODY
#define NO_EARLY_RELEASE_SOCKET // TODO: improve the AJP client

#include "tio.hxx"
#include "t_client.hxx"
#include "ajp_server.hxx"
#include "ajp/ajp_client.hxx"
#include "http_response.hxx"
#include "async.hxx"
#include "system/SetupProcess.hxx"
#include "system/fd-util.h"
#include "system/fd_util.h"
#include "growing_buffer.hxx"
#include "header_writer.hxx"
#include "lease.hxx"
#include "direct.hxx"
#include "istream/istream.hxx"
#include "strmap.hxx"
#include "RootPool.hxx"
#include "fb_pool.hxx"
#include "event/Event.hxx"
#include "util/ByteOrder.hxx"

#include <inline/compiler.h>

#include <sys/wait.h>

static void
ajp_server_null(struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);

    if (request.code != AJP_CODE_FORWARD_REQUEST)
        exit(EXIT_FAILURE);

    write_headers(HTTP_STATUS_NO_CONTENT, nullptr);
    write_end();
}

static void
ajp_server_hello(struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);

    if (request.code != AJP_CODE_FORWARD_REQUEST)
        exit(EXIT_FAILURE);

    write_headers(HTTP_STATUS_OK, nullptr);
    write_body_chunk("hello", 5, 0);
    write_end();
}

static void
ajp_server_tiny(struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);

    if (request.code != AJP_CODE_FORWARD_REQUEST)
        exit(EXIT_FAILURE);

    auto *headers = strmap_new(pool);
    headers->Add("content-length", "5");

    write_headers(HTTP_STATUS_OK, headers);
    write_body_chunk("hello", 5, 0);
    write_end();
}

static void
ajp_server_mirror(struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);

    if (request.code != AJP_CODE_FORWARD_REQUEST)
        exit(EXIT_FAILURE);

    http_status_t status = request.length == 0
        ? HTTP_STATUS_NO_CONTENT
        : HTTP_STATUS_OK;

    write_headers(status, request.headers);

    if (request.method != AJP_METHOD_HEAD) {
        size_t position = 0;
        while (position < request.length) {
            if (request.received < request.length && position == request.received)
                read_ajp_request_body_chunk(&request);

            assert(position < request.received);

            size_t nbytes = request.received - position;
            if (nbytes > 8192)
                nbytes = 8192;

            write_body_chunk(request.body + position, nbytes, 0);
            position += nbytes;
        }

        if (request.length > 0)
            read_ajp_end_request_body_chunk(&request);
    }

    write_end();
}

static void
ajp_server_hold(struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);
    write_headers(HTTP_STATUS_OK, nullptr);

    /* wait until the connection gets closed */
    struct ajp_header header;
    read_ajp_header(&header);
}

static void
ajp_server_premature_close_headers(gcc_unused struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);

    static constexpr struct ajp_header header = {
        .a = 'A',
        .b = 'B',
        .length = ToBE16(256),
    };

    write_full(&header, sizeof(header));
}

static void
ajp_server_premature_close_body(gcc_unused struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);

    write_headers(HTTP_STATUS_OK, nullptr);

    static constexpr struct ajp_header header = {
        .a = 'A',
        .b = 'B',
        .length = ToBE16(256),
    };

    write_full(&header, sizeof(header));
    write_byte(AJP_CODE_SEND_BODY_CHUNK);
    write_short(200);
}

struct Connection {
    EventLoop &event_loop;
    const pid_t pid;
    const int fd;

    Connection(EventLoop &_event_loop, pid_t _pid, int _fd)
        :event_loop(_event_loop), pid(_pid), fd(_fd) {}
    static Connection *New(EventLoop &event_loop, void (*f)(struct pool *pool));
    ~Connection();

    void Request(struct pool *pool,
                 Lease &lease,
                 http_method_t method, const char *uri,
                 StringMap &&headers,
                 Istream *body,
                 HttpResponseHandler &handler,
                 struct async_operation_ref async_ref) {
        ajp_client_request(*pool, event_loop, fd, FdType::FD_SOCKET,
                           lease,
                           "http", "192.168.1.100", "remote", "server", 80, false,
                           method, uri, headers, body,
                           handler, async_ref);
    }

    static Connection *NewMirror(struct pool &, EventLoop &event_loop) {
        return New(event_loop, ajp_server_mirror);
    }

    static Connection *NewNull(struct pool &, EventLoop &event_loop) {
        return New(event_loop, ajp_server_null);
    }

    static Connection *NewDummy(struct pool &, EventLoop &event_loop) {
        return New(event_loop, ajp_server_hello);
    }

    static Connection *NewFixed(struct pool &, EventLoop &event_loop) {
        return New(event_loop, ajp_server_hello);
    }

    static Connection *NewTiny(struct pool &, EventLoop &event_loop) {
        return New(event_loop, ajp_server_tiny);
    }

    static Connection *NewHold(struct pool &, EventLoop &event_loop) {
        return New(event_loop, ajp_server_hold);
    }

    static Connection *NewPrematureCloseHeaders(struct pool &,
                                                EventLoop &event_loop) {
        return New(event_loop, ajp_server_premature_close_headers);
    }

    static Connection *NewPrematureCloseBody(struct pool &,
                                             EventLoop &event_loop) {
        return New(event_loop, ajp_server_premature_close_body);
    }
};

Connection::~Connection()
{
    assert(pid >= 1);
    assert(fd >= 0);

    close(fd);

    int status;
    if (waitpid(pid, &status, 0) < 0) {
        perror("waitpid() failed");
        abort();
    }

    assert(!WIFSIGNALED(status));
}

Connection *
Connection::New(EventLoop &event_loop, void (*f)(struct pool *pool))
{
    int sv[2];
    pid_t pid;

    if (socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
        perror("socketpair() failed");
        exit(EXIT_FAILURE);
    }

    pid = fork();
    if (pid < 0) {
        perror("fork() failed");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {
        dup2(sv[1], 0);
        dup2(sv[1], 1);
        close(sv[0]);
        close(sv[1]);

        struct pool *pool = pool_new_libc(nullptr, "f");
        f(pool);
        shutdown(0, SHUT_RDWR);
        pool_unref(pool);
        exit(EXIT_SUCCESS);
    }

    close(sv[1]);

    fd_set_nonblock(sv[0], 1);

    return new Connection(event_loop, pid, sv[0]);
}

/*
 * main
 *
 */

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

    SetupProcess();

    direct_global_init();
    EventLoop event_loop;
    fb_pool_init(event_loop, false);

    run_all_tests<Connection>(RootPool());

    fb_pool_deinit();

    int status;
    while (wait(&status) > 0) {
        assert(!WIFSIGNALED(status));
    }
}
<commit_msg>test/t_ajp_client: add missing reference<commit_after>#define ENABLE_PREMATURE_CLOSE_HEADERS
#define ENABLE_PREMATURE_CLOSE_BODY
#define NO_EARLY_RELEASE_SOCKET // TODO: improve the AJP client

#include "tio.hxx"
#include "t_client.hxx"
#include "ajp_server.hxx"
#include "ajp/ajp_client.hxx"
#include "http_response.hxx"
#include "async.hxx"
#include "system/SetupProcess.hxx"
#include "system/fd-util.h"
#include "system/fd_util.h"
#include "growing_buffer.hxx"
#include "header_writer.hxx"
#include "lease.hxx"
#include "direct.hxx"
#include "istream/istream.hxx"
#include "strmap.hxx"
#include "RootPool.hxx"
#include "fb_pool.hxx"
#include "event/Event.hxx"
#include "util/ByteOrder.hxx"

#include <inline/compiler.h>

#include <sys/wait.h>

static void
ajp_server_null(struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);

    if (request.code != AJP_CODE_FORWARD_REQUEST)
        exit(EXIT_FAILURE);

    write_headers(HTTP_STATUS_NO_CONTENT, nullptr);
    write_end();
}

static void
ajp_server_hello(struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);

    if (request.code != AJP_CODE_FORWARD_REQUEST)
        exit(EXIT_FAILURE);

    write_headers(HTTP_STATUS_OK, nullptr);
    write_body_chunk("hello", 5, 0);
    write_end();
}

static void
ajp_server_tiny(struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);

    if (request.code != AJP_CODE_FORWARD_REQUEST)
        exit(EXIT_FAILURE);

    auto *headers = strmap_new(pool);
    headers->Add("content-length", "5");

    write_headers(HTTP_STATUS_OK, headers);
    write_body_chunk("hello", 5, 0);
    write_end();
}

static void
ajp_server_mirror(struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);

    if (request.code != AJP_CODE_FORWARD_REQUEST)
        exit(EXIT_FAILURE);

    http_status_t status = request.length == 0
        ? HTTP_STATUS_NO_CONTENT
        : HTTP_STATUS_OK;

    write_headers(status, request.headers);

    if (request.method != AJP_METHOD_HEAD) {
        size_t position = 0;
        while (position < request.length) {
            if (request.received < request.length && position == request.received)
                read_ajp_request_body_chunk(&request);

            assert(position < request.received);

            size_t nbytes = request.received - position;
            if (nbytes > 8192)
                nbytes = 8192;

            write_body_chunk(request.body + position, nbytes, 0);
            position += nbytes;
        }

        if (request.length > 0)
            read_ajp_end_request_body_chunk(&request);
    }

    write_end();
}

static void
ajp_server_hold(struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);
    write_headers(HTTP_STATUS_OK, nullptr);

    /* wait until the connection gets closed */
    struct ajp_header header;
    read_ajp_header(&header);
}

static void
ajp_server_premature_close_headers(gcc_unused struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);

    static constexpr struct ajp_header header = {
        .a = 'A',
        .b = 'B',
        .length = ToBE16(256),
    };

    write_full(&header, sizeof(header));
}

static void
ajp_server_premature_close_body(gcc_unused struct pool *pool)
{
    struct ajp_request request;
    read_ajp_request(pool, &request);

    write_headers(HTTP_STATUS_OK, nullptr);

    static constexpr struct ajp_header header = {
        .a = 'A',
        .b = 'B',
        .length = ToBE16(256),
    };

    write_full(&header, sizeof(header));
    write_byte(AJP_CODE_SEND_BODY_CHUNK);
    write_short(200);
}

struct Connection {
    EventLoop &event_loop;
    const pid_t pid;
    const int fd;

    Connection(EventLoop &_event_loop, pid_t _pid, int _fd)
        :event_loop(_event_loop), pid(_pid), fd(_fd) {}
    static Connection *New(EventLoop &event_loop, void (*f)(struct pool *pool));
    ~Connection();

    void Request(struct pool *pool,
                 Lease &lease,
                 http_method_t method, const char *uri,
                 StringMap &&headers,
                 Istream *body,
                 HttpResponseHandler &handler,
                 struct async_operation_ref &async_ref) {
        ajp_client_request(*pool, event_loop, fd, FdType::FD_SOCKET,
                           lease,
                           "http", "192.168.1.100", "remote", "server", 80, false,
                           method, uri, headers, body,
                           handler, async_ref);
    }

    static Connection *NewMirror(struct pool &, EventLoop &event_loop) {
        return New(event_loop, ajp_server_mirror);
    }

    static Connection *NewNull(struct pool &, EventLoop &event_loop) {
        return New(event_loop, ajp_server_null);
    }

    static Connection *NewDummy(struct pool &, EventLoop &event_loop) {
        return New(event_loop, ajp_server_hello);
    }

    static Connection *NewFixed(struct pool &, EventLoop &event_loop) {
        return New(event_loop, ajp_server_hello);
    }

    static Connection *NewTiny(struct pool &, EventLoop &event_loop) {
        return New(event_loop, ajp_server_tiny);
    }

    static Connection *NewHold(struct pool &, EventLoop &event_loop) {
        return New(event_loop, ajp_server_hold);
    }

    static Connection *NewPrematureCloseHeaders(struct pool &,
                                                EventLoop &event_loop) {
        return New(event_loop, ajp_server_premature_close_headers);
    }

    static Connection *NewPrematureCloseBody(struct pool &,
                                             EventLoop &event_loop) {
        return New(event_loop, ajp_server_premature_close_body);
    }
};

Connection::~Connection()
{
    assert(pid >= 1);
    assert(fd >= 0);

    close(fd);

    int status;
    if (waitpid(pid, &status, 0) < 0) {
        perror("waitpid() failed");
        abort();
    }

    assert(!WIFSIGNALED(status));
}

Connection *
Connection::New(EventLoop &event_loop, void (*f)(struct pool *pool))
{
    int sv[2];
    pid_t pid;

    if (socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
        perror("socketpair() failed");
        exit(EXIT_FAILURE);
    }

    pid = fork();
    if (pid < 0) {
        perror("fork() failed");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {
        dup2(sv[1], 0);
        dup2(sv[1], 1);
        close(sv[0]);
        close(sv[1]);

        struct pool *pool = pool_new_libc(nullptr, "f");
        f(pool);
        shutdown(0, SHUT_RDWR);
        pool_unref(pool);
        exit(EXIT_SUCCESS);
    }

    close(sv[1]);

    fd_set_nonblock(sv[0], 1);

    return new Connection(event_loop, pid, sv[0]);
}

/*
 * main
 *
 */

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

    SetupProcess();

    direct_global_init();
    EventLoop event_loop;
    fb_pool_init(event_loop, false);

    run_all_tests<Connection>(RootPool());

    fb_pool_deinit();

    int status;
    while (wait(&status) > 0) {
        assert(!WIFSIGNALED(status));
    }
}
<|endoftext|>


<commit_before>#include "precomp.hpp"
#include "iostream"

using namespace std;
using namespace cv;

void helpParser()
{
    printf("\nThe CommandLineParser class is designed for command line arguments parsing\n"
           "Keys map: \n"
           "Before you start to work with CommandLineParser you have to create a map for keys.\n"
           "    It will look like this\n"
           "    const char* keys =\n"
           "    {\n"
           "        {    s|  string|  123asd |string parameter}\n"
           "        {    d|  digit |  100    |digit parameter }\n"
           "        {    c|noCamera|false    |without camera  }\n"
           "        {    1|        |some text|help            }\n"
           "        {    2|        |333      |another help    }\n"
           "    };\n"
           "Usage syntax: \n"
           "    \"{\" - start of parameter string.\n"
           "    \"}\" - end of parameter string\n"
           "    \"|\" - separator between short name, full name, default value and help\n"
           "Supported syntax: \n"
           "    --key1=arg1  <If a key with '--' must has an argument\n"
           "                  you have to assign it through '=' sign.> \n"
           "<If the key with '--' doesn't have any argument, it means that it is a bool key>\n"
           "    -key2=arg2   <If a key with '-' must has an argument \n"
           "                  you have to assign it through '=' sign.> \n"
           "If the key with '-' doesn't have any argument, it means that it is a bool key\n"
           "    key3                 <This key can't has any parameter> \n"
           "Usage: \n"
           "      Imagine that the input parameters are next:\n"
           "                -s=string_value --digit=250 --noCamera lena.jpg 10000\n"
           "    CommandLineParser parser(argc, argv, keys) - create a parser object\n"
           "    parser.get<string>(\"s\" or \"string\") will return you first parameter value\n"
           "    parser.get<string>(\"s\", false or \"string\", false) will return you first parameter value\n"
           "                                                                without spaces in end and begin\n"
           "    parser.get<int>(\"d\" or \"digit\") will return you second parameter value.\n"
           "                    It also works with 'unsigned int', 'double', and 'float' types>\n"
           "    parser.get<bool>(\"c\" or \"noCamera\") will return you true .\n"
           "                                If you enter this key in commandline>\n"
           "                                It return you false otherwise.\n"
           "    parser.get<string>(\"1\") will return you the first argument without parameter (lena.jpg) \n"
           "    parser.get<int>(\"2\") will return you the second argument without parameter (10000)\n"
           "                          It also works with 'unsigned int', 'double', and 'float' types \n"
           );
}

vector<string> split_string(const string& str, const string& delimiters)
{
	vector<string> res;

	string split_str = str;
	int pos_delim = split_str.find(delimiters);

	while ( pos_delim != string::npos)
	{
		if (pos_delim == 0)
		{
			res.push_back("");
			split_str.erase(0, 1);
		}
		else
		{
			res.push_back(split_str.substr(0, pos_delim));
			split_str.erase(0, pos_delim + 1);
		}

		pos_delim = split_str.find(delimiters);
	}

	res.push_back(split_str);

	return res;
}

CommandLineParser::CommandLineParser(int argc, const char* const argv[], const char* keys)
{
	std::string keys_buffer;
    std::string values_buffer;
    std::string buffer;
    std::string curName;
    std::vector<string> keysVector;
    std::vector<string> paramVector;
    std::map<std::string, std::vector<std::string> >::iterator it;
    size_t flagPosition;
    int currentIndex = 1;
    bool isFound = false;
    bool withNoKey = false;
    bool hasValueThroughEq = false;

    keys_buffer = keys;
    while (!keys_buffer.empty())
    {

        flagPosition = keys_buffer.find_first_of('}');
        flagPosition++;
        buffer = keys_buffer.substr(0, flagPosition);
        keys_buffer.erase(0, flagPosition);

        flagPosition = buffer.find('{');
        if (flagPosition != buffer.npos)
            buffer.erase(flagPosition, (flagPosition + 1));

        flagPosition = buffer.find('}');
        if (flagPosition != buffer.npos)
            buffer.erase(flagPosition);

        paramVector = split_string(buffer, "|");
        buffer = paramVector[0];
        if (atoi(buffer.c_str()) == 0)
            buffer = buffer + '|' + paramVector[1];

        paramVector.erase(paramVector.begin(), paramVector.begin() + 2);
        data[buffer] = paramVector;
    }

    buffer.clear();
    keys_buffer.clear();
    paramVector.clear();
    for (int i = 1; i < argc; i++)
    {
        if (!argv[i])
            break;
        curName = argv[i];
        if (curName.find('-') == 0 && ((curName[1] < '0') || (curName[1] > '9')))
        {
            while (curName.find('-') == 0)
                curName.erase(curName.begin(), (curName.begin() + 1));
        }
            else
                withNoKey = true;
        if (curName.find('=') != curName.npos)
        {
            hasValueThroughEq = true;
            buffer = curName;
            curName.erase(curName.find('='));
            buffer.erase(0, (buffer.find('=') + 1));
        }

        for(it = data.begin(); it != data.end(); it++)
        {
            keys_buffer = it->first;
            keysVector = split_string(keys_buffer, "| ");
            if (keysVector.size() == 1)
                keysVector.push_back("");
            values_buffer = it->second[0];
            if (((curName == keysVector[0]) || (curName == keysVector[1])) && hasValueThroughEq)
            {
                it->second[0] = buffer;
                isFound = true;
                break;
            }

            if (!hasValueThroughEq && (values_buffer.find("false") == values_buffer.npos) &&
                ((curName == keysVector[0]) || (curName == keysVector[1])))

            {
                it->second[0] = argv[++i];
                isFound = true;
                break;
            }

            if (!hasValueThroughEq &&  (values_buffer.find("false") != values_buffer.npos)
                && ((curName == keysVector[0]) || (curName == keysVector[1])))

            {
                it->second[0] = "true";
                isFound = true;
                break;
            }

            if (withNoKey)
            {
                std::string noKeyStr = it->first;
                if(atoi(noKeyStr.c_str()) == currentIndex)
                {
                    it->second[0] = curName;
                    currentIndex++;
                    isFound = true;
                    break;
                }
            }
        }

        withNoKey = false;
        hasValueThroughEq = false;
        if(!isFound)
            printf("The current parameter is not defined: %s\n", curName.c_str());
        isFound = false;
    }
}

bool CommandLineParser::has(const std::string& keys)
{
    std::map<std::string, std::vector<std::string> >::iterator it;
    std::vector<string> keysVector;
    for(it = data.begin(); it != data.end(); it++)
    {
        keysVector = split_string(it->first, "| ");
        if (keysVector.size() == 1)
            keysVector.push_back("");
        if ((keys == keysVector[0]) || (keys == keysVector[1]))
            return true;
    }
    return false;
}

std::string CommandLineParser::getString(const std::string& keys)
{
    std::map<std::string, std::vector<std::string> >::iterator it;
    std::vector<string> valueVector;

    for(it = data.begin(); it != data.end(); it++)
    {
        valueVector = split_string(it->first, "| ");
        if (valueVector.size() == 1)
            valueVector.push_back("");
        if ((keys == valueVector[0]) || (keys == valueVector[1]))
            return it->second[0];
    }
    return string();
}

template<typename _Tp>
 _Tp CommandLineParser::fromStringNumber(const std::string& str)//the default conversion function for numbers
{
    const char* c_str=str.c_str();
    if ((!isdigit(c_str[0]))
        &&
        (
            (c_str[0]!='-') || (strlen(c_str) <= 1) || ( !isdigit(c_str[1]) )
        )
    )

    {
        printf("This string cannot be converted to a number. Zero will be returned %s\n ", str.c_str());
        return _Tp();
    }

    return  getData<_Tp>(str);
}

 void CommandLineParser::printParams()
 {
     std::map<std::string, std::vector<std::string> >::iterator it;
     std::vector<string> keysVector;
     for(it = data.begin(); it != data.end(); it++)
     {
         keysVector = split_string(it->first, "| ");
         if (keysVector.size() == 1)
             keysVector.push_back("");
         printf("\t%s [%8s] (%12s - by default) - %s\n", keysVector[0].c_str(),
                keysVector[1].c_str(), it->second[0].c_str(), it->second[1].c_str());
     }
 }

template<>
bool CommandLineParser::get<bool>(const std::string& name, bool space_delete)
{
    std::string str_buf = getString(name);
    if (space_delete)
    {
        while (str_buf.find_first_of(' ') == 0)
            str_buf.erase(0, 1);
        while (str_buf.find_last_of(' ') == (str_buf.length() - 1))
            str_buf.erase(str_buf.end() - 1, str_buf.end());
    }
    if (str_buf == "false")
        return false;
    return true;
}
template<>
std::string CommandLineParser::analyzeValue<std::string>(const std::string& str, bool space_delete)
{
    if (space_delete)
    {
        std::string str_buf = str;
        while (str_buf.find_first_of(' ') == 0)
            str_buf.erase(0, 1);
        while (str_buf.find_last_of('-') == (str.length() - 1))
            str_buf.erase(str_buf.end() - 1, str_buf.end());
        return str_buf;
    }
    return str;
}

template<>
int CommandLineParser::analyzeValue<int>(const std::string& str, bool /*space_delete*/)
{
    return fromStringNumber<int>(str);
}

template<>
unsigned int CommandLineParser::analyzeValue<unsigned int>(const std::string& str, bool /*space_delete*/)
{
    return fromStringNumber<unsigned int>(str);
}

template<>
uint64 CommandLineParser::analyzeValue<uint64>(const std::string& str, bool /*space_delete*/)
{
    return fromStringNumber<uint64>(str);
}

template<>
float CommandLineParser::analyzeValue<float>(const std::string& str, bool /*space_delete*/)
{
    return fromStringNumber<float>(str);
}

template<>
double CommandLineParser::analyzeValue<double>(const std::string& str, bool /*space_delete*/)
{
    return fromStringNumber<double>(str);
}
<commit_msg>fixed several bugs in CommandLineParser<commit_after>#include "precomp.hpp"
#include "iostream"

using namespace std;
using namespace cv;

void helpParser()
{
    printf("\nThe CommandLineParser class is designed for command line arguments parsing\n"
           "Keys map: \n"
           "Before you start to work with CommandLineParser you have to create a map for keys.\n"
           "    It will look like this\n"
           "    const char* keys =\n"
           "    {\n"
           "        {    s|  string|  123asd |string parameter}\n"
           "        {    d|  digit |  100    |digit parameter }\n"
           "        {    c|noCamera|false    |without camera  }\n"
           "        {    1|        |some text|help            }\n"
           "        {    2|        |333      |another help    }\n"
           "    };\n"
           "Usage syntax: \n"
           "    \"{\" - start of parameter string.\n"
           "    \"}\" - end of parameter string\n"
           "    \"|\" - separator between short name, full name, default value and help\n"
           "Supported syntax: \n"
           "    --key1=arg1  <If a key with '--' must has an argument\n"
           "                  you have to assign it through '=' sign.> \n"
           "<If the key with '--' doesn't have any argument, it means that it is a bool key>\n"
           "    -key2=arg2   <If a key with '-' must has an argument \n"
           "                  you have to assign it through '=' sign.> \n"
           "If the key with '-' doesn't have any argument, it means that it is a bool key\n"
           "    key3                 <This key can't has any parameter> \n"
           "Usage: \n"
           "      Imagine that the input parameters are next:\n"
           "                -s=string_value --digit=250 --noCamera lena.jpg 10000\n"
           "    CommandLineParser parser(argc, argv, keys) - create a parser object\n"
           "    parser.get<string>(\"s\" or \"string\") will return you first parameter value\n"
           "    parser.get<string>(\"s\", false or \"string\", false) will return you first parameter value\n"
           "                                                                without spaces in end and begin\n"
           "    parser.get<int>(\"d\" or \"digit\") will return you second parameter value.\n"
           "                    It also works with 'unsigned int', 'double', and 'float' types>\n"
           "    parser.get<bool>(\"c\" or \"noCamera\") will return you true .\n"
           "                                If you enter this key in commandline>\n"
           "                                It return you false otherwise.\n"
           "    parser.get<string>(\"1\") will return you the first argument without parameter (lena.jpg) \n"
           "    parser.get<int>(\"2\") will return you the second argument without parameter (10000)\n"
           "                          It also works with 'unsigned int', 'double', and 'float' types \n"
           );
}

vector<string> split_string(const string& str, const string& delimiters)
{
	vector<string> res;

	string split_str = str;
	size_t pos_delim = split_str.find(delimiters);

	while ( pos_delim != string::npos)
	{
		if (pos_delim == 0)
		{
			res.push_back("");
			split_str.erase(0, 1);
		}
		else
		{
			res.push_back(split_str.substr(0, pos_delim));
			split_str.erase(0, pos_delim + 1);
		}

		pos_delim = split_str.find(delimiters);
	}

	res.push_back(split_str);

	return res;
}

CommandLineParser::CommandLineParser(int argc, const char* const argv[], const char* keys)
{
	std::string keys_buffer;
    std::string values_buffer;
    std::string buffer;
    std::string curName;
    std::vector<string> keysVector;
    std::vector<string> paramVector;
    std::map<std::string, std::vector<std::string> >::iterator it;
    size_t flagPosition;
    int currentIndex = 1;
    bool isFound = false;
    bool withNoKey = false;
    bool hasValueThroughEq = false;

    keys_buffer = keys;
    while (!keys_buffer.empty())
    {

        flagPosition = keys_buffer.find_first_of('}');
        flagPosition++;
        buffer = keys_buffer.substr(0, flagPosition);
        keys_buffer.erase(0, flagPosition);

        flagPosition = buffer.find('{');
        if (flagPosition != buffer.npos)
            buffer.erase(flagPosition, (flagPosition + 1));

        flagPosition = buffer.find('}');
        if (flagPosition != buffer.npos)
            buffer.erase(flagPosition);

        paramVector = split_string(buffer, "|");
		while (paramVector.size() < 4) paramVector.push_back("");

		buffer = "";
		if (paramVector[0] != "")
		{
			buffer = paramVector[0];
			if (paramVector[1] != "")
				buffer += '|' + paramVector[1];
		}
		if (paramVector[1] != "")
			buffer = paramVector[1];

		//if (buffer == "") CV_ERROR(CV_StsBadArg, "In CommandLineParser need set short and full name");

		paramVector.erase(paramVector.begin(), paramVector.begin() + 2);
        data[buffer] = paramVector;
    }

    buffer.clear();
    keys_buffer.clear();
    paramVector.clear();
    for (int i = 1; i < argc; i++)
    {
        if (!argv[i])
            break;
        curName = argv[i];
        if (curName.find('-') == 0 && ((curName[1] < '0') || (curName[1] > '9')))
        {
            while (curName.find('-') == 0)
                curName.erase(curName.begin(), (curName.begin() + 1));
        }
            else
                withNoKey = true;
        if (curName.find('=') != curName.npos)
        {
            hasValueThroughEq = true;
            buffer = curName;
            curName.erase(curName.find('='));
            buffer.erase(0, (buffer.find('=') + 1));
        }

        for(it = data.begin(); it != data.end(); it++)
        {
            keys_buffer = it->first;
            keysVector = split_string(keys_buffer, "|");
            if (keysVector.size() == 1)
                keysVector.push_back("");
            values_buffer = it->second[0];
            if (((curName == keysVector[0]) || (curName == keysVector[1])) && hasValueThroughEq)
            {
                it->second[0] = buffer;
                isFound = true;
                break;
            }

            if (!hasValueThroughEq && (values_buffer.find("false") == values_buffer.npos) &&
                ((curName == keysVector[0]) || (curName == keysVector[1])))

            {
                it->second[0] = argv[++i];
                isFound = true;
                break;
            }

            if (!hasValueThroughEq &&  (values_buffer.find("false") != values_buffer.npos)
                && ((curName == keysVector[0]) || (curName == keysVector[1])))

            {
                it->second[0] = "true";
                isFound = true;
                break;
            }

            if (withNoKey)
            {
                std::string noKeyStr = it->first;
                if(atoi(noKeyStr.c_str()) == currentIndex)
                {
                    it->second[0] = curName;
                    currentIndex++;
                    isFound = true;
                    break;
                }
            }
        }

        withNoKey = false;
        hasValueThroughEq = false;
        if(!isFound)
            printf("The current parameter is not defined: %s\n", curName.c_str());
        isFound = false;
    }
}

string del_space(string name)
{
	while (name.find_first_of(' ') == 0)
		name.erase(0, 1);

	while (name.find_last_of(' ') == (name.length() - 1))
		name.erase(name.end() - 1, name.end());

	return name;
}

bool CommandLineParser::has(const std::string& keys)
{
    std::map<std::string, std::vector<std::string> >::iterator it;
    std::vector<string> keysVector;

    for(it = data.begin(); it != data.end(); it++)
    {
        keysVector = split_string(it->first, "|");
		for (int i = 0; i < keysVector.size(); i++) keysVector[i] = del_space(keysVector[i]);

        if (keysVector.size() == 1) keysVector.push_back("");

		if ((del_space(keys).compare(keysVector[0]) == 0) ||
			(del_space(keys).compare(keysVector[1]) == 0))
            return true;
    }

    return false;
}

std::string CommandLineParser::getString(const std::string& keys)
{
    std::map<std::string, std::vector<std::string> >::iterator it;
    std::vector<string> valueVector;

    for(it = data.begin(); it != data.end(); it++)
    {
        valueVector = split_string(it->first, "|");
		for (int i = 0; i < valueVector.size(); i++) valueVector[i] = del_space(valueVector[i]);

        if (valueVector.size() == 1) valueVector.push_back("");

		if ((del_space(keys).compare(valueVector[0]) == 0) ||
			(del_space(keys).compare(valueVector[1]) == 0))
            return it->second[0];
    }
    return string();
}

template<typename _Tp>
 _Tp CommandLineParser::fromStringNumber(const std::string& str)//the default conversion function for numbers
{
    return getData<_Tp>(str);
}

 void CommandLineParser::printParams()
 {
     std::map<std::string, std::vector<std::string> >::iterator it;
     std::vector<string> keysVector;
     for(it = data.begin(); it != data.end(); it++)
     {
         keysVector = split_string(it->first, "|");
         if (keysVector.size() == 1)
             keysVector.push_back("");
         printf("\t%s [%8s] (%12s - by default) - %s\n", keysVector[0].c_str(),
                keysVector[1].c_str(), it->second[0].c_str(), it->second[1].c_str());
     }
 }

template<>
bool CommandLineParser::get<bool>(const std::string& name, bool space_delete)
{
    std::string str_buf = getString(name);

	if (space_delete && str_buf != "")
    {
		str_buf = del_space(str_buf);
    }

    if (str_buf == "true")
        return true;

    return false;
}
template<>
std::string CommandLineParser::analyzeValue<std::string>(const std::string& str, bool space_delete)
{
    if (space_delete)
    {
		return del_space(str);
    }
    return str;
}

template<>
int CommandLineParser::analyzeValue<int>(const std::string& str, bool /*space_delete*/)
{
    return fromStringNumber<int>(str);
}

template<>
unsigned int CommandLineParser::analyzeValue<unsigned int>(const std::string& str, bool /*space_delete*/)
{
    return fromStringNumber<unsigned int>(str);
}

template<>
uint64 CommandLineParser::analyzeValue<uint64>(const std::string& str, bool /*space_delete*/)
{
    return fromStringNumber<uint64>(str);
}

template<>
float CommandLineParser::analyzeValue<float>(const std::string& str, bool /*space_delete*/)
{
    return fromStringNumber<float>(str);
}

template<>
double CommandLineParser::analyzeValue<double>(const std::string& str, bool /*space_delete*/)
{
    return fromStringNumber<double>(str);
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_CORE_SCOPED_CHAINABLESTACK_HPP
#define STAN_MATH_REV_CORE_SCOPED_CHAINABLESTACK_HPP

#include <stan/math/rev/core/chainablestack.hpp>
#include <stan/math/rev/core/start_nested.hpp>
#include <stan/math/rev/core/recover_memory_nested.hpp>

#include <vector>

namespace stan {
namespace math {

class ScopedChainableStack {
  typedef ChainableStack::AutodiffStackStorage chainablestack_t;
  chainablestack_t local_stack_;

  using stack_queue_t = std::vector<chainablestack_t*>;
  stack_queue_t stack_queue_;

  struct activate_scope {
    ScopedChainableStack& scoped_stack_;

    explicit activate_scope(ScopedChainableStack& scoped_stack)
        : scoped_stack_(scoped_stack) {
      scoped_stack_.stack_queue_.push_back(ChainableStack::instance_);
      ChainableStack::instance_ = &scoped_stack_.local_stack_;
    }

    ~activate_scope() {
      ChainableStack::instance_ = scoped_stack_.stack_queue_.back();
      scoped_stack_.stack_queue_.pop_back();
    }
  };

 public:
  ScopedChainableStack() = default;

  // execute in the current thread a nullary function and write the AD
  // tape to local_stack_ of this instance
  template <typename F>
  F execute(F f) {
    activate_scope active_scope(*this);
    f();
    return f;
  }
};

}  // namespace math
}  // namespace stan
#endif
<commit_msg>Update stan/math/rev/core/scoped_chainablestack.hpp<commit_after>#ifndef STAN_MATH_REV_CORE_SCOPED_CHAINABLESTACK_HPP
#define STAN_MATH_REV_CORE_SCOPED_CHAINABLESTACK_HPP

#include <stan/math/rev/core/chainablestack.hpp>
#include <stan/math/rev/core/start_nested.hpp>
#include <stan/math/rev/core/recover_memory_nested.hpp>

#include <vector>

namespace stan {
namespace math {

class ScopedChainableStack {
  typedef ChainableStack::AutodiffStackStorage chainablestack_t;
  chainablestack_t local_stack_;

  using stack_queue_t = std::vector<chainablestack_t*>;
  stack_queue_t stack_queue_;

  struct activate_scope {
    ScopedChainableStack& scoped_stack_;

    explicit activate_scope(ScopedChainableStack& scoped_stack)
        : scoped_stack_(scoped_stack) {
      scoped_stack_.stack_queue_.push_back(ChainableStack::instance_);
      ChainableStack::instance_ = &scoped_stack_.local_stack_;
    }

    ~activate_scope() {
      ChainableStack::instance_ = scoped_stack_.stack_queue_.back();
      scoped_stack_.stack_queue_.pop_back();
    }
  };

 public:
  ScopedChainableStack() = default;

  // execute in the current thread a nullary function and write the AD
  // tape to local_stack_ of this instance
  template <typename F>
  auto execute(F&& f) {
    activate_scope active_scope(*this);
    return std::forward<F>(f)();
  }
};

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>#ifndef STACKIOHELPERS_HHP_
#define STACKIOHELPERS_HHP_

#include <assert.h>
#include "boost/filesystem.hpp"

#include "itkTransformFileReader.h"
#include "itkTransformFileWriter.h"
#include "itkTranslationTransform.h"
#include "itkTransformFactory.h"

#include "Stack.hpp"
#include "StackTransforms.hpp"
#include "Dirs.hpp"

using namespace boost::filesystem;

// helper to construct transform file path
const string TransformFilePath(const string& imageFileName, const string& transformDirName) {
  path slicePath( imageFileName );
  string transformFileName( basename( slicePath.leaf() ) + ".meta" );
  path transformFilePath = path(transformDirName) / path(transformFileName);
  return transformFilePath.string();
}

// Stack Persistence
template <typename StackType>
void Save(StackType& stack, vector< string > fileNames, const string& dirName)
{
  typedef itk::TransformFileWriter WriterType;

  for(int slice_number=0; slice_number < stack.GetSize(); ++slice_number)
	{
    WriterType::Pointer writer = WriterType::New();
    writer->SetFileName( TransformFilePath(fileNames[slice_number], dirName).c_str() );
    writer->AddTransform( stack.GetTransform(slice_number) );

    try
    {
    	writer->Update();
    }
  	catch( itk::ExceptionObject & err )
  	{
      cerr << "ExceptionObject caught while saving transforms." << endl;
      cerr << err << endl;
  		std::abort();
  	}

  }

}

template <typename StackType>
void Load(StackType& stack, vector< string > fileNames, const string& dirName)
{
  typedef itk::TransformFileReader ReaderType;

  // Some transforms might not be registered
  // with the factory so we add them manually
  itk::TransformFactoryBase::RegisterDefaultTransforms();
  // TODO: below registers a new version of transform every time Load() is called
  itk::TransformFactory< itk::TranslationTransform< double, 2 > >::RegisterTransform();

  typename StackType::TransformVectorType newTransforms;

  for(unsigned int slice_number=0; slice_number<stack.GetSize(); ++slice_number)
  {
    ReaderType::Pointer reader = ReaderType::New();
    reader->SetFileName( TransformFilePath(fileNames[slice_number], dirName).c_str() );

    try
    {
      reader->Update();
    }
    catch( itk::ExceptionObject & err )
    {
      std::cerr << "ExceptionObject caught while reading transforms." << std::endl;
      cerr << err << endl;
  		std::abort();
    }

    typename StackType::TransformType::Pointer transform = static_cast<typename StackType::TransformType*>( reader->GetTransformList()->begin()->GetPointer() );
    newTransforms.push_back( transform );
  }

  stack.SetTransforms(newTransforms);
}

template <typename StackType>
void ApplyAdjustments(StackType& stack, vector< string > fileNames, const string& dirName)
{
  typedef itk::TransformFileReader ReaderType;

  // Some transforms might not be registered
  // with the factory so we add them manually
  itk::TransformFactoryBase::RegisterDefaultTransforms();
  itk::TransformFactory< itk::TranslationTransform< double, 2 > >::RegisterTransform();

  typename StackType::TransformVectorType newTransforms;

  for(unsigned int slice_number=0; slice_number<stack.GetSize(); ++slice_number)
  {
    // construct path to config transform file
    // config/Rat28/LoRes_adustments/0053.meta
    string transformFilePath = TransformFilePath(fileNames[slice_number], dirName);

    if( exists(transformFilePath) )
    {
      ReaderType::Pointer reader = ReaderType::New();
      reader->SetFileName( transformFilePath.c_str() );

      try
      {
        reader->Update();
      }
      catch( itk::ExceptionObject & err )
      {
        std::cerr << "ExceptionObject caught while reading transforms." << std::endl;
        cerr << err << endl;
           std::abort();
      }

      // convert Array to Vector
      itk::Array< double > parameters( reader->GetTransformList()->begin()->GetPointer()->GetParameters() );
      itk::Vector< double, 2 > translation;
      translation[0] = parameters[0];
      translation[1] = parameters[1];

      // translate block image
      StackTransforms::Translate<StackType>(stack, translation, slice_number );
    }
  }
}

template <typename DataType>
void saveVectorToFiles(const vector< DataType >& values, const string& dirName, const vector< string >& fileNames)
{
  assert(values.size() == fileNames.size());

  path pathName = Dirs::ResultsDir() + dirName;
  create_directory(pathName);

  for(unsigned int i=0; i<values.size(); ++i)
  {
    path outPath = pathName / fileNames[i];
    ofstream outFile(outPath.string().c_str());
    outFile << values[i] << endl;
  }
}

template <typename DataType>
vector< DataType > loadVectorFromFiles(const string& dirName,  const vector< string >& fileNames)
{
  path pathName = Dirs::ResultsDir() + dirName;
  typename vector< DataType >::size_type numberOfFiles = fileNames.size();
  vector< DataType > values(numberOfFiles);

  for(unsigned int i=0; i<fileNames.size(); ++i)
  {
    path inPath = pathName / fileNames[i];
    ifstream inFile(inPath.string().c_str());
    assert(inFile.is_open());
    inFile >> values[i];
  }

  return values;
}

#endif
<commit_msg>Vector IO removes filename extension.<commit_after>#ifndef STACKIOHELPERS_HHP_
#define STACKIOHELPERS_HHP_

#include <assert.h>
#include "boost/filesystem.hpp"

#include "itkTransformFileReader.h"
#include "itkTransformFileWriter.h"
#include "itkTranslationTransform.h"
#include "itkTransformFactory.h"

#include "Stack.hpp"
#include "StackTransforms.hpp"
#include "Dirs.hpp"

using namespace boost::filesystem;

// helper to construct transform file path
const string TransformFilePath(const string& imageFileName, const string& transformDirName) {
  path slicePath( imageFileName );
  string transformFileName( basename( slicePath.leaf() ) + ".meta" );
  path transformFilePath = path(transformDirName) / path(transformFileName);
  return transformFilePath.string();
}

// Stack Persistence
template <typename StackType>
void Save(StackType& stack, vector< string > fileNames, const string& dirName)
{
  typedef itk::TransformFileWriter WriterType;

  for(int slice_number=0; slice_number < stack.GetSize(); ++slice_number)
	{
    WriterType::Pointer writer = WriterType::New();
    writer->SetFileName( TransformFilePath(fileNames[slice_number], dirName).c_str() );
    writer->AddTransform( stack.GetTransform(slice_number) );

    try
    {
    	writer->Update();
    }
  	catch( itk::ExceptionObject & err )
  	{
      cerr << "ExceptionObject caught while saving transforms." << endl;
      cerr << err << endl;
  		std::abort();
  	}

  }

}

template <typename StackType>
void Load(StackType& stack, vector< string > fileNames, const string& dirName)
{
  typedef itk::TransformFileReader ReaderType;

  // Some transforms might not be registered
  // with the factory so we add them manually
  itk::TransformFactoryBase::RegisterDefaultTransforms();
  // TODO: below registers a new version of transform every time Load() is called
  itk::TransformFactory< itk::TranslationTransform< double, 2 > >::RegisterTransform();

  typename StackType::TransformVectorType newTransforms;

  for(unsigned int slice_number=0; slice_number<stack.GetSize(); ++slice_number)
  {
    ReaderType::Pointer reader = ReaderType::New();
    reader->SetFileName( TransformFilePath(fileNames[slice_number], dirName).c_str() );

    try
    {
      reader->Update();
    }
    catch( itk::ExceptionObject & err )
    {
      std::cerr << "ExceptionObject caught while reading transforms." << std::endl;
      cerr << err << endl;
  		std::abort();
    }

    typename StackType::TransformType::Pointer transform = static_cast<typename StackType::TransformType*>( reader->GetTransformList()->begin()->GetPointer() );
    newTransforms.push_back( transform );
  }

  stack.SetTransforms(newTransforms);
}

template <typename StackType>
void ApplyAdjustments(StackType& stack, vector< string > fileNames, const string& dirName)
{
  typedef itk::TransformFileReader ReaderType;

  // Some transforms might not be registered
  // with the factory so we add them manually
  itk::TransformFactoryBase::RegisterDefaultTransforms();
  itk::TransformFactory< itk::TranslationTransform< double, 2 > >::RegisterTransform();

  typename StackType::TransformVectorType newTransforms;

  for(unsigned int slice_number=0; slice_number<stack.GetSize(); ++slice_number)
  {
    // construct path to config transform file
    // config/Rat28/LoRes_adustments/0053.meta
    string transformFilePath = TransformFilePath(fileNames[slice_number], dirName);

    if( exists(transformFilePath) )
    {
      ReaderType::Pointer reader = ReaderType::New();
      reader->SetFileName( transformFilePath.c_str() );

      try
      {
        reader->Update();
      }
      catch( itk::ExceptionObject & err )
      {
        std::cerr << "ExceptionObject caught while reading transforms." << std::endl;
        cerr << err << endl;
           std::abort();
      }

      // convert Array to Vector
      itk::Array< double > parameters( reader->GetTransformList()->begin()->GetPointer()->GetParameters() );
      itk::Vector< double, 2 > translation;
      translation[0] = parameters[0];
      translation[1] = parameters[1];

      // translate block image
      StackTransforms::Translate<StackType>(stack, translation, slice_number );
    }
  }
}

template <typename DataType>
void saveVectorToFiles(const vector< DataType >& values, const string& dirName, const vector< string >& fileNames)
{
  assert(values.size() == fileNames.size());

  path pathName = Dirs::ResultsDir() + dirName;
  create_directory(pathName);

  for(unsigned int i=0; i<values.size(); ++i)
  {
    path outPath = pathName / basename(fileNames[i]);
    ofstream outFile(outPath.string().c_str());
    outFile << values[i] << endl;
  }
}

template <typename DataType>
vector< DataType > loadVectorFromFiles(const string& dirName,  const vector< string >& fileNames)
{
  path pathName = Dirs::ResultsDir() + dirName;
  typename vector< DataType >::size_type numberOfFiles = fileNames.size();
  vector< DataType > values(numberOfFiles);

  for(unsigned int i=0; i<fileNames.size(); ++i)
  {
    path inPath = pathName / basename(fileNames[i]);
    ifstream inFile(inPath.string().c_str());
    assert(inFile.is_open());
    inFile >> values[i];
  }

  return values;
}

#endif
<|endoftext|>


<commit_before>// cb_info allows to parse and manipulate MCell's cellblender output files
//
// (C) Markus Dittrich, 2015
// Licenses under a BSD license, see LICENSE file for details

#include <cassert>
#include <exception>
#include <getopt.h>
#include <iostream>
#include <string>

#include "analyze.hpp"
#include "cb_info.hpp"

// forward declaration of static funcs
static void usage();
static void error_and_exit(const std::string& errMsg);
static CmdlOpts parse_cmdline(int argc, char** argv);
static void read_Vec3s(std::ifstream& file, std::vector<Vec3>& vecs,
                       size_t numMols);
static std::string check_cmdline_opts(const CmdlOpts& cmdlOpts);
static std::string extract_and_check_species(const SpecMap& specMap,
                                             CmdlOpts& cmdlOpts);
static void print_positions(const SpecMap& specMap, const CmdlOpts& cmdlOpts);
static void print_orientations(const SpecMap& specMap,
                               const CmdlOpts& cmdlOpts);

// main entry point
int main(int argc, char** argv) {

  auto cmdl = parse_cmdline(argc, argv);
  std::string err = check_cmdline_opts(cmdl);
  if (err != "") {
    error_and_exit(err);
  }

  for (const auto& fileName : cmdl.files) {
    SpecMap specMap;
    try {
      specMap = parse_cb(fileName);
    } catch (std::exception& e) {
      error_and_exit("Failed to parse CellBlender file " + fileName + ": " +
                     e.what());
    }

    err = extract_and_check_species(specMap, cmdl);
    if (err != "") {
      error_and_exit(err);
    }

    if (cmdl.info) {
      for (const auto& s : specMap) {
        std::cout << s.first << "  " << s.second.pos.size()
          << "  " << (s.second.isVolMol ? "VOL" : "SURF") << "\n";
      }
    }

    if (cmdl.listMolPos) {
      print_positions(specMap, cmdl);
    }

    if (cmdl.listMolOrient) {
      for (const auto& s : cmdl.specs) {
        if (specMap.at(s).isVolMol) {
          error_and_exit("Cannot list orientations for volume mol " + s);
        }
      }
      print_orientations(specMap, cmdl);
    }

    if (cmdl.analyzePositions) {
      analyze_mol_positions(specMap, cmdl.specs);
    }
  }

  return EXIT_SUCCESS;
}

// parse_cb does the actual work of parsing the cellblender input file
SpecMap parse_cb(const std::string& fileName) {
  std::ifstream file(fileName);
  if (file.fail()) {
    throw std::runtime_error("failed to open");
  }

  SpecMap specs;
  uint32_t version;
  read_val(file, version);

  while (file) {
    unsigned char nameLength;
    read_val(file, nameLength);

    Species spec;
    char specName[nameLength + 1];
    for (int i = 0; i < nameLength; ++i) {
      read_val(file, specName[i]);
    }
    specName[nameLength] = '\0';

    unsigned char type;
    read_val(file, type);
    spec.isVolMol = (type == 0) ? true : false;

    uint32_t numMols;
    read_val(file, numMols);

    read_Vec3s(file, spec.pos, numMols);
    if (!spec.isVolMol) {
      read_Vec3s(file, spec.orient, numMols);
    }
    specs[specName] = std::move(spec);

    // check if we're done
    if (file.peek() == EOF) {
      break;
    }
  }

  return specs;
}

// read_Vec3s reads numMols worth of Vec3s from the passed ifstream
void read_Vec3s(std::ifstream& file, std::vector<Vec3>& vecs, size_t numMols) {
  vecs.reserve(numMols);
  assert(numMols % 3 == 0);
  for (size_t i = 0; i < numMols / 3; i++) {
    float x, y, z;  // NOTE: cellblender format stores floats
    read_val(file, x);
    read_val(file, y);
    read_val(file, z);
    vecs.emplace_back(std::move(Vec3{x, y, z}));
  }
}

// print_orentations prints the position info of the requested molecules
// NOTE: this function assumes that all species requested for printing
// actually exist and are surface molecule species.
void print_orientations(const SpecMap& specs, const CmdlOpts& cmdlOpts) {
  for (const auto& s : cmdlOpts.specs) {
    if (cmdlOpts.addSeparator) {
      std::cout << "--- " << s << "\n";
    }
    for (const auto& v : specs.at(s).orient) {
      std::cout << v << "\n";
    }
  }
}

// print_positions prints the position info of the requested molecules
// NOTE: this function assumes that all species requested for printing
// actually exist.
void print_positions(const SpecMap& specs, const CmdlOpts& cmdlOpts) {
  for (const auto& s : cmdlOpts.specs) {
    if (cmdlOpts.addSeparator) {
      std::cout << "--- " << s << "\n";
    }
    for (const auto& v : specs.at(s).pos) {
      std::cout << v << "\n";
    }
  }
}

// extract_and_check_species check is the requested species (for printing)
// exists. If not returns an error string. If no species were requested
// picks all available species as default. If no errors were encountered
// return an empty string.
std::string extract_and_check_species(const SpecMap& specMap,
                                      CmdlOpts& cmdlOpts) {
  for (const auto& s : cmdlOpts.specs) {
    if (specMap.find(s) == specMap.end()) {
      return "Unknown species " + s + " requested";
    }
  }

  if (cmdlOpts.specs.size() == 0) {
    for (const auto& m : specMap) {
      cmdlOpts.specs.push_back(m.first);
    }
  }

  return "";
}

// usage prints a quick usage info
void usage() {
  std::cout
      << "cb_info v0.1    (C) 2015 Markus Dittrich\n\n"
      << "usage: cb_info [options] <file1> <file2> ....\n\n"
      << "Options:"
      << "\n"
      << "\t-i, --species_info       print names of species and number of\n"
      << "\t                         available molecules\n"
      << "\t-p, --print_mol_positions <species type>\n"
      << "\t                         print the (x,y,z) positions of all\n"
      << "\t                         molecules of species type\n"
      << "\t-o, --print_mol_orientations <species type>\n"
      << "\t                         print the orientations of all\n"
      << "\t                         molecules of species type\n"
      << "\t                         (empty string \"\" implies all species)\n"
      << "\t-s, --add_separator      add separator between species in "
         "printout\n"
      << "\t-a, --analyze_positions  checks if molecules are uniformly "
         "distributed\n"
      << "\t-n, --species_name       name of species to print\n"
      << "\t-h, --help               this help message\n" << std::endl;
}

// longOptions provides the parameters used for command line parsing
static struct option long_options[] = {
    {"species_info", no_argument, NULL, 'i'},
    {"print_mol_positions", no_argument, NULL, 'p'},
    {"print_mol_orientations", no_argument, NULL, 'o'},
    {"add_separator", no_argument, NULL, 's'},
    {"species_name", required_argument, NULL, 'n'},
    {"analyze_positions", no_argument, NULL, 'a'},
    {"help", no_argument, NULL, 'h'}};

// parse_cmdline parses the user provided command line options and
// does some basic sanity checks on them
static CmdlOpts parse_cmdline(int argc, char** argv) {

  int c;
  CmdlOpts cmdlOpts;
  while ((c = getopt_long(argc, argv, "ain:spolh", long_options, NULL)) != -1) {
    switch (c) {
      case 'i':
        cmdlOpts.info = true;
        break;

      case 'p':
        cmdlOpts.listMolPos = true;
        break;

      case 'o':
        cmdlOpts.listMolOrient = true;
        break;

      case 'n':
        cmdlOpts.specs.push_back(optarg);
        break;

      case 's':
        cmdlOpts.addSeparator = true;
        break;

      case 'a':
        cmdlOpts.analyzePositions = true;
        break;

      case 'h':
      default:
        usage();
    }
  }
  while (optind < argc) {
    cmdlOpts.files.push_back(argv[optind++]);
  }

  return cmdlOpts;
}

// check_cmdline_opts does a sanity check of the provided command line
// options. If it finds a problem it returns a string with a description
// and an empty string otherwise.
std::string check_cmdline_opts(const CmdlOpts& cmdl) {
  if (cmdl.files.size() == 0) {
    return "No MCell viz files specified to operate on";
  }
  return "";
}

// error_and_exit aborts the program after printing the provided error
// message and usage info.
void error_and_exit(const std::string& errMsg) {
  std::cerr << "***** ERROR: " << errMsg << "\n\n";
  usage();
  exit(1);
}
<commit_msg>Add small enhancements to usage output.<commit_after>// cb_info allows to parse and manipulate MCell's cellblender output files
//
// (C) Markus Dittrich, 2015
// Licenses under a BSD license, see LICENSE file for details

#include <algorithm>
#include <cassert>
#include <exception>
#include <getopt.h>
#include <iostream>
#include <iterator>
#include <string>

#include "analyze.hpp"
#include "cb_info.hpp"

// forward declaration of static funcs
static void usage();
static void error_and_exit(const std::string& errMsg);
static CmdlOpts parse_cmdline(int argc, char** argv);
static void read_Vec3s(std::ifstream& file, std::vector<Vec3>& vecs,
                       size_t numMols);
static std::string check_cmdline_opts(const CmdlOpts& cmdlOpts);
static std::string extract_and_check_species(const SpecMap& specMap,
                                             CmdlOpts& cmdlOpts);
static void print_positions(const SpecMap& specMap, const CmdlOpts& cmdlOpts);
static void print_orientations(const SpecMap& specMap,
                               const CmdlOpts& cmdlOpts);

// main entry point
int main(int argc, char** argv) {

  auto cmdl = parse_cmdline(argc, argv);
  std::string err = check_cmdline_opts(cmdl);
  if (err != "") {
    error_and_exit(err);
  }

  for (const auto& fileName : cmdl.files) {
    SpecMap specMap;
    try {
      specMap = parse_cb(fileName);
    } catch (std::exception& e) {
      error_and_exit("Failed to parse CellBlender file " + fileName + ": " +
                     e.what());
    }

    err = extract_and_check_species(specMap, cmdl);
    if (err != "") {
      error_and_exit(err);
    }

    if (cmdl.info) {
      for (const auto& s : specMap) {
        std::cout << s.first << "  " << s.second.pos.size()
          << "  " << (s.second.isVolMol ? "VOL" : "SURF") << "\n";
      }
    }

    if (cmdl.listMolPos) {
      print_positions(specMap, cmdl);
    }

    if (cmdl.listMolOrient) {
      for (const auto& s : cmdl.specs) {
        if (specMap.at(s).isVolMol) {
          error_and_exit("Cannot list orientations for volume mol " + s);
        }
      }
      print_orientations(specMap, cmdl);
    }

    if (cmdl.analyzePositions) {
      analyze_mol_positions(specMap, cmdl.specs);
    }
  }

  return EXIT_SUCCESS;
}

// parse_cb does the actual work of parsing the cellblender input file
SpecMap parse_cb(const std::string& fileName) {
  std::ifstream file(fileName);
  if (file.fail()) {
    throw std::runtime_error("failed to open");
  }

  SpecMap specs;
  uint32_t version;
  read_val(file, version);

  while (file) {
    unsigned char nameLength;
    read_val(file, nameLength);

    Species spec;
    char specName[nameLength + 1];
    for (int i = 0; i < nameLength; ++i) {
      read_val(file, specName[i]);
    }
    specName[nameLength] = '\0';

    unsigned char type;
    read_val(file, type);
    spec.isVolMol = (type == 0) ? true : false;

    uint32_t numMols;
    read_val(file, numMols);

    read_Vec3s(file, spec.pos, numMols);
    if (!spec.isVolMol) {
      read_Vec3s(file, spec.orient, numMols);
    }
    specs[specName] = std::move(spec);

    // check if we're done
    if (file.peek() == EOF) {
      break;
    }
  }

  return specs;
}

// read_Vec3s reads numMols worth of Vec3s from the passed ifstream
void read_Vec3s(std::ifstream& file, std::vector<Vec3>& vecs, size_t numMols) {
  vecs.reserve(numMols);
  assert(numMols % 3 == 0);
  for (size_t i = 0; i < numMols / 3; i++) {
    float x, y, z;  // NOTE: cellblender format stores floats
    read_val(file, x);
    read_val(file, y);
    read_val(file, z);
    vecs.emplace_back(std::move(Vec3{x, y, z}));
  }
}

// print_orentations prints the position info of the requested molecules
// NOTE: this function assumes that all species requested for printing
// actually exist and are surface molecule species.
void print_orientations(const SpecMap& specs, const CmdlOpts& cmdlOpts) {
  for (const auto& s : cmdlOpts.specs) {
    if (cmdlOpts.addSeparator) {
      std::cout << "--- " << s << "\n";
    }
    for (const auto& v : specs.at(s).orient) {
      std::cout << v << "\n";
    }
  }
}

// print_positions prints the position info of the requested molecules
// NOTE: this function assumes that all species requested for printing
// actually exist.
void print_positions(const SpecMap& specs, const CmdlOpts& cmdlOpts) {
  for (const auto& s : cmdlOpts.specs) {
    if (cmdlOpts.addSeparator) {
      std::cout << "--- " << s << "\n";
    }
    for (const auto& v : specs.at(s).pos) {
      std::cout << v << "\n";
    }
  }
}

// extract_and_check_species check is the requested species (for printing)
// exists. If not returns an error string. If no species were requested
// picks all available species as default. If no errors were encountered
// return an empty string.
std::string extract_and_check_species(const SpecMap& specMap,
                                      CmdlOpts& cmdlOpts) {
  for (const auto& s : cmdlOpts.specs) {
    if (specMap.find(s) == specMap.end()) {
      return "Unknown species " + s + " requested";
    }
  }

  if (cmdlOpts.specs.size() == 0) {
    std::transform(specMap.begin(), specMap.end(),
                   std::back_inserter(cmdlOpts.specs),
                   [](const auto& p) { return p.first; });
  }
  return "";
}

// usage prints a quick usage info
void usage() {
  std::cout
      << "cb_info v0.1    (C) 2015 Markus Dittrich\n\n"
      << "usage: cb_info [options] <file1> <file2> ....\n\n"
      << "Options:"
      << "\n"
      << "\t-i, --species_info       print names of species and number of\n"
      << "\t                         available molecules\n"
      << "\t-p, --print_mol_positions print the (x,y,z) positions of all\n"
      << "\t                          molecules of species type\n"
      << "\t-o, --print_mol_orientations print the orientations of all\n"
      << "\t                             molecules of species type\n"
      << "\t                             (empty string \"\" implies all "
         "species)\n"
      << "\t-s, --add_separator      add separator between species in "
         "printout\n"
      << "\t-a, --analyze_positions  checks if molecules are uniformly "
         "distributed\n"
      << "\t-n, --species_name       name of species to print\n"
      << "\t-h, --help               this help message\n" << std::endl;
}

// longOptions provides the parameters used for command line parsing
static struct option long_options[] = {
    {"species_info", no_argument, NULL, 'i'},
    {"print_mol_positions", no_argument, NULL, 'p'},
    {"print_mol_orientations", no_argument, NULL, 'o'},
    {"add_separator", no_argument, NULL, 's'},
    {"species_name", required_argument, NULL, 'n'},
    {"analyze_positions", no_argument, NULL, 'a'},
    {"help", no_argument, NULL, 'h'}};

// parse_cmdline parses the user provided command line options and
// does some basic sanity checks on them
static CmdlOpts parse_cmdline(int argc, char** argv) {

  int c;
  CmdlOpts cmdlOpts;
  while ((c = getopt_long(argc, argv, "ain:spolh", long_options, NULL)) != -1) {
    switch (c) {
      case 'i':
        cmdlOpts.info = true;
        break;

      case 'p':
        cmdlOpts.listMolPos = true;
        break;

      case 'o':
        cmdlOpts.listMolOrient = true;
        break;

      case 'n':
        cmdlOpts.specs.push_back(optarg);
        break;

      case 's':
        cmdlOpts.addSeparator = true;
        break;

      case 'a':
        cmdlOpts.analyzePositions = true;
        break;

      case 'h':
      default:
        usage();
    }
  }
  while (optind < argc) {
    cmdlOpts.files.push_back(argv[optind++]);
  }

  return cmdlOpts;
}

// check_cmdline_opts does a sanity check of the provided command line
// options. If it finds a problem it returns a string with a description
// and an empty string otherwise.
std::string check_cmdline_opts(const CmdlOpts& cmdl) {
  if (cmdl.files.size() == 0) {
    return "No MCell viz files specified to operate on";
  }
  return "";
}

// error_and_exit aborts the program after printing the provided error
// message and usage info.
void error_and_exit(const std::string& errMsg) {
  std::cerr << "***** ERROR: " << errMsg << "\n\n";
  usage();
  exit(1);
}
<|endoftext|>


<commit_before>#include "point.h"
char* repeat(char c, int count)
{
	// figyeljuk meg, hogy a tomb meretenek nem csak konstanst, hanem
	// akarmilyen erteket megadhatunk
	char *buf = new char[count+1];
	memset(buf, c, count);
	buf[count] = 0;
	return buf;
}
int main()
{
	char *sleep = repeat('z', 10);
	printf("%s\n", sleep);
	// ne felejtsuk el felszabaditani!
	// ha tombot allokaltunk, akkor a delete[] operatort hasznaljuk
	delete[] sleep;

	Point *p = new Point(2, 2);
	// ha nem tomb, akkor siman delete
	delete p;

	return 0;
}
<commit_msg>Added missing header<commit_after>#include <stdio.h>
#include "point.h"

char* repeat(char c, int count)
{
	// figyeljuk meg, hogy a tomb meretenek nem csak konstanst, hanem
	// akarmilyen erteket megadhatunk
	char *buf = new char[count+1];
	memset(buf, c, count);
	buf[count] = 0;
	return buf;
}
int main()
{
	char *sleep = repeat('z', 10);
	printf("%s\n", sleep);
	// ne felejtsuk el felszabaditani!
	// ha tombot allokaltunk, akkor a delete[] operatort hasznaljuk
	delete[] sleep;

	Point *p = new Point(2, 2);
	// ha nem tomb, akkor siman delete
	delete p;

	return 0;
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define URHO3D_OPENGL
#include "../AllUrho.h"
#include "glue.h"
using namespace Urho3D;

//
// This is just an implemention of EventHandler that can be used with function
// pointers, so we can register delegates from C#
//

extern "C" {

	void * urho_map_urho_map_get_ptr (VariantMap &map, int hash)
	{
		StringHash h (hash);
		return map [h].GetVoidPtr ();
	}

	Urho3D::String urho_map_get_String (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetString ();
	}

	int urho_map_get_StringHash (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetStringHash ().Value ();
	}

	Variant urho_map_get_Variant (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h];
	}

	Vector3 urho_map_get_Vector3 (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetVector3 ();
	}

	bool urho_map_get_bool (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetBool ();
	}

	float urho_map_get_float (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetFloat ();
	}

	int urho_map_get_int (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetInt ();
	}

	uint urho_map_get_uint (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetUInt ();
	}

	void urho_map_get_buffer (VariantMap &map, int hash, void **buffer, unsigned *size)
	{
		StringHash h (hash);
		PODVector<unsigned char> p (map [h].GetBuffer ());
		*size  = p.Size ();
		*buffer = (void *) &p.Front();
	}

	int Network_Connect (Network *net, const char *ptr, short port, Scene *scene)
	{
		String s(ptr);

		return net->Connect (s, port, scene) ? 1 : 0;
	}

	void *TouchState_GetTouchedElement (TouchState *state)
	{
		return (void *) state->GetTouchedElement ();
	}

	const char *Urho_GetPlatform ()
	{
		return strdup (GetPlatform().CString ());
	}

	unsigned urho_stringhash_from_string (const char *p)
	{
		StringHash foo (p);
		return foo.Value ();
	}

	Skeleton *AnimatedModel_GetSkeleton (AnimatedModel *model)
	{
		return &model->GetSkeleton ();
	}

	//
	// returns: null on no matches
	// otherwise, a pointer that should be released with free() that
	// contains a first element (pointer sized) with the number of elements
	// followed by the number of pointers
	//
	void *urho_node_get_components (Node *node, int code, int recursive, int *count)
	{
		PODVector<Node*> dest;
		node->GetChildrenWithComponent (dest, StringHash(code), recursive);
		if (dest.Size () == 0)
			return NULL;
		*count = dest.Size ();
		void **t = (void **) malloc (sizeof(Node*)*dest.Size());
		for (int i = 0; i < dest.Size (); i++){
			t [i] = dest [i];
		}
		return t;
	}

void *
create_notification (Object *receiver, HandlerFunctionPtr callback, void *data)
{
	return (void *) new NotificationProxy (receiver, callback, data);
}

#if false

	// Stuff to check interop
void check1 (Context *app)
{

	ResourceCache* cache = app->GetSubsystem<ResourceCache>();
	Texture2D* logoTexture = cache->GetResource<Texture2D>("Textures/LogoLarge.png");
	printf ("LOGOTEXTURE %p\n", logoTexture);

        auto x = app->GetSubsystems ();
        for (auto i = x.Begin(); i != x.End(); ++i){
                printf ("got %s\n", i->second_.Get ()->GetTypeName().CString ());
        }
        void *g = app->GetSubsystem<Graphics>();
        printf ("GGGG->%p\n", g);
}

	class Vector3i {
	public:
		Vector3i(int a, int b, int c):x(a),y(b),z(c) {}
		int x, y, z;

	};

	struct Vector2i {
	public:
		int a, b;
		Vector2i (int a1, int b1):a(a1),b(b1) {}
	};

	Vector3i a (0xdeadbeef,0xcafebabe,0xfeed8001);
	Vector3i &Readl_getVector3 ()
	{
		return a;
	}

	Vector3i getVector3 ()
	{
		return Readl_getVector3 ();
	}

	void check2 (Vector3& vec)
	{
		printf ("Got %g %g %g\n", vec.x_, vec.y_, vec.z_);
	}

	Urho3D::IntVector2
	Input_GetMousePosition (Input *_target);

	Vector2i Foo1 ()
	{
		return Vector2i(0xb00bf00d, 0xfeedc0de);
	}

	Urho3D::IntVector2 Foo2 ()
	{
		return Urho3D::IntVector2(0xdeadbeef,0xdecafbab);
	}

	Vector2i Test2 (Input *inp)
	{
		return *((Vector2i *)&inp->GetMouseMove ());
	}

//void check2 (ResourceCache *rc)
//{
//        auto x = rc->GetSubsystems ();
//        for (auto i = x.Begin(); i != x.End(); ++i){
//                printf ("got %s\n", i->second_.Get ()->GetTypeName().CString ());
//        }
//        void *g = rc->GetSubsystem<Graphics>();
//        printf ("GGGG->%x\n", g);
//}
#endif

}

<commit_msg>close #35, looks like a type in glue.cpp<commit_after>#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define URHO3D_OPENGL
#include "../AllUrho.h"
#include "glue.h"
using namespace Urho3D;

//
// This is just an implemention of EventHandler that can be used with function
// pointers, so we can register delegates from C#
//

extern "C" {

	void * urho_map_get_ptr (VariantMap &map, int hash)
	{
		StringHash h (hash);
		return map [h].GetVoidPtr ();
	}

	Urho3D::String urho_map_get_String (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetString ();
	}

	int urho_map_get_StringHash (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetStringHash ().Value ();
	}

	Variant urho_map_get_Variant (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h];
	}

	Vector3 urho_map_get_Vector3 (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetVector3 ();
	}

	bool urho_map_get_bool (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetBool ();
	}

	float urho_map_get_float (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetFloat ();
	}

	int urho_map_get_int (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetInt ();
	}

	uint urho_map_get_uint (VariantMap& map, int hash)
	{
		StringHash h (hash);
		return map [h].GetUInt ();
	}

	void urho_map_get_buffer (VariantMap &map, int hash, void **buffer, unsigned *size)
	{
		StringHash h (hash);
		PODVector<unsigned char> p (map [h].GetBuffer ());
		*size  = p.Size ();
		*buffer = (void *) &p.Front();
	}

	int Network_Connect (Network *net, const char *ptr, short port, Scene *scene)
	{
		String s(ptr);

		return net->Connect (s, port, scene) ? 1 : 0;
	}

	void *TouchState_GetTouchedElement (TouchState *state)
	{
		return (void *) state->GetTouchedElement ();
	}

	const char *Urho_GetPlatform ()
	{
		return strdup (GetPlatform().CString ());
	}

	unsigned urho_stringhash_from_string (const char *p)
	{
		StringHash foo (p);
		return foo.Value ();
	}

	Skeleton *AnimatedModel_GetSkeleton (AnimatedModel *model)
	{
		return &model->GetSkeleton ();
	}

	//
	// returns: null on no matches
	// otherwise, a pointer that should be released with free() that
	// contains a first element (pointer sized) with the number of elements
	// followed by the number of pointers
	//
	void *urho_node_get_components (Node *node, int code, int recursive, int *count)
	{
		PODVector<Node*> dest;
		node->GetChildrenWithComponent (dest, StringHash(code), recursive);
		if (dest.Size () == 0)
			return NULL;
		*count = dest.Size ();
		void **t = (void **) malloc (sizeof(Node*)*dest.Size());
		for (int i = 0; i < dest.Size (); i++){
			t [i] = dest [i];
		}
		return t;
	}

void *
create_notification (Object *receiver, HandlerFunctionPtr callback, void *data)
{
	return (void *) new NotificationProxy (receiver, callback, data);
}

#if false

	// Stuff to check interop
void check1 (Context *app)
{

	ResourceCache* cache = app->GetSubsystem<ResourceCache>();
	Texture2D* logoTexture = cache->GetResource<Texture2D>("Textures/LogoLarge.png");
	printf ("LOGOTEXTURE %p\n", logoTexture);

        auto x = app->GetSubsystems ();
        for (auto i = x.Begin(); i != x.End(); ++i){
                printf ("got %s\n", i->second_.Get ()->GetTypeName().CString ());
        }
        void *g = app->GetSubsystem<Graphics>();
        printf ("GGGG->%p\n", g);
}

	class Vector3i {
	public:
		Vector3i(int a, int b, int c):x(a),y(b),z(c) {}
		int x, y, z;

	};

	struct Vector2i {
	public:
		int a, b;
		Vector2i (int a1, int b1):a(a1),b(b1) {}
	};

	Vector3i a (0xdeadbeef,0xcafebabe,0xfeed8001);
	Vector3i &Readl_getVector3 ()
	{
		return a;
	}

	Vector3i getVector3 ()
	{
		return Readl_getVector3 ();
	}

	void check2 (Vector3& vec)
	{
		printf ("Got %g %g %g\n", vec.x_, vec.y_, vec.z_);
	}

	Urho3D::IntVector2
	Input_GetMousePosition (Input *_target);

	Vector2i Foo1 ()
	{
		return Vector2i(0xb00bf00d, 0xfeedc0de);
	}

	Urho3D::IntVector2 Foo2 ()
	{
		return Urho3D::IntVector2(0xdeadbeef,0xdecafbab);
	}

	Vector2i Test2 (Input *inp)
	{
		return *((Vector2i *)&inp->GetMouseMove ());
	}

//void check2 (ResourceCache *rc)
//{
//        auto x = rc->GetSubsystems ();
//        for (auto i = x.Begin(); i != x.End(); ++i){
//                printf ("got %s\n", i->second_.Get ()->GetTypeName().CString ());
//        }
//        void *g = rc->GetSubsystem<Graphics>();
//        printf ("GGGG->%x\n", g);
//}
#endif

}

<|endoftext|>