<commit_before>/*
 * GenericShell.cc
 *
 * Generic interactive shell
 * Copyright (c) 2008, 2013, 2014 Linas Vepstas <linas@linas.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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 Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <thread>

#include <opencog/util/Logger.h>
#include <opencog/util/platform.h>

#include <opencog/cogserver/server/ConsoleSocket.h>
#include <opencog/eval/GenericEval.h>
#include "GenericShell.h"

using namespace opencog;

// Some random RFC 854 characters
#define IAC 0xff  // Telnet Interpret As Command
#define IP 0xf4   // Telnet IP Interrupt Process
#define AO 0xf5   // Telnet AO Abort Output
#define EL 0xf8   // Telnet EL Erase Line
#define WILL 0xfb // Telnet WILL
#define DO 0xfd   // Telnet DO
#define TIMING_MARK 0x6 // Telnet RFC 860 timing mark

// Some random ASCII control characters (unix semantics)
#define EOT 0x4   // end    or ^D at keyboard.
#define SYN 0x16  // quit   or ^C at keyboard.
#define CAN 0x18  // cancel or ^X at keyboard.
#define ESC 0x1b  // ecsape or ^[ at keyboard.

GenericShell::GenericShell(void)
{
	show_output = true;
	show_prompt = true;
	normal_prompt = "> ";
	pending_prompt = "... ";
	abort_prompt = "asdf"; // simply reserve 4 chars
	abort_prompt[0] = IAC;
	abort_prompt[1] = WILL;
	abort_prompt[2] = TIMING_MARK;
	abort_prompt[3] = '\n';

	evaluator = NULL;
	socket = NULL;
	evalthr = NULL;
	self_destruct = false;
	do_async_output = false;
}

GenericShell::~GenericShell()
{
	if (evalthr)
	{
		evalthr->join();
		delete evalthr;
		evalthr = NULL;
	}

	if (socket)
	{
		socket->SetShell(NULL);
		socket->OnRequestComplete();
		socket = NULL;
	}
}

void GenericShell::socketClosed(void)
{
	// As of right now, the only thing that calls methods on us is the
	// console socket. Thus, when the console socket closes, no one
	// else will ever call a method on this instance ever again. Thus,
	// we should self-destruct. Three remarks:
	// 1) This wouldn't be needed if we had garbage collection, and
	//    (or maybe used smart pointers to manage this object ???)
	// 2) If this feels hacky to you, well, it is, but I simply do not
	//    see a solution that is easier/better/simpler within the
	//    confines of the current module/socket/request design. (I can
	//    envision all sorts of complicated solutions, but none easy).
	// 3) This is safe in the current threading design, since the thread
	//    that is calling eval() is the same thread that is calling this
	//    method. Thus, no locks.  That is, the socket won't close until
	//    this->eval() returns.  This must not be changed, as otherwise
	//    hard-to-debug races and crashes will ensue.
	// 4) In short: don't change this.
	delete this;
}

/* ============================================================== */

void GenericShell::hush_output(bool hush)
{
	show_output = !hush;
}

void GenericShell::hush_prompt(bool hush)
{
	show_prompt = !hush;
}

void GenericShell::sync_output(bool sync)
{
	do_async_output = !sync;
}

const std::string& GenericShell::get_prompt(void)
{
	static const std::string empty_prompt = "";
	if (!show_prompt) return empty_prompt;

	// Use different prompts, depending on whether there is pending
	// input or not.
	if (evaluator->input_pending())
	{
		return pending_prompt;
	}
	else
	{
		return normal_prompt;
	}
}

/* ============================================================== */
/**
 * Register this shell with the console.
 */
void GenericShell::set_socket(ConsoleSocket *s)
{
	if (socket)
	{
		socket->SetShell(NULL);
		socket->OnRequestComplete();
	}

	socket = s;
	socket->SetShell(this);
}

/* ============================================================== */

void GenericShell::eval(const std::string &expr, ConsoleSocket *s)
{
	// XXX A subtle but important point: the way that socket handling
	// works in OpenCog is that socket-listen/accept happens in one
	// thread, while socket receive is in another. In particular, the
	// constructor for this class runs in a *different* thread than
	// this method does.
	if (NULL == socket)
	{
		socket = s;
	}

	// Launch the evaluator, possibly in a different thread,
	// and then send out whatever is reported back.
	line_discipline(expr);
	std::string retstr = poll_output();
	while (0 < retstr.size())
	{
		socket->Send(retstr);
		retstr = poll_output();
	}

	// The user is exiting the shell. No one will ever call a method on
	// this instance ever again. So stop hogging space, and self-destruct.
	// We have to do this here; there is no other opportunity to call dtor.
	if (self_destruct)
	{
		socket->sendPrompt();
		delete this;
	}
}

/* ============================================================== */
/**
 * Handle special characters, evaluate the expression
 */
void GenericShell::line_discipline(const std::string &expr)
{
	size_t len = expr.length();

	logger().debug("[GenericShell] line disc: expr, len of %zd ='%s'",
		len, expr.c_str());

	// Make sure there is at least one character if we are checking
	// for abort, interrrupt, escape, etc.
	if (0 != len)
	{
		// Handle Telnet RFC 854 IAC format
		// Basically, we're looking for telnet-encoded abort or interrupt
		// characters, starting at the end of the input string. If they
		// are there, then don't process input, and clear out the evaluator.
		// Also, be sure to send telnet IAC WILL TIMING-MARK so that telnet
		// doesn't sit there flushing output forever.
		//
		// Search for IAC to at most 20 chars from the end of the string.
		int i = len-2;
		int m = len - 20;
		if (m < 0) m = 0;
		while (m <= i)
		{
			unsigned char c = expr[i];
			if (IAC == c)
			{
				c = expr[i+1];
				if ((IP == c) || (AO == c))
				{
					evaluator->clear_pending();
					put_output(abort_prompt);
					return;
				}

				// Erase line -- just ignore this line.
				if (EL == c)
				{
					put_output(get_prompt());
					return;
				}
			}
			i--;
		}

		// Don't evaluate if the line is terminated by
		// escape (^[), cancel (^X) or quit (^C)
		// These would typically be sent by netcat, and not telnet.
		unsigned char c = expr[len-1];
		if ((SYN == c) || (CAN == c) || (ESC == c))
		{
			evaluator->clear_pending();
			put_output("\n");
			put_output(normal_prompt);
			return;
		}

		// Look for either an isolated control-D, or a single period on a line
		// by itself. This means "leave the shell". We leave the shell by
		// unsetting the shell pointer in the ConsoleSocket.
		// 0x4 is ASCII EOT, which is what ctrl-D at keybd becomes.
		if ((false == evaluator->input_pending()) and
		    ((EOT == expr[len-1]) or ((1 == len) and ('.' == expr[0]))))
		{
			self_destruct = true;
			put_output("");
			if (show_prompt)
				put_output("Exiting the shell\n");
			return;
		}
	}

	/*
	 * The newline is always cut. Re-insert it; otherwise, comments
	 * within procedures will have the effect of commenting out the
	 * rest of the procedure, leading to garbage.
	 * (This is a pointless string copy, it should be eliminated.)
	 */
	std::string input = expr + "\n";
	do_eval(input);
}

/* ============================================================== */
/**
 * Evaluate the expression. Assumes line discipline was already done.
 */
void GenericShell::do_eval(const std::string &input)
{
	eval_done = false;
	evaluator->begin_eval(); // must be called in same thread as result_poll
	if (do_async_output)
	{
		auto async_wrapper = [&](GenericShell* p, const std::string& in)
		{
			thread_init();
			p->evaluator->eval_expr(in.c_str());
		};

		// We cannot use the same evaluator in two different threads
		// at the same time; a single evaluator is not thread-safe
		// against itself. So always wait for the previous thread to
		// finish, before we go at it again.
		if (evalthr)
		{
			evalthr->join();
			delete evalthr;
		}
		evalthr = new std::thread(async_wrapper, this, input);
	}
	else
	{
		evaluator->eval_expr(input.c_str());
	}
}

void GenericShell::thread_init(void)
{
	/* No-op. The Scheme shell sets the current atomspace here */
}

/* ============================================================== */

void GenericShell::put_output(const std::string& s)
{
	pending_output += s;
}

std::string GenericShell::poll_output()
{
	// If there's pending output, return that.
	if (0 < pending_output.size())
	{
		std::string result = pending_output;
		pending_output.clear();
		return result;
	}

	// If we are here, there's no pending output. Does the
	// evaluator have anything for us?
	std::string result = evaluator->poll_result();
	if (0 < result.size())
		return result;

	// If we are here, the evaluator is done. Return shell prompts.
	if (eval_done) return "";
	eval_done = true;

	if (evaluator->input_pending())
	{
		if (show_output && show_prompt)
			return pending_prompt;
		else
			return "";
	}

	if (show_output || evaluator->eval_error())
	{
		if (show_prompt) return normal_prompt;
	}
	return "";
}

/* ===================== END OF FILE ============================ */
<commit_msg>First attempt to capture python output.<commit_after>/*
 * GenericShell.cc
 *
 * Generic interactive shell
 * Copyright (c) 2008, 2013, 2014 Linas Vepstas <linas@linas.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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 Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <thread>

#include <opencog/util/Logger.h>
#include <opencog/util/platform.h>

#include <opencog/cogserver/server/ConsoleSocket.h>
#include <opencog/eval/GenericEval.h>
#include "GenericShell.h"

using namespace opencog;

// Some random RFC 854 characters
#define IAC 0xff  // Telnet Interpret As Command
#define IP 0xf4   // Telnet IP Interrupt Process
#define AO 0xf5   // Telnet AO Abort Output
#define EL 0xf8   // Telnet EL Erase Line
#define WILL 0xfb // Telnet WILL
#define DO 0xfd   // Telnet DO
#define TIMING_MARK 0x6 // Telnet RFC 860 timing mark

// Some random ASCII control characters (unix semantics)
#define EOT 0x4   // end    or ^D at keyboard.
#define SYN 0x16  // quit   or ^C at keyboard.
#define CAN 0x18  // cancel or ^X at keyboard.
#define ESC 0x1b  // ecsape or ^[ at keyboard.

GenericShell::GenericShell(void)
{
	show_output = true;
	show_prompt = true;
	normal_prompt = "> ";
	pending_prompt = "... ";
	abort_prompt = "asdf"; // simply reserve 4 chars
	abort_prompt[0] = IAC;
	abort_prompt[1] = WILL;
	abort_prompt[2] = TIMING_MARK;
	abort_prompt[3] = '\n';

	evaluator = NULL;
	socket = NULL;
	evalthr = NULL;
	self_destruct = false;
	do_async_output = false;
}

GenericShell::~GenericShell()
{
	if (evalthr)
	{
		evalthr->join();
		delete evalthr;
		evalthr = NULL;
	}

	if (socket)
	{
		socket->SetShell(NULL);
		socket->OnRequestComplete();
		socket = NULL;
	}
}

void GenericShell::socketClosed(void)
{
	// As of right now, the only thing that calls methods on us is the
	// console socket. Thus, when the console socket closes, no one
	// else will ever call a method on this instance ever again. Thus,
	// we should self-destruct. Three remarks:
	// 1) This wouldn't be needed if we had garbage collection, and
	//    (or maybe used smart pointers to manage this object ???)
	// 2) If this feels hacky to you, well, it is, but I simply do not
	//    see a solution that is easier/better/simpler within the
	//    confines of the current module/socket/request design. (I can
	//    envision all sorts of complicated solutions, but none easy).
	// 3) This is safe in the current threading design, since the thread
	//    that is calling eval() is the same thread that is calling this
	//    method. Thus, no locks.  That is, the socket won't close until
	//    this->eval() returns.  This must not be changed, as otherwise
	//    hard-to-debug races and crashes will ensue.
	// 4) In short: don't change this.
	delete this;
}

/* ============================================================== */

void GenericShell::hush_output(bool hush)
{
	show_output = !hush;
}

void GenericShell::hush_prompt(bool hush)
{
	show_prompt = !hush;
}

void GenericShell::sync_output(bool sync)
{
	do_async_output = !sync;
}

const std::string& GenericShell::get_prompt(void)
{
	static const std::string empty_prompt = "";
	if (!show_prompt) return empty_prompt;

	// Use different prompts, depending on whether there is pending
	// input or not.
	if (evaluator->input_pending())
	{
		return pending_prompt;
	}
	else
	{
		return normal_prompt;
	}
}

/* ============================================================== */
/**
 * Register this shell with the console.
 */
void GenericShell::set_socket(ConsoleSocket *s)
{
	if (socket)
	{
		socket->SetShell(NULL);
		socket->OnRequestComplete();
	}

	socket = s;
	socket->SetShell(this);
}

/* ============================================================== */

void GenericShell::eval(const std::string &expr, ConsoleSocket *s)
{
	// XXX A subtle but important point: the way that socket handling
	// works in OpenCog is that socket-listen/accept happens in one
	// thread, while socket receive is in another. In particular, the
	// constructor for this class runs in a *different* thread than
	// this method does.
	if (NULL == socket)
	{
		socket = s;
	}

	// What used to be stdout will now go to the pipe.
	int pipefd[2];
	pipe2(pipefd, 0);  // O_NONBLOCK);
	int stdout_backup = dup(fileno(stdout));
	dup2(pipefd[1], fileno(stdout));

	// Launch the evaluator, possibly in a different thread,
	// and then send out whatever is reported back.
	line_discipline(expr);
	std::string retstr = poll_output();
	while (0 < retstr.size())
	{
		socket->Send(retstr);
		retstr = poll_output();
	}

	// Restore stdout
	fflush(stdout);
	write(pipefd[1], "", 1); // null-terminated string!
	close(pipefd[1]);
	dup2(stdout_backup, fileno(stdout)); // restore stdout

	// Drain the pipe
	char buf[4996];
	int nr = read(pipefd[0], buf, sizeof(buf));
	while (0 < nr)
	{
		printf("duuuuude its %s\n", buf);
		retstr = buf;
		socket->Send(retstr);
		nr = read(pipefd[0], buf, sizeof(buf));
	}

	// cleanup.
	close(pipefd[0]);

	// The user is exiting the shell. No one will ever call a method on
	// this instance ever again. So stop hogging space, and self-destruct.
	// We have to do this here; there is no other opportunity to call dtor.
	if (self_destruct)
	{
		socket->sendPrompt();
		delete this;
	}
}

/* ============================================================== */
/**
 * Handle special characters, evaluate the expression
 */
void GenericShell::line_discipline(const std::string &expr)
{
	size_t len = expr.length();

	logger().debug("[GenericShell] line disc: expr, len of %zd ='%s'",
		len, expr.c_str());

	// Make sure there is at least one character if we are checking
	// for abort, interrrupt, escape, etc.
	if (0 != len)
	{
		// Handle Telnet RFC 854 IAC format
		// Basically, we're looking for telnet-encoded abort or interrupt
		// characters, starting at the end of the input string. If they
		// are there, then don't process input, and clear out the evaluator.
		// Also, be sure to send telnet IAC WILL TIMING-MARK so that telnet
		// doesn't sit there flushing output forever.
		//
		// Search for IAC to at most 20 chars from the end of the string.
		int i = len-2;
		int m = len - 20;
		if (m < 0) m = 0;
		while (m <= i)
		{
			unsigned char c = expr[i];
			if (IAC == c)
			{
				c = expr[i+1];
				if ((IP == c) || (AO == c))
				{
					evaluator->clear_pending();
					put_output(abort_prompt);
					return;
				}

				// Erase line -- just ignore this line.
				if (EL == c)
				{
					put_output(get_prompt());
					return;
				}
			}
			i--;
		}

		// Don't evaluate if the line is terminated by
		// escape (^[), cancel (^X) or quit (^C)
		// These would typically be sent by netcat, and not telnet.
		unsigned char c = expr[len-1];
		if ((SYN == c) || (CAN == c) || (ESC == c))
		{
			evaluator->clear_pending();
			put_output("\n");
			put_output(normal_prompt);
			return;
		}

		// Look for either an isolated control-D, or a single period on a line
		// by itself. This means "leave the shell". We leave the shell by
		// unsetting the shell pointer in the ConsoleSocket.
		// 0x4 is ASCII EOT, which is what ctrl-D at keybd becomes.
		if ((false == evaluator->input_pending()) and
		    ((EOT == expr[len-1]) or ((1 == len) and ('.' == expr[0]))))
		{
			self_destruct = true;
			put_output("");
			if (show_prompt)
				put_output("Exiting the shell\n");
			return;
		}
	}

	/*
	 * The newline is always cut. Re-insert it; otherwise, comments
	 * within procedures will have the effect of commenting out the
	 * rest of the procedure, leading to garbage.
	 * (This is a pointless string copy, it should be eliminated.)
	 */
	std::string input = expr + "\n";
	do_eval(input);
}

/* ============================================================== */
/**
 * Evaluate the expression. Assumes line discipline was already done.
 */
void GenericShell::do_eval(const std::string &input)
{
	eval_done = false;
	evaluator->begin_eval(); // must be called in same thread as result_poll
	if (do_async_output)
	{
		auto async_wrapper = [&](GenericShell* p, const std::string& in)
		{
			thread_init();
			p->evaluator->eval_expr(in.c_str());
		};

		// We cannot use the same evaluator in two different threads
		// at the same time; a single evaluator is not thread-safe
		// against itself. So always wait for the previous thread to
		// finish, before we go at it again.
		if (evalthr)
		{
			evalthr->join();
			delete evalthr;
		}
		evalthr = new std::thread(async_wrapper, this, input);
	}
	else
	{
		evaluator->eval_expr(input.c_str());
	}
}

void GenericShell::thread_init(void)
{
	/* No-op. The Scheme shell sets the current atomspace here */
}

/* ============================================================== */

void GenericShell::put_output(const std::string& s)
{
	pending_output += s;
}

std::string GenericShell::poll_output()
{
	// If there's pending output, return that.
	if (0 < pending_output.size())
	{
		std::string result = pending_output;
		pending_output.clear();
		return result;
	}

	// If we are here, there's no pending output. Does the
	// evaluator have anything for us?
	std::string result = evaluator->poll_result();
	if (0 < result.size())
		return result;

	// If we are here, the evaluator is done. Return shell prompts.
	if (eval_done) return "";
	eval_done = true;

	if (evaluator->input_pending())
	{
		if (show_output && show_prompt)
			return pending_prompt;
		else
			return "";
	}

	if (show_output || evaluator->eval_error())
	{
		if (show_prompt) return normal_prompt;
	}
	return "";
}

/* ===================== END OF FILE ============================ */
<|endoftext|>


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

#include "stdafx.h"
#include "BlackBerryBus.h"
#include <QWebFrame>

using namespace BlackBerry::Starbuck;

QMap<QString, QList<CallbackInfo>*> BlackBerryBus::_listener;

BlackBerryBus::BlackBerryBus(QObject *parent, QWebFrame *webFrame)
  : QObject(parent), m_pWebFrame(webFrame)
{
    // seed the random generator
    qsrand(QTime::currentTime().msec());
}

BlackBerryBus::~BlackBerryBus()
{

}

QString BlackBerryBus::generateRandomFunctionName()
{
    const char *alphaSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    QString name;

    name = "z"; // needs to start with a character so lets make everything start with z

    for (int i = 0; i < 20; i++)
    {
        name += alphaSet[qrand() % strlen(alphaSet) + 0];
    }

    return name;
}

// async version of trigger function
void BlackBerryBus::trigger(QString eventName, QString jsonData, bool async)
{
    if (async)
    {
      if (_listener[eventName])
      {
        QList<CallbackInfo>* info = _listener[eventName];
        for(int i = 0; i < (*info).length(); i++)
        {
          CallbackInfo callback = (*info)[i];
          QString evalString("eventbus.trigger('" + eventName + "', '" + jsonData + "')");
          QVariant res = callback.frame->evaluateJavaScript("setTimeout(\"" + evalString + "\", 1)");
        }
      }
    }
    else
        trigger(eventName, jsonData);
}

void BlackBerryBus::trigger(QString eventName, QString jsonData)
{
  if (_listener[eventName])
  {
    QList<CallbackInfo>* info = _listener[eventName];
    for(int i = 0; i < (*info).length(); i++)
    {
      CallbackInfo callback = (*info)[i];
      QString evalString("eventbus.trigger('" + eventName + "', '" + jsonData + "')");
      QVariant res = callback.frame->evaluateJavaScript(evalString);
    }
  }
}

QString BlackBerryBus::on(QString eventName, QString jsonCallback)
{
  QList<CallbackInfo>* info = 0;

  if (_listener.contains(eventName) )
    info = _listener[eventName];
  else
    info = new QList<CallbackInfo>();

  CallbackInfo callback;
  callback.function = generateRandomFunctionName();
  callback.frame = this->m_pWebFrame;

  info->append(callback);

  _listener.insert(eventName, info);

  return callback.function;
}

QString BlackBerryBus::getFunctionName(QString input)
{
    QList<CallbackInfo>* info = 0;
    QString result;

    if (_listener.contains(input) )
    {
        info = _listener[input];
        for (int i = 0; i<info->length(); i++)
        {
            if (!result.isEmpty())
                result += ";";

            result += (*info)[i].function;
        }
    }

    return result;
}
<commit_msg>Fixed a logic error in eventbus code<commit_after>/*
* Copyright 2010-2011 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "stdafx.h"
#include "BlackBerryBus.h"
#include <QWebFrame>

using namespace BlackBerry::Starbuck;

QMap<QString, QList<CallbackInfo>*> BlackBerryBus::_listener;

BlackBerryBus::BlackBerryBus(QObject *parent, QWebFrame *webFrame)
  : QObject(parent), m_pWebFrame(webFrame)
{
    // seed the random generator
    qsrand(QTime::currentTime().msec());
}

BlackBerryBus::~BlackBerryBus()
{

}

QString BlackBerryBus::generateRandomFunctionName()
{
    const char *alphaSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    QString name;

    name = "z"; // needs to start with a character so lets make everything start with z

    for (int i = 0; i < 20; i++)
    {
        name += alphaSet[qrand() % strlen(alphaSet) + 0];
    }

    return name;
}

// async version of trigger function
void BlackBerryBus::trigger(QString eventName, QString jsonData, bool async)
{
    if (async)
    {
      if (_listener[eventName])
      {
        QList<CallbackInfo>* info = _listener[eventName];
        for(int i = 0; i < (*info).length(); i++)
        {
          CallbackInfo callback = (*info)[i];
          QString evalString("eventbus.trigger('" + eventName + "', '" + jsonData + "')");
          QVariant res = callback.frame->evaluateJavaScript("setTimeout(\"" + evalString + "\", 1)");
        }
      }
    }
    else
        trigger(eventName, jsonData);
}

void BlackBerryBus::trigger(QString eventName, QString jsonData)
{
  if (_listener.contains(eventName))
  {
    QList<CallbackInfo>* info = _listener[eventName];
    for(int i = 0; i < (*info).length(); i++)
    {
      CallbackInfo callback = (*info)[i];
      QString evalString("eventbus.trigger('" + eventName + "', '" + jsonData + "')");
      QVariant res = callback.frame->evaluateJavaScript(evalString);
    }
  }
}

QString BlackBerryBus::on(QString eventName, QString jsonCallback)
{
  QList<CallbackInfo>* info = 0;

  if (_listener.contains(eventName) )
    info = _listener[eventName];
  else
    info = new QList<CallbackInfo>();

  CallbackInfo callback;
  callback.function = generateRandomFunctionName();
  callback.frame = this->m_pWebFrame;

  info->append(callback);

  _listener.insert(eventName, info);

  return callback.function;
}

QString BlackBerryBus::getFunctionName(QString input)
{
    QList<CallbackInfo>* info = 0;
    QString result;

    if (_listener.contains(input) )
    {
        info = _listener[input];
        for (int i = 0; i<info->length(); i++)
        {
            if (!result.isEmpty())
                result += ";";

            result += (*info)[i].function;
        }
    }

    return result;
}
<|endoftext|>


<commit_before>/**
 * Appcelerator Titanium - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2009 Appcelerator, Inc. All Rights Reserved.
 */

#include <windows.h>
#include <objbase.h>
#include <Wininet.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include "Progress.h"
#include "Resource.h"

#define alert(msg) MessageBoxA(GetDesktopWindow(), msg, "Message", MB_OK);
#define walert(msg) MessageBoxW(GetDesktopWindow(), msg, L"Message", MB_OK);

#define DISTRIBUTION_UUID	L"7F7FA377-E695-4280-9F1F-96126F3D2C2A"
#define RUNTIME_UUID		L"A2AC5CB5-8C52-456C-9525-601A5B0725DA"
#define MODULE_UUID			L"1ACE5D3A-2B52-43FB-A136-007BD166CFD0"

std::wstring ParseQueryParam(std::wstring uri, std::wstring name)
{
	std::wstring key = name;
	key+=L"=";
	size_t pos = uri.find(key);
	if (pos!=std::wstring::npos)
	{
		std::wstring p = uri.substr(pos + key.length());
		pos = p.find(L"&");
		if (pos!=std::wstring::npos)
		{
			p = p.substr(0,pos);
		}

		// decode
		WCHAR szOut[INTERNET_MAX_URL_LENGTH];
		DWORD cchDecodedUrl = INTERNET_MAX_URL_LENGTH;
		CoInternetParseUrl(p.c_str(), PARSE_UNESCAPE, 0, szOut, INTERNET_MAX_URL_LENGTH, &cchDecodedUrl, 0);
		p.assign(szOut);

		return p;
	}
	return L"";
}

std::wstring ProgressString(DWORD size, DWORD total)
{
	char str[1024];

#define KB 1024
#define MB KB * 1024

	if (total < KB) {
		sprintf(str, "%0.2f of %0.2f bytes", size, total);
	}

	else if (size < MB) {
		double totalKB = total/1024.0;
		double sizeKB = size/1024.0;
		sprintf(str, "%0.2f of %0.2f KB", sizeKB, totalKB);
	}

	else {
		// hopefully we shouldn't ever need to count more than 1023 in a single file!
		double totalMB = total/1024.0/1024.0;
		double sizeMB = size/1024.0/1024.0;
		sprintf(str, "%0.2f of %0.2f MB", size, total);
	}

	wchar_t wstr[1024];
	mbtowc(wstr, str, strlen(str));
	return std::wstring(wstr);
}

bool DownloadURL(Progress *p, HINTERNET hINet, std::wstring url, std::wstring outFilename)
{
	WCHAR szDecodedUrl[INTERNET_MAX_URL_LENGTH];
	DWORD cchDecodedUrl = INTERNET_MAX_URL_LENGTH;
	WCHAR szDomainName[INTERNET_MAX_URL_LENGTH];

	// parse the URL
	HRESULT hr = CoInternetParseUrl(url.c_str(), PARSE_DECODE, URL_ENCODING_NONE, szDecodedUrl,
                    INTERNET_MAX_URL_LENGTH, &cchDecodedUrl, 0);
	if (hr != S_OK)
	{
		return false;
	}

	// figure out the domain/hostname
	hr = CoInternetParseUrl(szDecodedUrl, PARSE_DOMAIN, 0, szDomainName, INTERNET_MAX_URL_LENGTH, &cchDecodedUrl, 0);
	if (hr != S_OK)
	{
		return false;
	}

	// TODO - how to cancel download if user presses the Cancel button

	// start the HTTP fetch
	HINTERNET hConnection = InternetConnectW( hINet, szDomainName, 80, L" ", L" ", INTERNET_SERVICE_HTTP, 0, 0 );
	if ( !hConnection )
	{
		return false;
	}

	std::wstring wurl(szDecodedUrl);
	std::wstring path = wurl.substr(wurl.find(szDomainName)+wcslen(szDomainName));
	//std::wstring queryString = url.substr(url.rfind("?")+1);
	//astd::wstring object = path + "?" + queryString;

	HINTERNET hRequest = HttpOpenRequestW( hConnection, L"GET", path.c_str(), NULL, NULL, NULL, INTERNET_FLAG_RELOAD|INTERNET_FLAG_NO_CACHE_WRITE|INTERNET_FLAG_NO_COOKIES|INTERNET_FLAG_NO_UI|INTERNET_FLAG_IGNORE_CERT_CN_INVALID|INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, 0 );

	if ( !hRequest )
	{
		InternetCloseHandle(hConnection);
		return false;
	}

	// now stream the resulting HTTP into a file
	std::ofstream ostr;
	ostr.open(outFilename.c_str(), std::ios_base::binary | std::ios_base::trunc);

	bool failed = false;

	CHAR buffer[2048];
	DWORD dwRead;
	DWORD total = 0;
	wchar_t msg[255];

	HttpSendRequest( hRequest, NULL, 0, NULL, 0);
	while( InternetReadFile( hRequest, buffer, 2047, &dwRead ) )
	{
		if ( dwRead == 0)
		{
			break;
		}
		if (p->IsCancelled())
		{
			failed = true;
			break;
		}
		buffer[dwRead] = '\0';
		total+=dwRead;
		ostr.write(buffer, dwRead);
		wsprintfW(msg,L"Downloaded %d KB",total/1024);
		p->SetLineText(2,msg,true);
	}
	ostr.close();
	InternetCloseHandle(hConnection);
	InternetCloseHandle(hRequest);

	return ! failed;
}

bool DownloadURL2(Progress *p, HINTERNET hINet, std::wstring url, std::wstring outFilename)
{
	WCHAR szDecodedUrl[INTERNET_MAX_URL_LENGTH];
	DWORD cchDecodedUrl = INTERNET_MAX_URL_LENGTH;
	HRESULT hr = CoInternetParseUrl(url.c_str(), PARSE_DECODE, URL_ENCODING_NONE, szDecodedUrl, INTERNET_MAX_URL_LENGTH, &cchDecodedUrl, 0);
	if (hr != S_OK)
	{
		return false;
	}

	// start the HTTP fetch
	HINTERNET urlConn = InternetOpenUrlW(hINet, szDecodedUrl, NULL, 0, 0, 0);
	if ( !urlConn )
	{
		return false;
	}

	bool failed = false;

	// now stream the resulting HTTP into a file
	std::ofstream ostr;
	ostr.open(outFilename.c_str(), std::ios_base::binary | std::ios_base::trunc);

	CHAR buffer[2048];
	DWORD dwRead;
	DWORD total = 0;
	wchar_t msg[255];
	while( InternetReadFile(urlConn, buffer, 2047, &dwRead ) )
	{
		if ( dwRead == 0)
		{
			break;
		}
		if (p->IsCancelled())
		{
			failed = true;
			break;
		}
		buffer[dwRead] = '\0';
		total+=dwRead;
		ostr.write(buffer, dwRead);
		wsprintfW(msg,L"Downloaded %d KB",total/1024);
		p->SetLineText(2,msg,true);
	}
	ostr.close();
	InternetCloseHandle(urlConn);

	return ! failed;
}

BOOL DirectoryExists(std::wstring dirName)
{
	DWORD attribs = ::GetFileAttributesW(dirName.c_str());

	if (attribs == INVALID_FILE_ATTRIBUTES) {
		return false;
	}

	return (attribs & FILE_ATTRIBUTE_DIRECTORY);
}

void CreateDirectoryTree(std::wstring dir)
{
	if(! DirectoryExists(dir))
	{
		// ensure parent dir exits
		int lastSlash = dir.find_last_of(L"\\");
		if(lastSlash != std::wstring::npos)
		{
			std::wstring parent = dir.substr(0, lastSlash);

			CreateDirectoryTree(parent);
		}

		// by this point, all parent dirs are created
		CreateDirectoryW(dir.c_str(), NULL);
	}
}

bool UnzipFile(std::wstring unzipper, std::wstring zipFile, std::wstring destdir)
{
	// ensure destdir exists
	CreateDirectoryTree(destdir);

	// now we're going to invoke back into the boot to unzip our file and install
	STARTUPINFOW si;
	PROCESS_INFORMATION pi;
	ZeroMemory( &si, sizeof(si) );
	ZeroMemory( &pi, sizeof(pi) );
	si.cb = sizeof(si);

	std::wstring cmdline = L"\"";
	cmdline+=unzipper;
	cmdline+=L"\" --tiunzip \"";
	cmdline+=zipFile;
	cmdline+=L"\" \"";
	cmdline+=destdir;
	cmdline+=L"\"";

	// in win32, we just invoke back the same process and let him unzip
	if (!CreateProcessW(NULL,(LPWSTR)cmdline.c_str(),NULL,NULL,FALSE,NULL,NULL,NULL,&si,&pi))
	{
		return false;
	}

	// wait for the process to finish unzipping
	WaitForSingleObject(pi.hProcess,INFINITE);

	return true;
}
int WINAPI WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow
)
{
	//TODO: set the icon for this app and dialogs
//	HICON icon = LoadIcon(hInstance,MAKEINTRESOURCE(IDR_MAINFRAME));
//	SendMessage(NULL, WM_SETICON, (WPARAM)true, (LPARAM)icon);

	// get the command line
	LPWSTR cmdline = GetCommandLineW();
    int argcount = 0;
	LPWSTR *args = CommandLineToArgvW(cmdline,&argcount);

	// we must have at least the mandatory args + 1 URL
	if (argcount < 7)
	{
		MessageBoxW(GetDesktopWindow(),L"Invalid arguments passed to Installer",L"Application Error",MB_OK|MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
		return 1;
	}

	std::wstring appname = args[1];
	std::wstring title = args[2];
	std::wstring message = args[3];
	std::wstring appTitle = appname + L" Installer";
	std::wstring tempdir = args[4];
	std::wstring installdir = args[5];
	std::wstring unzipper = args[6];

	// verify the installation
	if (IDOK != MessageBoxW(GetDesktopWindow(),message.c_str(),title.c_str(),MB_ICONINFORMATION|MB_OKCANCEL))
	{
		MessageBoxW(GetDesktopWindow(),L"Installation Aborted. To install later, re-run the application again.", title.c_str(), MB_OK|MB_ICONWARNING);
		return 1;
	}

	int count = argcount - 7;
	int startAt = 7;

	CoInitialize(NULL);

	// create our progress indicator class
	Progress *p = new Progress;
	p->SetTitle(appTitle.c_str());
	p->SetCancelMessage(L"Cancelling, one moment...");

	wchar_t buf[255];
	wsprintfW(buf,L"Preparing to download %d file%s", count, (count > 1 ? L"s" : L""));

	p->SetLineText(1,std::wstring(buf),true);
	p->Show();
	p->Update(0,count);

	// initialize interent DLL
	HINTERNET hINet = InternetOpenW(L"Mozilla/5.0 (compatible; Titanium_Downloader/0.1; Win32)", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );

	// for each URL, fetch the URL and then unzip it
	bool failed = false;
	DWORD x = 0;
	for (int c=startAt;c<argcount;c++)
	{
		p->Update(x++,count);
		std::wstring url = args[c];

		std::wstring uuid = ParseQueryParam(url,L"uuid");
		std::wstring name = ParseQueryParam(url,L"name");
		std::wstring version = ParseQueryParam(url,L"version");
		std::wstring filename = name;
		filename+=L"-";
		filename+=version;
		filename+=L".zip";

		// figure out the path and destination
		std::wstring path = tempdir + L"\\" + filename;
		std::wstring destdir;

		if (RUNTIME_UUID == uuid)
        {
			destdir = installdir + L"\\runtime\\win32\\" + version;
        }
        else if (MODULE_UUID == uuid)
        {
			destdir = installdir + L"\\modules\\win32\\" + name + L"\\" + version;
        }
        else
        {
			continue;
        }

		bool downloaded = DownloadURL(p, hINet, url, path);

		if(downloaded)
		{
			wchar_t msg[255];
			wsprintfW(msg, L"Installing %s/%s ...",name.c_str(),version.c_str());
			p->SetLineText(2,msg,true);
			UnzipFile(unzipper, path, destdir);
		}
	}

	// done with iNet - so close it
	InternetCloseHandle(hINet);

	if (p->IsCancelled())
	{
		failed = true;
	}

	// cleanup
	delete p;

	CoUninitialize();

	return (failed) ? 1 : 0;
}
<commit_msg>remove TODO comment<commit_after>/**
 * Appcelerator Titanium - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2009 Appcelerator, Inc. All Rights Reserved.
 */

#include <windows.h>
#include <objbase.h>
#include <Wininet.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include "Progress.h"
#include "Resource.h"

#define alert(msg) MessageBoxA(GetDesktopWindow(), msg, "Message", MB_OK);
#define walert(msg) MessageBoxW(GetDesktopWindow(), msg, L"Message", MB_OK);

#define DISTRIBUTION_UUID	L"7F7FA377-E695-4280-9F1F-96126F3D2C2A"
#define RUNTIME_UUID		L"A2AC5CB5-8C52-456C-9525-601A5B0725DA"
#define MODULE_UUID			L"1ACE5D3A-2B52-43FB-A136-007BD166CFD0"

std::wstring ParseQueryParam(std::wstring uri, std::wstring name)
{
	std::wstring key = name;
	key+=L"=";
	size_t pos = uri.find(key);
	if (pos!=std::wstring::npos)
	{
		std::wstring p = uri.substr(pos + key.length());
		pos = p.find(L"&");
		if (pos!=std::wstring::npos)
		{
			p = p.substr(0,pos);
		}

		// decode
		WCHAR szOut[INTERNET_MAX_URL_LENGTH];
		DWORD cchDecodedUrl = INTERNET_MAX_URL_LENGTH;
		CoInternetParseUrl(p.c_str(), PARSE_UNESCAPE, 0, szOut, INTERNET_MAX_URL_LENGTH, &cchDecodedUrl, 0);
		p.assign(szOut);

		return p;
	}
	return L"";
}

std::wstring ProgressString(DWORD size, DWORD total)
{
	char str[1024];

#define KB 1024
#define MB KB * 1024

	if (total < KB) {
		sprintf(str, "%0.2f of %0.2f bytes", size, total);
	}

	else if (size < MB) {
		double totalKB = total/1024.0;
		double sizeKB = size/1024.0;
		sprintf(str, "%0.2f of %0.2f KB", sizeKB, totalKB);
	}

	else {
		// hopefully we shouldn't ever need to count more than 1023 in a single file!
		double totalMB = total/1024.0/1024.0;
		double sizeMB = size/1024.0/1024.0;
		sprintf(str, "%0.2f of %0.2f MB", size, total);
	}

	wchar_t wstr[1024];
	mbtowc(wstr, str, strlen(str));
	return std::wstring(wstr);
}

bool DownloadURL(Progress *p, HINTERNET hINet, std::wstring url, std::wstring outFilename)
{
	WCHAR szDecodedUrl[INTERNET_MAX_URL_LENGTH];
	DWORD cchDecodedUrl = INTERNET_MAX_URL_LENGTH;
	WCHAR szDomainName[INTERNET_MAX_URL_LENGTH];

	// parse the URL
	HRESULT hr = CoInternetParseUrl(url.c_str(), PARSE_DECODE, URL_ENCODING_NONE, szDecodedUrl,
                    INTERNET_MAX_URL_LENGTH, &cchDecodedUrl, 0);
	if (hr != S_OK)
	{
		return false;
	}

	// figure out the domain/hostname
	hr = CoInternetParseUrl(szDecodedUrl, PARSE_DOMAIN, 0, szDomainName, INTERNET_MAX_URL_LENGTH, &cchDecodedUrl, 0);
	if (hr != S_OK)
	{
		return false;
	}

	// start the HTTP fetch
	HINTERNET hConnection = InternetConnectW( hINet, szDomainName, 80, L" ", L" ", INTERNET_SERVICE_HTTP, 0, 0 );
	if ( !hConnection )
	{
		return false;
	}

	std::wstring wurl(szDecodedUrl);
	std::wstring path = wurl.substr(wurl.find(szDomainName)+wcslen(szDomainName));
	//std::wstring queryString = url.substr(url.rfind("?")+1);
	//astd::wstring object = path + "?" + queryString;

	HINTERNET hRequest = HttpOpenRequestW( hConnection, L"GET", path.c_str(), NULL, NULL, NULL, INTERNET_FLAG_RELOAD|INTERNET_FLAG_NO_CACHE_WRITE|INTERNET_FLAG_NO_COOKIES|INTERNET_FLAG_NO_UI|INTERNET_FLAG_IGNORE_CERT_CN_INVALID|INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, 0 );

	if ( !hRequest )
	{
		InternetCloseHandle(hConnection);
		return false;
	}

	// now stream the resulting HTTP into a file
	std::ofstream ostr;
	ostr.open(outFilename.c_str(), std::ios_base::binary | std::ios_base::trunc);

	bool failed = false;

	CHAR buffer[2048];
	DWORD dwRead;
	DWORD total = 0;
	wchar_t msg[255];

	HttpSendRequest( hRequest, NULL, 0, NULL, 0);
	while( InternetReadFile( hRequest, buffer, 2047, &dwRead ) )
	{
		if ( dwRead == 0)
		{
			break;
		}
		if (p->IsCancelled())
		{
			failed = true;
			break;
		}
		buffer[dwRead] = '\0';
		total+=dwRead;
		ostr.write(buffer, dwRead);
		wsprintfW(msg,L"Downloaded %d KB",total/1024);
		p->SetLineText(2,msg,true);
	}
	ostr.close();
	InternetCloseHandle(hConnection);
	InternetCloseHandle(hRequest);

	return ! failed;
}

bool DownloadURL2(Progress *p, HINTERNET hINet, std::wstring url, std::wstring outFilename)
{
	WCHAR szDecodedUrl[INTERNET_MAX_URL_LENGTH];
	DWORD cchDecodedUrl = INTERNET_MAX_URL_LENGTH;
	HRESULT hr = CoInternetParseUrl(url.c_str(), PARSE_DECODE, URL_ENCODING_NONE, szDecodedUrl, INTERNET_MAX_URL_LENGTH, &cchDecodedUrl, 0);
	if (hr != S_OK)
	{
		return false;
	}

	// start the HTTP fetch
	HINTERNET urlConn = InternetOpenUrlW(hINet, szDecodedUrl, NULL, 0, 0, 0);
	if ( !urlConn )
	{
		return false;
	}

	bool failed = false;

	// now stream the resulting HTTP into a file
	std::ofstream ostr;
	ostr.open(outFilename.c_str(), std::ios_base::binary | std::ios_base::trunc);

	CHAR buffer[2048];
	DWORD dwRead;
	DWORD total = 0;
	wchar_t msg[255];
	while( InternetReadFile(urlConn, buffer, 2047, &dwRead ) )
	{
		if ( dwRead == 0)
		{
			break;
		}
		if (p->IsCancelled())
		{
			failed = true;
			break;
		}
		buffer[dwRead] = '\0';
		total+=dwRead;
		ostr.write(buffer, dwRead);
		wsprintfW(msg,L"Downloaded %d KB",total/1024);
		p->SetLineText(2,msg,true);
	}
	ostr.close();
	InternetCloseHandle(urlConn);

	return ! failed;
}

BOOL DirectoryExists(std::wstring dirName)
{
	DWORD attribs = ::GetFileAttributesW(dirName.c_str());

	if (attribs == INVALID_FILE_ATTRIBUTES) {
		return false;
	}

	return (attribs & FILE_ATTRIBUTE_DIRECTORY);
}

void CreateDirectoryTree(std::wstring dir)
{
	if(! DirectoryExists(dir))
	{
		// ensure parent dir exits
		int lastSlash = dir.find_last_of(L"\\");
		if(lastSlash != std::wstring::npos)
		{
			std::wstring parent = dir.substr(0, lastSlash);

			CreateDirectoryTree(parent);
		}

		// by this point, all parent dirs are created
		CreateDirectoryW(dir.c_str(), NULL);
	}
}

bool UnzipFile(std::wstring unzipper, std::wstring zipFile, std::wstring destdir)
{
	// ensure destdir exists
	CreateDirectoryTree(destdir);

	// now we're going to invoke back into the boot to unzip our file and install
	STARTUPINFOW si;
	PROCESS_INFORMATION pi;
	ZeroMemory( &si, sizeof(si) );
	ZeroMemory( &pi, sizeof(pi) );
	si.cb = sizeof(si);

	std::wstring cmdline = L"\"";
	cmdline+=unzipper;
	cmdline+=L"\" --tiunzip \"";
	cmdline+=zipFile;
	cmdline+=L"\" \"";
	cmdline+=destdir;
	cmdline+=L"\"";

	// in win32, we just invoke back the same process and let him unzip
	if (!CreateProcessW(NULL,(LPWSTR)cmdline.c_str(),NULL,NULL,FALSE,NULL,NULL,NULL,&si,&pi))
	{
		return false;
	}

	// wait for the process to finish unzipping
	WaitForSingleObject(pi.hProcess,INFINITE);

	return true;
}
int WINAPI WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow
)
{
	//TODO: set the icon for this app and dialogs
//	HICON icon = LoadIcon(hInstance,MAKEINTRESOURCE(IDR_MAINFRAME));
//	SendMessage(NULL, WM_SETICON, (WPARAM)true, (LPARAM)icon);

	// get the command line
	LPWSTR cmdline = GetCommandLineW();
    int argcount = 0;
	LPWSTR *args = CommandLineToArgvW(cmdline,&argcount);

	// we must have at least the mandatory args + 1 URL
	if (argcount < 7)
	{
		MessageBoxW(GetDesktopWindow(),L"Invalid arguments passed to Installer",L"Application Error",MB_OK|MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
		return 1;
	}

	std::wstring appname = args[1];
	std::wstring title = args[2];
	std::wstring message = args[3];
	std::wstring appTitle = appname + L" Installer";
	std::wstring tempdir = args[4];
	std::wstring installdir = args[5];
	std::wstring unzipper = args[6];

	// verify the installation
	if (IDOK != MessageBoxW(GetDesktopWindow(),message.c_str(),title.c_str(),MB_ICONINFORMATION|MB_OKCANCEL))
	{
		MessageBoxW(GetDesktopWindow(),L"Installation Aborted. To install later, re-run the application again.", title.c_str(), MB_OK|MB_ICONWARNING);
		return 1;
	}

	int count = argcount - 7;
	int startAt = 7;

	CoInitialize(NULL);

	// create our progress indicator class
	Progress *p = new Progress;
	p->SetTitle(appTitle.c_str());
	p->SetCancelMessage(L"Cancelling, one moment...");

	wchar_t buf[255];
	wsprintfW(buf,L"Preparing to download %d file%s", count, (count > 1 ? L"s" : L""));

	p->SetLineText(1,std::wstring(buf),true);
	p->Show();
	p->Update(0,count);

	// initialize interent DLL
	HINTERNET hINet = InternetOpenW(L"Mozilla/5.0 (compatible; Titanium_Downloader/0.1; Win32)", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );

	// for each URL, fetch the URL and then unzip it
	bool failed = false;
	DWORD x = 0;
	for (int c=startAt;c<argcount;c++)
	{
		p->Update(x++,count);
		std::wstring url = args[c];

		std::wstring uuid = ParseQueryParam(url,L"uuid");
		std::wstring name = ParseQueryParam(url,L"name");
		std::wstring version = ParseQueryParam(url,L"version");
		std::wstring filename = name;
		filename+=L"-";
		filename+=version;
		filename+=L".zip";

		// figure out the path and destination
		std::wstring path = tempdir + L"\\" + filename;
		std::wstring destdir;

		if (RUNTIME_UUID == uuid)
        {
			destdir = installdir + L"\\runtime\\win32\\" + version;
        }
        else if (MODULE_UUID == uuid)
        {
			destdir = installdir + L"\\modules\\win32\\" + name + L"\\" + version;
        }
        else
        {
			continue;
        }

		bool downloaded = DownloadURL(p, hINet, url, path);

		if(downloaded)
		{
			wchar_t msg[255];
			wsprintfW(msg, L"Installing %s/%s ...",name.c_str(),version.c_str());
			p->SetLineText(2,msg,true);
			UnzipFile(unzipper, path, destdir);
		}
	}

	// done with iNet - so close it
	InternetCloseHandle(hINet);

	if (p->IsCancelled())
	{
		failed = true;
	}

	// cleanup
	delete p;

	CoUninitialize();

	return (failed) ? 1 : 0;
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/MetaProcessor/MetaProcessor.h"

#include "Display.h"
#include "InputValidator.h"
#include "MetaParser.h"
#include "MetaSema.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Value.h"

#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"

#include "llvm/Support/Path.h"

#include <fstream>
#include <cstdlib>
#include <cctype>
#include <stdio.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#define STDIN_FILENO  0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#endif

using namespace clang;

namespace cling {

  MetaProcessor::MaybeRedirectOutputRAII::MaybeRedirectOutputRAII(
                                          MetaProcessor* p)
  :m_MetaProcessor(p), m_isCurrentlyRedirecting(0) {
    StringRef redirectionFile;
    if (!m_MetaProcessor->m_PrevStdoutFileName.empty()) {
      redirectionFile = m_MetaProcessor->m_PrevStdoutFileName.back();
      redirect(stdout, redirectionFile.str(), kSTDOUT);
    }
    if (!m_MetaProcessor->m_PrevStderrFileName.empty()) {
      redirectionFile = m_MetaProcessor->m_PrevStderrFileName.back();
      // Deal with the case 2>&1 and 2&>1
      if (strcmp(redirectionFile.data(), "_IO_2_1_stdout_") == 0) {
        // If out is redirected to a file.
        if (!m_MetaProcessor->m_PrevStdoutFileName.empty()) {
          redirectionFile = m_MetaProcessor->m_PrevStdoutFileName.back();
        } else {
          unredirect(m_MetaProcessor->m_backupFDStderr, STDERR_FILENO, stderr);
        }
      }
      redirect(stderr, redirectionFile.str(), kSTDERR);
    }
  }

  void MetaProcessor::MaybeRedirectOutputRAII::redirect(FILE* file,
                                        const std::string& fileName,
                                        MetaProcessor::RedirectionScope scope) {
    if (!fileName.empty()) {
      FILE* redirectionFile = freopen(fileName.c_str(), "a", file);
      if (!redirectionFile) {
        llvm::errs()<<"cling::MetaProcessor::MaybeRedirectOutputRAII::redirect:"
                    " Not succefully reopened the redirection file "
                    << fileName.c_str() << "\n.";
      } else {
        m_isCurrentlyRedirecting |= scope;
      }
    }
  }

  void MetaProcessor::MaybeRedirectOutputRAII::pop() {
    if (m_isCurrentlyRedirecting & kSTDOUT) {
      unredirect(m_MetaProcessor->m_backupFDStdout, STDOUT_FILENO, stdout);
    }
    if (m_isCurrentlyRedirecting & kSTDERR) {
      unredirect(m_MetaProcessor->m_backupFDStderr, STDERR_FILENO, stderr);
    }
  }

  void MetaProcessor::MaybeRedirectOutputRAII::unredirect(int backupFD,
                                                          int expectedFD,
                                                          FILE* file) {
    // Switch back to previous file after line is processed.

    // Flush the current content if there is any.
    if (!feof(file)) {
      fflush(file);
    }
    // Copy the original fd for the std.
    if (dup2(backupFD, expectedFD) != expectedFD) {
        llvm::errs() << "cling::MetaProcessor::unredirect "
                     << "The unredirection file descriptor not valid "
                     << backupFD << ".\n";
    }
  }

  MetaProcessor::MetaProcessor(Interpreter& interp, raw_ostream& outs)
    : m_Interp(interp), m_Outs(&outs) {
    m_InputValidator.reset(new InputValidator());
    m_MetaParser.reset(new MetaParser(new MetaSema(interp, *this)));
    m_backupFDStdout = copyFileDescriptor(STDOUT_FILENO);
    m_backupFDStderr = copyFileDescriptor(STDERR_FILENO);
  }

  MetaProcessor::~MetaProcessor() {}

  int MetaProcessor::process(const char* input_text,
                             Interpreter::CompilationResult& compRes,
                             Value* result) {
    if (result)
      *result = Value();
    compRes = Interpreter::kSuccess;
    int expectedIndent = m_InputValidator->getExpectedIndent();

    if (expectedIndent)
      compRes = Interpreter::kMoreInputExpected;
    if (!input_text || !input_text[0]) {
      // nullptr / empty string, nothing to do.
      return expectedIndent;
    }
    std::string input_line(input_text);
    if (input_line == "\n") { // just a blank line, nothing to do.
      return expectedIndent;
    }
    //  Check for and handle meta commands.
    m_MetaParser->enterNewInputLine(input_line);
    MetaSema::ActionResult actionResult = MetaSema::AR_Success;
    if (m_MetaParser->isMetaCommand(actionResult, result)) {

      if (m_MetaParser->isQuitRequested())
        return -1;

      if (actionResult != MetaSema::AR_Success)
        compRes = Interpreter::kFailure;
      return expectedIndent;
    }

    // Check if the current statement is now complete. If not, return to
    // prompt for more.
    if (m_InputValidator->validate(input_line) == InputValidator::kIncomplete) {
      compRes = Interpreter::kMoreInputExpected;
      return m_InputValidator->getExpectedIndent();
    }

    //  We have a complete statement, compile and execute it.
    std::string input = m_InputValidator->getInput();
    m_InputValidator->reset();
    // if (m_Options.RawInput)
    //   compResLocal = m_Interp.declare(input);
    // else
    compRes = m_Interp.process(input, result);

    return 0;
  }

  void MetaProcessor::cancelContinuation() const {
    m_InputValidator->reset();
  }

  int MetaProcessor::getExpectedIndent() const {
    return m_InputValidator->getExpectedIndent();
  }

  Interpreter::CompilationResult
  MetaProcessor::readInputFromFile(llvm::StringRef filename,
                                   Value* result,
                                   bool ignoreOutmostBlock /*=false*/) {

    {
      // check that it's not binary:
      std::ifstream in(filename.str().c_str(), std::ios::in | std::ios::binary);
      char magic[1024] = {0};
      in.read(magic, sizeof(magic));
      size_t readMagic = in.gcount();
      if (readMagic >= 4) {
        llvm::StringRef magicStr(magic,in.gcount());
        llvm::sys::fs::file_magic fileType
          = llvm::sys::fs::identify_magic(magicStr);
        if (fileType != llvm::sys::fs::file_magic::unknown) {
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a binary file!\n";
          return Interpreter::kFailure;
        }
        unsigned printable = 0;
        for (size_t i = 0; i < readMagic; ++i)
          if (isprint(magic[i]))
            ++printable;
        if (10 * printable <  5 * readMagic) {
          // 50% printable for ASCII files should be a safe guess.
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a (likely) binary file!\n" << printable;
          return Interpreter::kFailure;
        }
      }
    }

    std::ifstream in(filename.str().c_str());
    in.seekg(0, std::ios::end);
    size_t size = in.tellg();
    std::string content(size, ' ');
    in.seekg(0);
    in.read(&content[0], size);

    if (ignoreOutmostBlock && !content.empty()) {
      static const char whitespace[] = " \t\r\n";
      std::string::size_type posNonWS = content.find_first_not_of(whitespace);
      // Handle comments before leading {
      while (content[posNonWS] == '/' && content[posNonWS+1] == '/') {
        // Remove the comment line
        posNonWS = content.find_first_of('\n', posNonWS+2)+1;
      }
      std::string::size_type replaced = posNonWS;
      if (posNonWS != std::string::npos) {
        if (content[posNonWS] == '{') {
          // hide the curly brace:
          content[posNonWS] = ' ';
          // and the matching closing '}'
          posNonWS = content.find_last_not_of(whitespace);
          if (posNonWS != std::string::npos) {
            if (content[posNonWS] == ';' && content[posNonWS-1] == '}') {
              content[posNonWS--] = ' '; // replace ';' and enter next if
            }
            if (content[posNonWS] == '}') {
              content[posNonWS] = ' '; // replace '}'
            } else {
              std::string::size_type posComment = content.find_last_of('}');
                if (content[posComment] == '}') {
                  content[posComment] = ' '; // replace '}'
                }
                posComment = content.find_first_not_of(whitespace, posComment);
              if (content[posComment] == '/' && content[posComment+1] == '/') {
              // More text (comments) are okay after the last '}', but
              // we can not easily find it to remove it (so we need to upgrade
              // this code to better handle the case with comments or
              // preprocessor code before and after the leading { and
              // trailing })
                while (posComment <= posNonWS) {
                  content[posComment++] = ' '; // replace '}' and comment
                }
              } else {
                content[replaced] = '{';
                // By putting the '{' back, we keep the code as consistent as
                // the user wrote it ... but we should still warn that we not
                // goint to treat this file an unamed macro.
                llvm::errs()
                << "Warning in cling::MetaProcessor: can not find the closing '}', "
                << llvm::sys::path::filename(filename)
                << " is not handled as an unamed script!\n";
              } // did not find '}''
            } // remove comments after the trailing '}'
          } // find '}'
        } // have '{'
      } // have non-whitespace
    } // ignore outmost block

    std::string strFilename(filename.str());
    m_CurrentlyExecutingFile = strFilename;
    bool topmost = !m_TopExecutingFile.data();
    if (topmost)
      m_TopExecutingFile = m_CurrentlyExecutingFile;
    Interpreter::CompilationResult ret;
    // We don't want to value print the results of a unnamed macro.
    if (process((content + ";").c_str(), ret, result)) {
      // Input file has to be complete.
       llvm::errs()
          << "Error in cling::MetaProcessor: file "
          << llvm::sys::path::filename(filename)
          << " is incomplete (missing parenthesis or similar)!\n";
      ret = Interpreter::kFailure;
    }
    m_CurrentlyExecutingFile = llvm::StringRef();
    if (topmost)
      m_TopExecutingFile = llvm::StringRef();
    return ret;
  }

  void MetaProcessor::setFileStream(llvm::StringRef file, bool append, int fd,
              llvm::SmallVector<llvm::SmallString<128>, 2>& prevFileStack) {
    // If we have a fileName to redirect to store it.
    if (!file.empty()) {
      prevFileStack.push_back(file);
      // pop and push a null terminating 0.
      // SmallVectorImpl<T> does not have a c_str(), thus instead of casting to
      // a SmallString<T> we null terminate the data that we have and pop the
      // 0 char back.
      prevFileStack.back().push_back(0);
      prevFileStack.back().pop_back();
      if (!append) {
        FILE * f;
        if (!(f = fopen(file.data(), "w"))) {
          llvm::errs() << "cling::MetaProcessor::setFileStream:"
                       " The file path " << file.data() << "is not valid.";
        } else {
          fclose(f);
        }
      }
    // Else unredirection, so switch to the previous file.
    } else {
      // If there is no previous file on the stack we pop the file
      if (!prevFileStack.empty()) {
        prevFileStack.pop_back();
      }
    }
  }

  void MetaProcessor::setStdStream(llvm::StringRef file,
                                   RedirectionScope stream, bool append) {

    if (stream & kSTDOUT) {
      setFileStream(file, append, STDOUT_FILENO, m_PrevStdoutFileName);
    }
    if (stream & kSTDERR) {
      setFileStream(file, append, STDERR_FILENO, m_PrevStderrFileName);
    }
  }

  int MetaProcessor::copyFileDescriptor(int fd) {
    int backupFD = dup(fd);
    if (backupFD < 0) {
      llvm::errs() << "MetaProcessor::copyFileDescriptor: Duplicating the file"
                   " descriptor " << fd << "resulted in an error."
                   " Will not be able to unredirect.";
    }
    return backupFD;
  }

} // end namespace cling
<commit_msg>Add a filename to the unnamed macro handling. Fixes ROOT-4760.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/MetaProcessor/MetaProcessor.h"

#include "Display.h"
#include "InputValidator.h"
#include "MetaParser.h"
#include "MetaSema.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Value.h"

#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"

#include "llvm/Support/Path.h"

#include <fstream>
#include <cstdlib>
#include <cctype>
#include <stdio.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#define STDIN_FILENO  0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#endif

using namespace clang;

namespace cling {

  MetaProcessor::MaybeRedirectOutputRAII::MaybeRedirectOutputRAII(
                                          MetaProcessor* p)
  :m_MetaProcessor(p), m_isCurrentlyRedirecting(0) {
    StringRef redirectionFile;
    if (!m_MetaProcessor->m_PrevStdoutFileName.empty()) {
      redirectionFile = m_MetaProcessor->m_PrevStdoutFileName.back();
      redirect(stdout, redirectionFile.str(), kSTDOUT);
    }
    if (!m_MetaProcessor->m_PrevStderrFileName.empty()) {
      redirectionFile = m_MetaProcessor->m_PrevStderrFileName.back();
      // Deal with the case 2>&1 and 2&>1
      if (strcmp(redirectionFile.data(), "_IO_2_1_stdout_") == 0) {
        // If out is redirected to a file.
        if (!m_MetaProcessor->m_PrevStdoutFileName.empty()) {
          redirectionFile = m_MetaProcessor->m_PrevStdoutFileName.back();
        } else {
          unredirect(m_MetaProcessor->m_backupFDStderr, STDERR_FILENO, stderr);
        }
      }
      redirect(stderr, redirectionFile.str(), kSTDERR);
    }
  }

  void MetaProcessor::MaybeRedirectOutputRAII::redirect(FILE* file,
                                        const std::string& fileName,
                                        MetaProcessor::RedirectionScope scope) {
    if (!fileName.empty()) {
      FILE* redirectionFile = freopen(fileName.c_str(), "a", file);
      if (!redirectionFile) {
        llvm::errs()<<"cling::MetaProcessor::MaybeRedirectOutputRAII::redirect:"
                    " Not succefully reopened the redirection file "
                    << fileName.c_str() << "\n.";
      } else {
        m_isCurrentlyRedirecting |= scope;
      }
    }
  }

  void MetaProcessor::MaybeRedirectOutputRAII::pop() {
    if (m_isCurrentlyRedirecting & kSTDOUT) {
      unredirect(m_MetaProcessor->m_backupFDStdout, STDOUT_FILENO, stdout);
    }
    if (m_isCurrentlyRedirecting & kSTDERR) {
      unredirect(m_MetaProcessor->m_backupFDStderr, STDERR_FILENO, stderr);
    }
  }

  void MetaProcessor::MaybeRedirectOutputRAII::unredirect(int backupFD,
                                                          int expectedFD,
                                                          FILE* file) {
    // Switch back to previous file after line is processed.

    // Flush the current content if there is any.
    if (!feof(file)) {
      fflush(file);
    }
    // Copy the original fd for the std.
    if (dup2(backupFD, expectedFD) != expectedFD) {
        llvm::errs() << "cling::MetaProcessor::unredirect "
                     << "The unredirection file descriptor not valid "
                     << backupFD << ".\n";
    }
  }

  MetaProcessor::MetaProcessor(Interpreter& interp, raw_ostream& outs)
    : m_Interp(interp), m_Outs(&outs) {
    m_InputValidator.reset(new InputValidator());
    m_MetaParser.reset(new MetaParser(new MetaSema(interp, *this)));
    m_backupFDStdout = copyFileDescriptor(STDOUT_FILENO);
    m_backupFDStderr = copyFileDescriptor(STDERR_FILENO);
  }

  MetaProcessor::~MetaProcessor() {}

  int MetaProcessor::process(const char* input_text,
                             Interpreter::CompilationResult& compRes,
                             Value* result) {
    if (result)
      *result = Value();
    compRes = Interpreter::kSuccess;
    int expectedIndent = m_InputValidator->getExpectedIndent();

    if (expectedIndent)
      compRes = Interpreter::kMoreInputExpected;
    if (!input_text || !input_text[0]) {
      // nullptr / empty string, nothing to do.
      return expectedIndent;
    }
    std::string input_line(input_text);
    if (input_line == "\n") { // just a blank line, nothing to do.
      return expectedIndent;
    }
    //  Check for and handle meta commands.
    m_MetaParser->enterNewInputLine(input_line);
    MetaSema::ActionResult actionResult = MetaSema::AR_Success;
    if (m_MetaParser->isMetaCommand(actionResult, result)) {

      if (m_MetaParser->isQuitRequested())
        return -1;

      if (actionResult != MetaSema::AR_Success)
        compRes = Interpreter::kFailure;
      return expectedIndent;
    }

    // Check if the current statement is now complete. If not, return to
    // prompt for more.
    if (m_InputValidator->validate(input_line) == InputValidator::kIncomplete) {
      compRes = Interpreter::kMoreInputExpected;
      return m_InputValidator->getExpectedIndent();
    }

    //  We have a complete statement, compile and execute it.
    std::string input = m_InputValidator->getInput();
    m_InputValidator->reset();
    // if (m_Options.RawInput)
    //   compResLocal = m_Interp.declare(input);
    // else
    compRes = m_Interp.process(input, result);

    return 0;
  }

  void MetaProcessor::cancelContinuation() const {
    m_InputValidator->reset();
  }

  int MetaProcessor::getExpectedIndent() const {
    return m_InputValidator->getExpectedIndent();
  }

  Interpreter::CompilationResult
  MetaProcessor::readInputFromFile(llvm::StringRef filename,
                                   Value* result,
                                   bool ignoreOutmostBlock /*=false*/) {

    {
      // check that it's not binary:
      std::ifstream in(filename.str().c_str(), std::ios::in | std::ios::binary);
      char magic[1024] = {0};
      in.read(magic, sizeof(magic));
      size_t readMagic = in.gcount();
      if (readMagic >= 4) {
        llvm::StringRef magicStr(magic,in.gcount());
        llvm::sys::fs::file_magic fileType
          = llvm::sys::fs::identify_magic(magicStr);
        if (fileType != llvm::sys::fs::file_magic::unknown) {
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a binary file!\n";
          return Interpreter::kFailure;
        }
        unsigned printable = 0;
        for (size_t i = 0; i < readMagic; ++i)
          if (isprint(magic[i]))
            ++printable;
        if (10 * printable <  5 * readMagic) {
          // 50% printable for ASCII files should be a safe guess.
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a (likely) binary file!\n" << printable;
          return Interpreter::kFailure;
        }
      }
    }

    std::ifstream in(filename.str().c_str());
    in.seekg(0, std::ios::end);
    size_t size = in.tellg();
    std::string content(size, ' ');
    in.seekg(0);
    in.read(&content[0], size);

    if (ignoreOutmostBlock && !content.empty()) {
      static const char whitespace[] = " \t\r\n";
      std::string::size_type posNonWS = content.find_first_not_of(whitespace);
      // Handle comments before leading {
      while (content[posNonWS] == '/' && content[posNonWS+1] == '/') {
        // Remove the comment line
        posNonWS = content.find_first_of('\n', posNonWS+2)+1;
      }
      std::string::size_type replaced = posNonWS;
      if (posNonWS != std::string::npos) {
        if (content[posNonWS] == '{') {
          // hide the curly brace:
          content[posNonWS] = ' ';
          // and the matching closing '}'
          posNonWS = content.find_last_not_of(whitespace);
          if (posNonWS != std::string::npos) {
            if (content[posNonWS] == ';' && content[posNonWS-1] == '}') {
              content[posNonWS--] = ' '; // replace ';' and enter next if
            }
            if (content[posNonWS] == '}') {
              content[posNonWS] = ' '; // replace '}'
            } else {
              std::string::size_type posComment = content.find_last_of('}');
                if (content[posComment] == '}') {
                  content[posComment] = ' '; // replace '}'
                }
                posComment = content.find_first_not_of(whitespace, posComment);
              if (content[posComment] == '/' && content[posComment+1] == '/') {
              // More text (comments) are okay after the last '}', but
              // we can not easily find it to remove it (so we need to upgrade
              // this code to better handle the case with comments or
              // preprocessor code before and after the leading { and
              // trailing })
                while (posComment <= posNonWS) {
                  content[posComment++] = ' '; // replace '}' and comment
                }
              } else {
                content[replaced] = '{';
                // By putting the '{' back, we keep the code as consistent as
                // the user wrote it ... but we should still warn that we not
                // goint to treat this file an unamed macro.
                llvm::errs()
                << "Warning in cling::MetaProcessor: can not find the closing '}', "
                << llvm::sys::path::filename(filename)
                << " is not handled as an unamed script!\n";
              } // did not find '}''
            } // remove comments after the trailing '}'
          } // find '}'
        } // have '{'
      } // have non-whitespace
    } // ignore outmost block

    std::string strFilename(filename.str());
    m_CurrentlyExecutingFile = strFilename;
    bool topmost = !m_TopExecutingFile.data();
    if (topmost)
      m_TopExecutingFile = m_CurrentlyExecutingFile;
    Interpreter::CompilationResult ret;
    // We don't want to value print the results of a unnamed macro.
    content = "#line 2 \"" + filename.str() + "\" \n" + content;
    if (process((content + ";").c_str(), ret, result)) {
      // Input file has to be complete.
       llvm::errs()
          << "Error in cling::MetaProcessor: file "
          << llvm::sys::path::filename(filename)
          << " is incomplete (missing parenthesis or similar)!\n";
      ret = Interpreter::kFailure;
    }
    m_CurrentlyExecutingFile = llvm::StringRef();
    if (topmost)
      m_TopExecutingFile = llvm::StringRef();
    return ret;
  }

  void MetaProcessor::setFileStream(llvm::StringRef file, bool append, int fd,
              llvm::SmallVector<llvm::SmallString<128>, 2>& prevFileStack) {
    // If we have a fileName to redirect to store it.
    if (!file.empty()) {
      prevFileStack.push_back(file);
      // pop and push a null terminating 0.
      // SmallVectorImpl<T> does not have a c_str(), thus instead of casting to
      // a SmallString<T> we null terminate the data that we have and pop the
      // 0 char back.
      prevFileStack.back().push_back(0);
      prevFileStack.back().pop_back();
      if (!append) {
        FILE * f;
        if (!(f = fopen(file.data(), "w"))) {
          llvm::errs() << "cling::MetaProcessor::setFileStream:"
                       " The file path " << file.data() << "is not valid.";
        } else {
          fclose(f);
        }
      }
    // Else unredirection, so switch to the previous file.
    } else {
      // If there is no previous file on the stack we pop the file
      if (!prevFileStack.empty()) {
        prevFileStack.pop_back();
      }
    }
  }

  void MetaProcessor::setStdStream(llvm::StringRef file,
                                   RedirectionScope stream, bool append) {

    if (stream & kSTDOUT) {
      setFileStream(file, append, STDOUT_FILENO, m_PrevStdoutFileName);
    }
    if (stream & kSTDERR) {
      setFileStream(file, append, STDERR_FILENO, m_PrevStderrFileName);
    }
  }

  int MetaProcessor::copyFileDescriptor(int fd) {
    int backupFD = dup(fd);
    if (backupFD < 0) {
      llvm::errs() << "MetaProcessor::copyFileDescriptor: Duplicating the file"
                   " descriptor " << fd << "resulted in an error."
                   " Will not be able to unredirect.";
    }
    return backupFD;
  }

} // end namespace cling
<|endoftext|>


<commit_before>/*! @file gradient_descent.cpp
    @brief Implementation of GradientDescent class
*/
#include "gradient_descent.hpp"
#include "genotype.hpp"
#include "util.hpp"

#include <sfmt.hpp>
#include <wtl/exception.hpp>
#include <wtl/debug.hpp>
#include <wtl/iostr.hpp>
#include <wtl/zfstream.hpp>
#include <wtl/itertools.hpp>
#include <wtl/concurrent.hpp>
#include <wtl/scope.hpp>

namespace likeligrid {

// std::unique_ptr needs to know GenotypeModel implementation
GradientDescent::~GradientDescent() = default;

GradientDescent::GradientDescent(const std::string& result_filename,
    const size_t max_sites,
    const std::pair<size_t, size_t>& epistasis_pair,
    const bool pleiotropy,
    const unsigned int concurrency)
    : concurrency_(concurrency) {HERE;
    std::string genotype_file;
    size_t prev_max_sites;
    std::string prev_epistasis;
    std::tie(genotype_file, prev_max_sites, prev_epistasis)
        = read_results(result_filename);
    std::cerr << "genotype: " << genotype_file << std::endl;
    model_ = std::make_unique<GenotypeModel>(genotype_file, max_sites);
    bool is_restarting = (max_sites != prev_max_sites);
    if (model_->set_epistasis(epistasis_pair, pleiotropy)) {
        if (prev_epistasis.empty()) {
            is_restarting = true;
        } else {
            if (model_->names().back() != prev_epistasis) {
                throw std::runtime_error("epistasis_name != prev_epistasis");
            }
        }
    }
    const auto it = const_max_iterator();
    std::cerr << "old best: " << *it << std::endl;
    if (is_restarting) {
        const auto& old_best = it->first;
        std::valarray<double> new_start(1.0, model_->names().size());
        std::copy(std::begin(old_best), std::end(old_best), std::begin(new_start));
        history_.clear();
        const double loglik = model_->calc_loglik(new_start);
        history_.emplace(new_start, loglik);
        std::cerr << "new start: " << *history_.begin() << std::endl;
    }
}

GradientDescent::GradientDescent(
    std::istream& ist_genotype,
    const size_t max_sites,
    const std::pair<size_t, size_t>& epistasis_pair,
    const bool pleiotropy,
    const unsigned int concurrency)
    : model_(std::make_unique<GenotypeModel>(ist_genotype, max_sites)),
      concurrency_(concurrency) {HERE;
    model_->set_epistasis(epistasis_pair, pleiotropy);
    const std::valarray<double> new_start(1.0, model_->names().size());
    const double loglik = model_->calc_loglik(new_start);
    history_.emplace(new_start, loglik);
}

void GradientDescent::run(std::ostream& ost) {HERE;
    auto at_exit = wtl::scope_exit([&ost,this](){
        std::cerr << "\n" << *const_max_iterator() << std::endl;
        write(ost);
    });
    for (auto it = max_iterator();
         it != history_.end();
         it = find_better(it)) {
    }
}

MapGrid::iterator GradientDescent::find_better(const MapGrid::iterator& prev_it) {
    auto better_it = prev_it;
    auto task = [](GenotypeModel model, const std::valarray<double> theta) {
        // arguments are copied for each thread
        return std::make_pair(theta, model.calc_loglik(theta));
    };
    std::vector<std::future<std::pair<std::valarray<double>, double>>> futures;
    futures.reserve(concurrency_);
    const auto candidates = empty_neighbors_of(prev_it->first);
    for (const auto& theta: candidates) {
        futures.push_back(std::async(std::launch::async, task, *model_, theta));
        if ((futures.size() == concurrency_) || (&theta == &candidates.back())) {
            for (auto& ftr: futures) {
                auto result_it = history_.insert(ftr.get()).first;
                std::cerr << "." << std::flush;
                if (result_it->second > better_it->second) {
                    better_it = result_it;
                }
            }
            if (better_it != prev_it) {
                std::cerr << "*" << std::flush;
                return better_it;
            }
            futures.clear();
        }
    }
    return history_.end();
}

std::vector<std::valarray<double>> GradientDescent::empty_neighbors_of(const std::valarray<double>& center) {
    const auto axes = make_vicinity(center, 3, 0.01);
    auto iter = wtl::itertools::product(axes);
    std::vector<std::valarray<double>> empty_neighbors;
    empty_neighbors.reserve(iter.max_count());
    for (const auto& x: iter()) {
        if (history_.find(x) == history_.end()) {
            empty_neighbors.push_back(x);
        }
    }
    std::shuffle(std::begin(empty_neighbors), std::end(empty_neighbors), wtl::sfmt64());
    return empty_neighbors;
}

std::string GradientDescent::outfile() const {HERE;
    std::ostringstream oss;
    oss << "gradient-s" << model_->max_sites();
    if (model_->epistasis_pair().first != model_->epistasis_pair().second) {
        oss << "-e" << model_->epistasis_pair().first
            <<  "x" << model_->epistasis_pair().second;
    }
    oss << ".tsv.gz";
    return oss.str();
}

void GradientDescent::write(std::ostream& ost) {HERE;
    ost << "##genotype_file=" << model_->filename() << "\n";
    ost << "##max_sites=" << model_->max_sites() << "\n";
    ost << "##max_count=" << 0u << "\n";
    ost << "##step=" << 0.01 << "\n";
    ost << "loglik\t" << wtl::join(model_->names(), "\t") << "\n";
    for (const auto& p: history_) {
        ost << p.second << "\t"
            << wtl::str_join(p.first, "\t") << "\n";
    }
}

std::tuple<std::string, size_t, std::string> GradientDescent::read_results(const std::string& infile) {HERE;
    wtl::izfstream ist(infile);
    std::string genotype_file;
    size_t prev_max_sites;
    std::tie(genotype_file, prev_max_sites, std::ignore, std::ignore) = read_metadata(ist);

    std::string buffer;
    ist >> buffer; // loglik
    std::getline(ist, buffer); // header
    buffer.erase(0, 1); // \t
    const std::vector<std::string> colnames = wtl::split(buffer, "\t");
    std::string epistasis_name = colnames.back();
    if (epistasis_name.find(':') == std::string::npos) epistasis_name.clear();

    while (std::getline(ist, buffer)) {
        std::istringstream iss(buffer);
        std::istream_iterator<double> it(iss);
        double loglik = *it;
        std::vector<double> vec(++it, std::istream_iterator<double>());
        history_.emplace(std::valarray<double>(vec.data(), vec.size()), loglik);
    }
    return {genotype_file, prev_max_sites, epistasis_name};
}

MapGrid::iterator GradientDescent::max_iterator() {HERE;
    return std::max_element(std::begin(history_), std::end(history_),
        [](MapGrid::value_type& x, MapGrid::value_type& y){
            return x.second < y.second;
        });
}

MapGrid::const_iterator GradientDescent::const_max_iterator() const {HERE;
    return std::max_element(std::begin(history_), std::end(history_),
        [](const MapGrid::value_type& x, const MapGrid::value_type& y){
            return x.second < y.second;
        });
}

void GradientDescent::test() {HERE;
    std::stringstream sst;
    sst <<
R"({
  "pathway": ["A", "B"],
  "annotation": ["0011", "1100"],
  "sample": ["0011", "0101", "1001", "0110", "1010", "1100"]
})";
    GradientDescent searcher(sst, 4, {0, 1});
    searcher.run(std::cout);
}

} // namespace likeligrid
<commit_msg>Use wtl::ThreadPool in GradientDescent<commit_after>/*! @file gradient_descent.cpp
    @brief Implementation of GradientDescent class
*/
#include "gradient_descent.hpp"
#include "genotype.hpp"
#include "util.hpp"

#include <sfmt.hpp>
#include <wtl/exception.hpp>
#include <wtl/debug.hpp>
#include <wtl/iostr.hpp>
#include <wtl/zfstream.hpp>
#include <wtl/itertools.hpp>
#include <wtl/concurrent.hpp>
#include <wtl/scope.hpp>

namespace likeligrid {

// std::unique_ptr needs to know GenotypeModel implementation
GradientDescent::~GradientDescent() = default;

GradientDescent::GradientDescent(const std::string& result_filename,
    const size_t max_sites,
    const std::pair<size_t, size_t>& epistasis_pair,
    const bool pleiotropy,
    const unsigned int concurrency)
    : concurrency_(concurrency) {HERE;
    std::string genotype_file;
    size_t prev_max_sites;
    std::string prev_epistasis;
    std::tie(genotype_file, prev_max_sites, prev_epistasis)
        = read_results(result_filename);
    std::cerr << "genotype: " << genotype_file << std::endl;
    model_ = std::make_unique<GenotypeModel>(genotype_file, max_sites);
    bool is_restarting = (max_sites != prev_max_sites);
    if (model_->set_epistasis(epistasis_pair, pleiotropy)) {
        if (prev_epistasis.empty()) {
            is_restarting = true;
        } else {
            if (model_->names().back() != prev_epistasis) {
                throw std::runtime_error("epistasis_name != prev_epistasis");
            }
        }
    }
    const auto it = const_max_iterator();
    std::cerr << "old best: " << *it << std::endl;
    if (is_restarting) {
        const auto& old_best = it->first;
        std::valarray<double> new_start(1.0, model_->names().size());
        std::copy(std::begin(old_best), std::end(old_best), std::begin(new_start));
        history_.clear();
        const double loglik = model_->calc_loglik(new_start);
        history_.emplace(new_start, loglik);
        std::cerr << "new start: " << *history_.begin() << std::endl;
    }
}

GradientDescent::GradientDescent(
    std::istream& ist_genotype,
    const size_t max_sites,
    const std::pair<size_t, size_t>& epistasis_pair,
    const bool pleiotropy,
    const unsigned int concurrency)
    : model_(std::make_unique<GenotypeModel>(ist_genotype, max_sites)),
      concurrency_(concurrency) {HERE;
    model_->set_epistasis(epistasis_pair, pleiotropy);
    const std::valarray<double> new_start(1.0, model_->names().size());
    const double loglik = model_->calc_loglik(new_start);
    history_.emplace(new_start, loglik);
}

void GradientDescent::run(std::ostream& ost) {HERE;
    auto at_exit = wtl::scope_exit([&ost,this](){
        std::cerr << "\n" << *const_max_iterator() << std::endl;
        write(ost);
    });
    for (auto it = max_iterator();
         it != history_.end();
         it = find_better(it)) {
    }
}

MapGrid::iterator GradientDescent::find_better(const MapGrid::iterator& prev_it) {
    auto better_it = prev_it;
    auto task = [](GenotypeModel model, const std::valarray<double> theta) {
        // arguments are copied for each thread
        return std::make_pair(theta, model.calc_loglik(theta));
    };
    std::vector<std::future<std::pair<std::valarray<double>, double>>> futures;
    futures.reserve(concurrency_);
    wtl::ThreadPool pool(concurrency_);
    const auto candidates = empty_neighbors_of(prev_it->first);
    for (const auto& theta: candidates) {
        futures.push_back(pool.submit<std::pair<std::valarray<double>, double>>(task, *model_, theta));
        if ((futures.size() == concurrency_) || (&theta == &candidates.back())) {
            for (auto& ftr: futures) {
                auto result_it = history_.insert(ftr.get()).first;
                std::cerr << "." << std::flush;
                if (result_it->second > better_it->second) {
                    better_it = result_it;
                }
            }
            if (better_it != prev_it) {
                std::cerr << "*" << std::flush;
                return better_it;
            }
            futures.clear();
        }
    }
    return history_.end();
}

std::vector<std::valarray<double>> GradientDescent::empty_neighbors_of(const std::valarray<double>& center) {
    const auto axes = make_vicinity(center, 3, 0.01);
    auto iter = wtl::itertools::product(axes);
    std::vector<std::valarray<double>> empty_neighbors;
    empty_neighbors.reserve(iter.max_count());
    for (const auto& x: iter()) {
        if (history_.find(x) == history_.end()) {
            empty_neighbors.push_back(x);
        }
    }
    std::shuffle(std::begin(empty_neighbors), std::end(empty_neighbors), wtl::sfmt64());
    return empty_neighbors;
}

std::string GradientDescent::outfile() const {HERE;
    std::ostringstream oss;
    oss << "gradient-s" << model_->max_sites();
    if (model_->epistasis_pair().first != model_->epistasis_pair().second) {
        oss << "-e" << model_->epistasis_pair().first
            <<  "x" << model_->epistasis_pair().second;
    }
    oss << ".tsv.gz";
    return oss.str();
}

void GradientDescent::write(std::ostream& ost) {HERE;
    ost << "##genotype_file=" << model_->filename() << "\n";
    ost << "##max_sites=" << model_->max_sites() << "\n";
    ost << "##max_count=" << 0u << "\n";
    ost << "##step=" << 0.01 << "\n";
    ost << "loglik\t" << wtl::join(model_->names(), "\t") << "\n";
    for (const auto& p: history_) {
        ost << p.second << "\t"
            << wtl::str_join(p.first, "\t") << "\n";
    }
}

std::tuple<std::string, size_t, std::string> GradientDescent::read_results(const std::string& infile) {HERE;
    wtl::izfstream ist(infile);
    std::string genotype_file;
    size_t prev_max_sites;
    std::tie(genotype_file, prev_max_sites, std::ignore, std::ignore) = read_metadata(ist);

    std::string buffer;
    ist >> buffer; // loglik
    std::getline(ist, buffer); // header
    buffer.erase(0, 1); // \t
    const std::vector<std::string> colnames = wtl::split(buffer, "\t");
    std::string epistasis_name = colnames.back();
    if (epistasis_name.find(':') == std::string::npos) epistasis_name.clear();

    while (std::getline(ist, buffer)) {
        std::istringstream iss(buffer);
        std::istream_iterator<double> it(iss);
        double loglik = *it;
        std::vector<double> vec(++it, std::istream_iterator<double>());
        history_.emplace(std::valarray<double>(vec.data(), vec.size()), loglik);
    }
    return {genotype_file, prev_max_sites, epistasis_name};
}

MapGrid::iterator GradientDescent::max_iterator() {HERE;
    return std::max_element(std::begin(history_), std::end(history_),
        [](MapGrid::value_type& x, MapGrid::value_type& y){
            return x.second < y.second;
        });
}

MapGrid::const_iterator GradientDescent::const_max_iterator() const {HERE;
    return std::max_element(std::begin(history_), std::end(history_),
        [](const MapGrid::value_type& x, const MapGrid::value_type& y){
            return x.second < y.second;
        });
}

void GradientDescent::test() {HERE;
    std::stringstream sst;
    sst <<
R"({
  "pathway": ["A", "B"],
  "annotation": ["0011", "1100"],
  "sample": ["0011", "0101", "1001", "0110", "1010", "1100"]
})";
    GradientDescent searcher(sst, 4, {0, 1});
    searcher.run(std::cout);
}

} // namespace likeligrid
<|endoftext|>


<commit_before>/*
TIGRE (https://gitorious.org/tigre) is made available under the MIT License.

Copyright (c) 2012 - 2013 Aurélien Cavelan (razlock)

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.
*/

#ifndef DISPLAY_H
#define DISPLAY_H

/**
 * Base class for the Display
 *
 * The goal of this class is to abstract everything that concerns
 * widgets management, OpenGL or context creation.
 *
 * The use is the implementation of its choice (e.g OpenGL)
 */

namespace tigre
{
	namespace graphics
	{
		class Display
		{
			public:

				virtual ~Display() {}

				virtual bool valid() const = 0;

				virtual void resize(int width, int height) = 0;

				virtual int getWidth() const = 0;

				virtual int getHeight() const = 0;

				virtual void swapBuffers() = 0;

		};
	}
}

#endif
<commit_msg>correct mistake in Display.hpp's doc<commit_after>/*
TIGRE (https://gitorious.org/tigre) is made available under the MIT License.

Copyright (c) 2012 - 2013 Aurélien Cavelan (razlock)

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.
*/

#ifndef DISPLAY_H
#define DISPLAY_H

/**
 * Base class for the Display
 *
 * The goal of this class is to abstract everything that concerns
 * widgets management, OpenGL or context creation.
 */

namespace tigre
{
	namespace graphics
	{
		class Display
		{
			public:

				virtual ~Display() {}

				virtual bool valid() const = 0;

				virtual void resize(int width, int height) = 0;

				virtual int getWidth() const = 0;

				virtual int getHeight() const = 0;

				virtual void swapBuffers() = 0;

		};
	}
}

#endif
<|endoftext|>


<commit_before>#include "texture.hpp"
#include "dummytexture.hpp"
#include "SDL_opengl.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <vector>

Texture::Texture()
    : buf_(0), bufsz_(0),
      width_(0), height_(0), twidth_(0), theight_(0),
      iscolor_(false), hasalpha_(false),
      refcount_(0), tex_(0), loaded_(false), registered_(false)
{ }

Texture::~Texture()
{
    free(buf_);
}

static std::vector<Texture *> textures;

void Texture::updateAll()
{
    std::vector<Texture *>::iterator
        b = textures.begin(), i = b, e = textures.end();
    try {
        while (i != e) {
            Texture *t = *i;
            if (t->refcount_ > 0) {
                if (!t->loaded_)
                    t->loadTex();
                ++i;
            } else {
                t->unloadTex();
                delete t;
                --e;
                if (i != e)
                    *i = *e;
            }
        }
    } catch (...) {
        textures.resize(e - b);
        throw;
    }
    textures.resize(e - b);
}

void Texture::registerTexture()
{
    if (registered_)
        return;
    textures.push_back(this);
    registered_ = true;
}

void Texture::loadTex()
{
    if (loaded_)
        return;
    if (tex_)
        fprintf(stderr, "Reloading texture %s\n", name().c_str());
    else
        fprintf(stderr, "Loading texture %s\n", name().c_str());
    bool success = false;
    success = load();
    if (success) {
        GLuint tex = 0;
        if (tex_ && !isnull_)
            tex = tex_;
        else
            glGenTextures(1, &tex);
        glBindTexture(GL_TEXTURE_2D, tex);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        GLint fmt;
        if (iscolor_)
            fmt = hasalpha_ ? GL_RGBA : GL_RGB;
        else
            fmt = hasalpha_ ? GL_LUMINANCE_ALPHA : GL_LUMINANCE;
        glTexImage2D(GL_TEXTURE_2D, 0, fmt, twidth_, theight_, 0,
                     fmt, GL_UNSIGNED_BYTE, buf_);
        tex_ = tex;
        loaded_ = true;
        isnull_ = false;
    } else {
        fprintf(stderr, "    failed\n");
        unloadTex();
        // Make sure to set loaded_ true before checking if the dummy
        // texture is loaded, because this might be the dummy texture.
        loaded_ = true;
        isnull_ = true;
        Texture &t = DummyTexture::nullTexture;
        if (!t.loaded_)
            t.loadTex();
        tex_ = t.tex_;
    }
}

void Texture::unloadTex()
{
    if (tex_ != 0 && !isnull_) {
        fprintf(stderr, "Unloading texture %s\n", name().c_str());
        GLuint tex = tex_;
        glDeleteTextures(1, &tex);
    }
    tex_ = 0;
    loaded_ = false;
    isnull_ = false;
}

unsigned int
round_up_pow2(unsigned int x)
{
    x -= 1;
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;
    x += 1;
    return x;
}

void Texture::alloc(unsigned int width, unsigned int height,
                    bool iscolor, bool hasalpha)
{
    // FIXME overflow, error handling
    unsigned int
        twidth = round_up_pow2(width), theight = round_up_pow2(height),
        chan = (iscolor ? 3 : 1) + (hasalpha ? 1 : 0),
        rb = (twidth * chan + 3) & ~3;
    size_t sz = (size_t)rb * theight;
    if (bufsz_ != sz) {
        void *buf = malloc(sz);
        if (!buf) throw std::bad_alloc();
        if (buf_) free(buf_);
        buf_ = buf;
        bufsz_ = sz;
    }
    width_ = width;
    height_ = height;
    twidth_ = twidth;
    theight_ = theight;
    iscolor_ = iscolor;
    hasalpha_ = hasalpha;
}
<commit_msg>Texture::loadTex method now catches exceptions from Texture::load.<commit_after>#include "texture.hpp"
#include "dummytexture.hpp"
#include "SDL_opengl.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <vector>

Texture::Texture()
    : buf_(0), bufsz_(0),
      width_(0), height_(0), twidth_(0), theight_(0),
      iscolor_(false), hasalpha_(false),
      refcount_(0), tex_(0), loaded_(false), registered_(false)
{ }

Texture::~Texture()
{
    free(buf_);
}

static std::vector<Texture *> textures;

void Texture::updateAll()
{
    std::vector<Texture *>::iterator
        b = textures.begin(), i = b, e = textures.end();
    try {
        while (i != e) {
            Texture *t = *i;
            if (t->refcount_ > 0) {
                if (!t->loaded_)
                    t->loadTex();
                ++i;
            } else {
                t->unloadTex();
                delete t;
                --e;
                if (i != e)
                    *i = *e;
            }
        }
    } catch (...) {
        textures.resize(e - b);
        throw;
    }
    textures.resize(e - b);
}

void Texture::registerTexture()
{
    if (registered_)
        return;
    textures.push_back(this);
    registered_ = true;
}

void Texture::loadTex()
{
    if (loaded_)
        return;
    if (tex_)
        fprintf(stderr, "Reloading texture %s\n", name().c_str());
    else
        fprintf(stderr, "Loading texture %s\n", name().c_str());
    bool success;
    try {
        success = load();
    } catch (std::exception const &e) {
        fprintf(stderr, "Error: %s\n", e.what());
        success = false;
    }
    if (success) {
        GLuint tex = 0;
        if (tex_ && !isnull_)
            tex = tex_;
        else
            glGenTextures(1, &tex);
        glBindTexture(GL_TEXTURE_2D, tex);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        GLint fmt;
        if (iscolor_)
            fmt = hasalpha_ ? GL_RGBA : GL_RGB;
        else
            fmt = hasalpha_ ? GL_LUMINANCE_ALPHA : GL_LUMINANCE;
        glTexImage2D(GL_TEXTURE_2D, 0, fmt, twidth_, theight_, 0,
                     fmt, GL_UNSIGNED_BYTE, buf_);
        tex_ = tex;
        loaded_ = true;
        isnull_ = false;
    } else {
        fprintf(stderr, "    failed\n");
        unloadTex();
        // Make sure to set loaded_ true before checking if the dummy
        // texture is loaded, because this might be the dummy texture.
        loaded_ = true;
        isnull_ = true;
        Texture &t = DummyTexture::nullTexture;
        if (!t.loaded_)
            t.loadTex();
        tex_ = t.tex_;
    }
}

void Texture::unloadTex()
{
    if (tex_ != 0 && !isnull_) {
        fprintf(stderr, "Unloading texture %s\n", name().c_str());
        GLuint tex = tex_;
        glDeleteTextures(1, &tex);
    }
    tex_ = 0;
    loaded_ = false;
    isnull_ = false;
}

unsigned int
round_up_pow2(unsigned int x)
{
    x -= 1;
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;
    x += 1;
    return x;
}

void Texture::alloc(unsigned int width, unsigned int height,
                    bool iscolor, bool hasalpha)
{
    // FIXME overflow, error handling
    unsigned int
        twidth = round_up_pow2(width), theight = round_up_pow2(height),
        chan = (iscolor ? 3 : 1) + (hasalpha ? 1 : 0),
        rb = (twidth * chan + 3) & ~3;
    size_t sz = (size_t)rb * theight;
    if (bufsz_ != sz) {
        void *buf = malloc(sz);
        if (!buf) throw std::bad_alloc();
        if (buf_) free(buf_);
        buf_ = buf;
        bufsz_ = sz;
    }
    width_ = width;
    height_ = height;
    twidth_ = twidth;
    theight_ = theight;
    iscolor_ = iscolor;
    hasalpha_ = hasalpha;
}
<|endoftext|>