<commit_before>/*
 * Copyright (c) 2010-2011, 2014, 2016-2017 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2006 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "arch/arm/nativetrace.hh"

#include "arch/arm/regs/cc.hh"
#include "arch/arm/regs/misc.hh"
#include "base/compiler.hh"
#include "cpu/thread_context.hh"
#include "debug/ExecRegDelta.hh"
#include "params/ArmNativeTrace.hh"
#include "sim/byteswap.hh"

namespace gem5
{

using namespace ArmISA;

namespace Trace {

[[maybe_unused]] static const char *regNames[] = {
    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
    "r8", "r9", "r10", "fp", "r12", "sp", "lr", "pc",
    "cpsr", "f0", "f1", "f2", "f3", "f4", "f5", "f6",
    "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14",
    "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22",
    "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30",
    "f31", "fpscr"
};

void
Trace::ArmNativeTrace::ThreadState::update(NativeTrace *parent)
{
    oldState = state[current];
    current = (current + 1) % 2;
    newState = state[current];

    memcpy(newState, oldState, sizeof(state[0]));

    uint64_t diffVector;
    parent->read(&diffVector, sizeof(diffVector));
    diffVector = letoh(diffVector);

    int changes = 0;
    for (int i = 0; i < STATE_NUMVALS; i++) {
        if (diffVector & 0x1) {
            changed[i] = true;
            changes++;
        } else {
            changed[i] = false;
        }
        diffVector >>= 1;
    }

    uint64_t values[changes];
    parent->read(values, sizeof(values));
    int pos = 0;
    for (int i = 0; i < STATE_NUMVALS; i++) {
        if (changed[i]) {
            newState[i] = letoh(values[pos++]);
            changed[i] = (newState[i] != oldState[i]);
        }
    }
}

void
Trace::ArmNativeTrace::ThreadState::update(ThreadContext *tc)
{
    oldState = state[current];
    current = (current + 1) % 2;
    newState = state[current];

    // Regular int regs
    for (int i = 0; i < 15; i++) {
        newState[i] = tc->readIntReg(i);
        changed[i] = (oldState[i] != newState[i]);
    }

    //R15, aliased with the PC
    newState[STATE_PC] = tc->pcState().as<ArmISA::PCState>().npc();
    changed[STATE_PC] = (newState[STATE_PC] != oldState[STATE_PC]);

    //CPSR
    CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
    cpsr.nz = tc->readCCReg(CCREG_NZ);
    cpsr.c = tc->readCCReg(CCREG_C);
    cpsr.v = tc->readCCReg(CCREG_V);
    cpsr.ge = tc->readCCReg(CCREG_GE);

    newState[STATE_CPSR] = cpsr;
    changed[STATE_CPSR] = (newState[STATE_CPSR] != oldState[STATE_CPSR]);

    for (int i = 0; i < NumVecV7ArchRegs; i++) {
        auto *vec = tc->readVecReg(RegId(VecRegClass,i)).as<uint64_t>();
        newState[STATE_F0 + 2*i] = vec[0];
        newState[STATE_F0 + 2*i + 1] = vec[1];
    }
    newState[STATE_FPSCR] = tc->readMiscRegNoEffect(MISCREG_FPSCR) |
                            tc->readCCReg(CCREG_FP);
}

void
Trace::ArmNativeTrace::check(NativeTraceRecord *record)
{
    ThreadContext *tc = record->getThread();
    // This area is read only on the target. It can't stop there to tell us
    // what's going on, so we should skip over anything there also.
    if (tc->pcState().as<ArmISA::PCState>().npc() > 0xffff0000)
        return;
    nState.update(this);
    mState.update(tc);

    // If a syscall just happened native trace needs another tick
    if ((mState.oldState[STATE_PC] == nState.oldState[STATE_PC]) &&
            (mState.newState[STATE_PC] - 4 == nState.newState[STATE_PC])) {
            DPRINTF(ExecRegDelta, "Advancing to match PCs after syscall\n");
            nState.update(this);

    }

    bool errorFound = false;
    // Regular int regs
    for (int i = 0; i < STATE_NUMVALS; i++) {
        if (nState.changed[i] || mState.changed[i]) {
            bool oldMatch = (mState.oldState[i] == nState.oldState[i]);
            bool newMatch = (mState.newState[i] == nState.newState[i]);
            if (oldMatch && newMatch) {
                // The more things change, the more they stay the same.
                continue;
            }

            errorFound = true;

#ifndef NDEBUG
            const char *vergence = "  ";
            if (oldMatch && !newMatch) {
                vergence = "<>";
            } else if (!oldMatch && newMatch) {
                vergence = "><";
            }

            if (!nState.changed[i]) {
                DPRINTF(ExecRegDelta, "%s [%5s] "\
                                      "Native:         %#010x         "\
                                      "M5:     %#010x => %#010x\n",
                                      vergence, regNames[i],
                                      nState.newState[i],
                                      mState.oldState[i], mState.newState[i]);
            } else if (!mState.changed[i]) {
                DPRINTF(ExecRegDelta, "%s [%5s] "\
                                      "Native: %#010x => %#010x "\
                                      "M5:             %#010x        \n",
                                      vergence, regNames[i],
                                      nState.oldState[i], nState.newState[i],
                                      mState.newState[i]);
            } else {
                DPRINTF(ExecRegDelta, "%s [%5s] "\
                                      "Native: %#010x => %#010x "\
                                      "M5:     %#010x => %#010x\n",
                                      vergence, regNames[i],
                                      nState.oldState[i], nState.newState[i],
                                      mState.oldState[i], mState.newState[i]);
            }
#endif
        }
    }
    if (errorFound) {
        StaticInstPtr inst = record->getStaticInst();
        assert(inst);
        bool ran = true;
        if (inst->isMicroop()) {
            ran = false;
            inst = record->getMacroStaticInst();
        }
        assert(inst);
        record->traceInst(inst, ran);

        bool pcError = (mState.newState[STATE_PC] !=
                        nState.newState[STATE_PC]);
        if (stopOnPCError && pcError)
            panic("Native trace detected an error in control flow!");
    }
}

} // namespace Trace
} // namespace gem5
<commit_msg>arch-arm: Fix dangling pointer to unnamed temporary in nativetrace.cc.<commit_after>/*
 * Copyright (c) 2010-2011, 2014, 2016-2017 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2006 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "arch/arm/nativetrace.hh"

#include "arch/arm/regs/cc.hh"
#include "arch/arm/regs/misc.hh"
#include "base/compiler.hh"
#include "cpu/thread_context.hh"
#include "debug/ExecRegDelta.hh"
#include "params/ArmNativeTrace.hh"
#include "sim/byteswap.hh"

namespace gem5
{

using namespace ArmISA;

namespace Trace {

[[maybe_unused]] static const char *regNames[] = {
    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
    "r8", "r9", "r10", "fp", "r12", "sp", "lr", "pc",
    "cpsr", "f0", "f1", "f2", "f3", "f4", "f5", "f6",
    "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14",
    "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22",
    "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30",
    "f31", "fpscr"
};

void
Trace::ArmNativeTrace::ThreadState::update(NativeTrace *parent)
{
    oldState = state[current];
    current = (current + 1) % 2;
    newState = state[current];

    memcpy(newState, oldState, sizeof(state[0]));

    uint64_t diffVector;
    parent->read(&diffVector, sizeof(diffVector));
    diffVector = letoh(diffVector);

    int changes = 0;
    for (int i = 0; i < STATE_NUMVALS; i++) {
        if (diffVector & 0x1) {
            changed[i] = true;
            changes++;
        } else {
            changed[i] = false;
        }
        diffVector >>= 1;
    }

    uint64_t values[changes];
    parent->read(values, sizeof(values));
    int pos = 0;
    for (int i = 0; i < STATE_NUMVALS; i++) {
        if (changed[i]) {
            newState[i] = letoh(values[pos++]);
            changed[i] = (newState[i] != oldState[i]);
        }
    }
}

void
Trace::ArmNativeTrace::ThreadState::update(ThreadContext *tc)
{
    oldState = state[current];
    current = (current + 1) % 2;
    newState = state[current];

    // Regular int regs
    for (int i = 0; i < 15; i++) {
        newState[i] = tc->readIntReg(i);
        changed[i] = (oldState[i] != newState[i]);
    }

    //R15, aliased with the PC
    newState[STATE_PC] = tc->pcState().as<ArmISA::PCState>().npc();
    changed[STATE_PC] = (newState[STATE_PC] != oldState[STATE_PC]);

    //CPSR
    CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
    cpsr.nz = tc->readCCReg(CCREG_NZ);
    cpsr.c = tc->readCCReg(CCREG_C);
    cpsr.v = tc->readCCReg(CCREG_V);
    cpsr.ge = tc->readCCReg(CCREG_GE);

    newState[STATE_CPSR] = cpsr;
    changed[STATE_CPSR] = (newState[STATE_CPSR] != oldState[STATE_CPSR]);

    for (int i = 0; i < NumVecV7ArchRegs; i++) {
        auto vec = tc->readVecReg(RegId(VecRegClass,i));
        auto *arr = vec.as<uint64_t>();
        newState[STATE_F0 + 2*i] = arr[0];
        newState[STATE_F0 + 2*i + 1] = arr[1];
    }
    newState[STATE_FPSCR] = tc->readMiscRegNoEffect(MISCREG_FPSCR) |
                            tc->readCCReg(CCREG_FP);
}

void
Trace::ArmNativeTrace::check(NativeTraceRecord *record)
{
    ThreadContext *tc = record->getThread();
    // This area is read only on the target. It can't stop there to tell us
    // what's going on, so we should skip over anything there also.
    if (tc->pcState().as<ArmISA::PCState>().npc() > 0xffff0000)
        return;
    nState.update(this);
    mState.update(tc);

    // If a syscall just happened native trace needs another tick
    if ((mState.oldState[STATE_PC] == nState.oldState[STATE_PC]) &&
            (mState.newState[STATE_PC] - 4 == nState.newState[STATE_PC])) {
            DPRINTF(ExecRegDelta, "Advancing to match PCs after syscall\n");
            nState.update(this);

    }

    bool errorFound = false;
    // Regular int regs
    for (int i = 0; i < STATE_NUMVALS; i++) {
        if (nState.changed[i] || mState.changed[i]) {
            bool oldMatch = (mState.oldState[i] == nState.oldState[i]);
            bool newMatch = (mState.newState[i] == nState.newState[i]);
            if (oldMatch && newMatch) {
                // The more things change, the more they stay the same.
                continue;
            }

            errorFound = true;

#ifndef NDEBUG
            const char *vergence = "  ";
            if (oldMatch && !newMatch) {
                vergence = "<>";
            } else if (!oldMatch && newMatch) {
                vergence = "><";
            }

            if (!nState.changed[i]) {
                DPRINTF(ExecRegDelta, "%s [%5s] "\
                                      "Native:         %#010x         "\
                                      "M5:     %#010x => %#010x\n",
                                      vergence, regNames[i],
                                      nState.newState[i],
                                      mState.oldState[i], mState.newState[i]);
            } else if (!mState.changed[i]) {
                DPRINTF(ExecRegDelta, "%s [%5s] "\
                                      "Native: %#010x => %#010x "\
                                      "M5:             %#010x        \n",
                                      vergence, regNames[i],
                                      nState.oldState[i], nState.newState[i],
                                      mState.newState[i]);
            } else {
                DPRINTF(ExecRegDelta, "%s [%5s] "\
                                      "Native: %#010x => %#010x "\
                                      "M5:     %#010x => %#010x\n",
                                      vergence, regNames[i],
                                      nState.oldState[i], nState.newState[i],
                                      mState.oldState[i], mState.newState[i]);
            }
#endif
        }
    }
    if (errorFound) {
        StaticInstPtr inst = record->getStaticInst();
        assert(inst);
        bool ran = true;
        if (inst->isMicroop()) {
            ran = false;
            inst = record->getMacroStaticInst();
        }
        assert(inst);
        record->traceInst(inst, ran);

        bool pcError = (mState.newState[STATE_PC] !=
                        nState.newState[STATE_PC]);
        if (stopOnPCError && pcError)
            panic("Native trace detected an error in control flow!");
    }
}

} // namespace Trace
} // namespace gem5
<|endoftext|>


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

/*
 * Go onto IRC
 * badly hacked.
 * Linas October 2007
 */

#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include "IRC.h"

#include "whirr-sockets.h"

static const char *channel = "#opencog-test";
static const char *vstring = "La Cogita OpenCog (http://opencog.org) chatbot version 0.1";

int end_of_motd(const char* params, irc_reply_data* ird, void* data)
{
	IRC* conn = (IRC*)data;

	printf("duude par=%s\n", params);
	printf("duude got motd nick=%s ident=%s host=%s target=%s\n",
		ird->nick, ird->ident, ird->host, ird->target);

	sleep(1);
	conn->join (channel);
	printf("duude done join\n");
	sleep(2);
	conn->notice (channel, "ola");
	printf("duude done notice\n");
	sleep(2);
	conn->privmsg (channel, "here we are");
	printf("duude done priv\n");
	return 0;
}

int got_privmsg(const char* params, irc_reply_data* ird, void* data)
{
	IRC* conn = (IRC*)data;

	printf("input=%s\n", params);
	printf("nick=%s ident=%s host=%s target=%s\n", ird->nick, ird->ident, ird->host, ird->target);

	const char * start = NULL;
	int priv = 0;
	if (!strcmp (ird->target, "cogita-bot")) {priv = 1; start = params+1; }
	else if (!strncmp (params, ":cogita-bot:", 12)) start = params+12;
	else if (!strncmp (params, ":cog:", 5)) start = params+5;
	else if (!strncmp (params, ":cogita:", 8)) start = params+8;

	if (!start) return 0;
	char * msg_target = NULL;
	if (priv)
	{
		msg_target = ird->nick;
	}
	else
	{
		msg_target = ird->target;
	}

	if ((0x1 == start[0]) && !strncmp (&start[1], "VERSION", 7))
	{
		printf ("VERSION: %s\n", vstring);
		conn->privmsg (msg_target, vstring);
		return 0;
	}

	// printf ("duude starting with 0x%x %s\n", start[0], start);
	size_t textlen = strlen(start);
	size_t len = textlen;
	len += strlen ("(say-id-english )");
	len += strlen (ird->nick);
	len += 120;

	char * cmdline = (char *) malloc(sizeof (char) * (len+1));

	// Get into the opencog scheme shell, and run the command
	strcpy (cmdline, "scm\n(say-id-english \"");
	strcat (cmdline, ird->nick);
	strcat (cmdline, "\" \"");
	size_t toff = strlen(cmdline);
	strcat (cmdline, start);
	strcat (cmdline, "\")\n");

	// strip out quotation marks, replace with blanks, for now.
	for (size_t i =0; i<textlen; i++)
	{
		if ('\"' == cmdline[toff+i]) cmdline[toff+i] = ' ';
	}

	// printf ("Sending to opencog: %s\n", cmdline);
	char * reply = whirr_sock_io (cmdline);
	printf ("opencog reply: %s\n", reply);

	/* Each newline has to be on its own line */
	/* Limit to 5 replies so we don't get kicked for flooding */
	int cnt = 0;
	char * p = reply;
	while (*p)
	{
		char *ep = strchr (p, '\n');
		if (!ep)
		{
			conn->privmsg (msg_target, p);
			break;
		}
		ep ++;
		int save = *ep;
		*ep = 0x0;
		if (0 < strlen(p))
			conn->privmsg (msg_target, p);
		*ep = save;
		p = ep;
		cnt ++;
		if (4 < cnt) sleep(1);
		if (8 < cnt) sleep(1);
	}

	free(reply);
	return 0;
}

int main (int argc, char * argv[])
{
	whirr_sock_setup();

	IRC conn;

	conn.hook_irc_command("376", &end_of_motd);
	conn.hook_irc_command("PRIVMSG", &got_privmsg);

	const char *login = getlogin();

	// The login-name, nick, etc. are there only to make it look
	// pretty on IRC ident.
	conn.start ("irc.freenode.net", 6667, "cogita-bot", login,
	            "La Cogita OpenCog chatbot", "asdf");

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

/*
 * Go onto IRC
 * badly hacked.
 * Linas October 2007
 */

#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include "IRC.h"

#include "whirr-sockets.h"

static const char *channel = "#opencog-test";
static const char *vstring = "La Cogita OpenCog (http://opencog.org) chatbot version 0.1";

int end_of_motd(const char* params, irc_reply_data* ird, void* data)
{
	IRC* conn = (IRC*)data;

	printf("duude par=%s\n", params);
	printf("duude got motd nick=%s ident=%s host=%s target=%s\n",
		ird->nick, ird->ident, ird->host, ird->target);

	sleep(1);
	conn->join (channel);
	printf("duude done join\n");
	sleep(2);
	conn->notice (channel, "ola");
	printf("duude done notice\n");
	sleep(2);
	conn->privmsg (channel, "here we are");
	printf("duude done priv\n");
	return 0;
}

int got_privmsg(const char* params, irc_reply_data* ird, void* data)
{
	IRC* conn = (IRC*)data;

	printf("input=%s\n", params);
	printf("nick=%s ident=%s host=%s target=%s\n", ird->nick, ird->ident, ird->host, ird->target);

	const char * start = NULL;
	int priv = 0;
	if (!strcmp (ird->target, "cogita-bot")) {priv = 1; start = params+1; }
	else if (!strncmp (params, ":cogita-bot:", 12)) start = params+12;
	else if (!strncmp (params, ":cog:", 5)) start = params+5;
	else if (!strncmp (params, ":cogita:", 8)) start = params+8;

	if (!start) return 0;
	char * msg_target = NULL;
	if (priv)
	{
		msg_target = ird->nick;
	}
	else
	{
		msg_target = ird->target;
	}

	if ((0x1 == start[0]) && !strncmp (&start[1], "VERSION", 7))
	{
		printf ("VERSION: %s\n", vstring);
		conn->privmsg (msg_target, vstring);
		return 0;
	}

	// printf ("duude starting with 0x%x %s\n", start[0], start);
	size_t textlen = strlen(start);
	size_t len = textlen;
	len += strlen ("(say-id-english )");
	len += strlen (ird->nick);
	len += 120;

	char * cmdline = (char *) malloc(sizeof (char) * (len+1));

	// Get into the opencog scheme shell, and run the command
	strcpy (cmdline, "scm\n(say-id-english \"");
	strcat (cmdline, ird->nick);
	strcat (cmdline, "\" \"");
	size_t toff = strlen(cmdline);
	strcat (cmdline, start);
	strcat (cmdline, "\")\n");

	// strip out quotation marks, replace with blanks, for now.
	for (size_t i =0; i<textlen; i++)
	{
		if ('\"' == cmdline[toff+i]) cmdline[toff+i] = ' ';
	}

	// printf ("Sending to opencog: %s\n", cmdline);
	char * reply = whirr_sock_io (cmdline);
	printf ("opencog reply: %s\n", reply);

	/* Each newline has to be on its own line */
	/* Limit to 5 replies so we don't get kicked for flooding */
	int cnt = 0;
	char * p = reply;
	while (*p)
	{
		char *ep = strchr (p, '\n');
		if (!ep)
		{
			if (0 < strlen(p))
				conn->privmsg (msg_target, p);
			break;
		}
		ep ++;
		int save = *ep;
		*ep = 0x0;
		if (0 < strlen(p))
			conn->privmsg (msg_target, p);
		*ep = save;
		p = ep;
		cnt ++;
		if (4 < cnt) sleep(1);
		if (8 < cnt) sleep(1);
	}

	free(reply);
	return 0;
}

int main (int argc, char * argv[])
{
	whirr_sock_setup();

	IRC conn;

	conn.hook_irc_command("376", &end_of_motd);
	conn.hook_irc_command("PRIVMSG", &got_privmsg);

	const char *login = getlogin();

	// The login-name, nick, etc. are there only to make it look
	// pretty on IRC ident.
	conn.start ("irc.freenode.net", 6667, "cogita-bot", login,
	            "La Cogita OpenCog chatbot", "asdf");

	conn.message_loop();
}
<|endoftext|>


<commit_before>/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * file-photoflow.c -- raw file format plug-in that uses photoflow
 * Copyright (C) 2012 Simon Budig <simon@gimp.org>
 * Copyright (C) 2016 Tobias Ellinghaus <me@houz.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

//#include "config.h"

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fstream>
#include <sstream>

#include <glib/gstdio.h>
#include <glib/gi18n.h>

#define INIT_I18N()

#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>

/*#include "libgimp/stdplugins-intl.h"*/

#include "file-formats.h"

#define LOAD_THUMB_PROC "file-raw-load-thumb"

static std::string phf_binary;

static void     query                (void);
static void     run                  (const gchar      *name,
                                      gint              nparams,
                                      const GimpParam  *param,
                                      gint             *nreturn_vals,
                                      GimpParam       **return_vals);
static gint32   load_image           (const gchar      *filename,
                                      GimpRunMode       run_mode,
                                      GError          **error);

static gint32   load_thumbnail_image (const gchar      *filename,
                                      gint             thumb_size,
                                      gint             *width,
                                      gint             *height,
                                      GError          **error);

const GimpPlugInInfo PLUG_IN_INFO =
{
  NULL,  /* init_proc */
  NULL,  /* quit_proc */
  query, /* query proc */
  run,   /* run_proc */
};

MAIN ()

void
query (void)
{
  phf_binary = "photoflow";
  char* phf_path = getenv("PHOTOFLOW_PATH");
  if( phf_path ) phf_binary = phf_path;

  printf("file-photoflow query() called, phf_binary=%s\n",phf_binary.c_str());

  static const GimpParamDef load_args[] =
  {
    { GIMP_PDB_INT32,  "run-mode",     "The run mode { RUN-INTERACTIVE (0) }" },
    { GIMP_PDB_STRING, "filename",     "The name of the file to load." },
    { GIMP_PDB_STRING, "raw-filename", "The name entered" },
  };

  static const GimpParamDef load_return_vals[] =
  {
    { GIMP_PDB_IMAGE,  "image",        "Output image" }
  };

  static const GimpParamDef thumb_args[] =
  {
    { GIMP_PDB_STRING, "filename",     "The name of the file to load"  },
    { GIMP_PDB_INT32,  "thumb-size",   "Preferred thumbnail size"      }
  };

  static const GimpParamDef thumb_return_vals[] =
  {
    { GIMP_PDB_IMAGE,  "image",        "Thumbnail image"               },
    { GIMP_PDB_INT32,  "image-width",  "Width of full-sized image"     },
    { GIMP_PDB_INT32,  "image-height", "Height of full-sized image"    }
  };

  /* check if photoflow is installed
   * TODO: allow setting the location of the executable in preferences
   */
  gchar    *argv[]           = { phf_binary.c_str(), "--version", NULL };
  gchar    *photoflow_stdout = NULL;
  gboolean  have_photoflow   = FALSE;
  gint      i;

  if (g_spawn_sync (NULL,
      argv,
      NULL,
      G_SPAWN_STDERR_TO_DEV_NULL |
      G_SPAWN_SEARCH_PATH,
      NULL,
      NULL,
      &photoflow_stdout,
      NULL,
      NULL,
      NULL)) {
    gint major, minor, patch;

    printf("stdout:\n%s\n",photoflow_stdout);
    gchar* version_str = strstr(photoflow_stdout, "this is photoflow");
    if(version_str) {
      int nread = sscanf (version_str,
          "this is photoflow %d.%d.%d",
          &major, &minor, &patch);
      printf("nread: %d\n",nread);
      if ( nread == 3) {
        printf("Photoflow version: %d.%d.%d\n", major, minor, patch);
        if( major >= 0 && minor >= 2 && patch >= 8 ) {
          have_photoflow = TRUE;
        }
      }
    }

    g_free (photoflow_stdout);
  } else {
    printf("file-photoflow query(): failed to run photoflow (%s)\n",phf_binary.c_str());
  }

  if (! have_photoflow)
    return;

  /*
  gimp_install_procedure (LOAD_THUMB_PROC,
                          "Load thumbnail from a raw image via photoflow",
                          "This plug-in loads a thumbnail from a raw image by calling photoflow-cli.",
                          "Tobias Ellinghaus",
                          "Tobias Ellinghaus",
                          "2016",
                          NULL,
                          NULL,
                          GIMP_PLUGIN,
                          G_N_ELEMENTS (thumb_args),
                          G_N_ELEMENTS (thumb_return_vals),
                          thumb_args, thumb_return_vals);
  */
  for (i = 0; i < G_N_ELEMENTS (file_formats); i++)
    {
      const FileFormat *format = &file_formats[i];

      gimp_install_procedure (format->load_proc,
                              format->load_blurb,
                              format->load_help,
                              "Tobias Ellinghaus",
                              "Tobias Ellinghaus",
                              "2016",
                              format->file_type,
                              NULL,
                              GIMP_PLUGIN,
                              G_N_ELEMENTS (load_args),
                              G_N_ELEMENTS (load_return_vals),
                              load_args, load_return_vals);

      gimp_register_file_handler_mime (format->load_proc,
                                       format->mime_type);
      gimp_register_magic_load_handler (format->load_proc,
                                        format->extensions,
                                        "",
                                        format->magic);

      gimp_register_thumbnail_loader (format->load_proc, LOAD_THUMB_PROC);
    }
}

static void
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
{
  static GimpParam   values[6];
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
  GimpRunMode        run_mode;
  gint               image_ID;
  GError            *error = NULL;
  gint               i;

  INIT_I18N ();

  run_mode = param[0].data.d_int32;

  *nreturn_vals = 1;
  *return_vals  = values;

  values[0].type          = GIMP_PDB_STATUS;
  values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;

  phf_binary = "photoflow";
  char* phf_path = getenv("PHOTOFLOW_PATH");
  if( phf_path ) phf_binary = phf_path;

  printf("file-photoflow: run() procedure called, name=%s, phf_binary=%s\n", name, phf_binary.c_str());

  /* check if the format passed is actually supported & load */
  for (i = 0; i < G_N_ELEMENTS (file_formats); i++)
    {
      const FileFormat *format = &file_formats[i];

      if (format->load_proc && ! strcmp (name, format->load_proc))
        {
          image_ID = load_image (param[1].data.d_string, run_mode, &error);

          if (image_ID != -1)
            {
              *nreturn_vals = 2;
              values[1].type         = GIMP_PDB_IMAGE;
              values[1].data.d_image = image_ID;
            }
          else
            {
              status = GIMP_PDB_EXECUTION_ERROR;
            }

          break;
        }
      else if (! strcmp (name, LOAD_THUMB_PROC))
        {
          gint width  = 0;
          gint height = 0;

          image_ID = load_thumbnail_image (param[0].data.d_string,
                                           param[1].data.d_int32,
                                           &width,
                                           &height,
                                           &error);

          if (image_ID != -1)
            {
              *nreturn_vals = 6;
              values[1].type         = GIMP_PDB_IMAGE;
              values[1].data.d_image = image_ID;
              values[2].type         = GIMP_PDB_INT32;
              values[2].data.d_int32 = width;
              values[3].type         = GIMP_PDB_INT32;
              values[3].data.d_int32 = height;
              values[4].type         = GIMP_PDB_INT32;
              values[4].data.d_int32 = GIMP_RGB_IMAGE;
              values[5].type         = GIMP_PDB_INT32;
              values[5].data.d_int32 = 1; /* num_layers */
            }
          else
            {
              status = GIMP_PDB_EXECUTION_ERROR;
            }

          break;
        }
    }

  if (i == G_N_ELEMENTS (file_formats))
    status = GIMP_PDB_CALLING_ERROR;

  if (status != GIMP_PDB_SUCCESS && error)
    {
      *nreturn_vals = 2;
      values[1].type           = GIMP_PDB_STRING;
      values[1].data.d_string  = error->message;
    }

  values[0].data.d_status = status;
}

static gint32
load_image (const gchar  *filename,
            GimpRunMode   run_mode,
            GError      **error)
{
  gint32  image_ID        = -1;
  gchar  *filename_out    = gimp_temp_name ("tif");
  gchar  *pfiname         = gimp_temp_name ("pfi");

  gchar *photoflow_stdout = NULL;

  /* linear sRGB for now as GIMP uses that internally in many places anyway */
  gchar *argv[] =
    {
        phf_binary.c_str(),
      "--plugin",
      (gchar *) filename,
      (gchar *) filename_out,
      (gchar *) pfiname,
      NULL
    };

  gimp_progress_init_printf (_("Opening '%s'"),
                             gimp_filename_to_utf8 (filename));

  char cmd[1000];
  sprintf(cmd,"%s --plugin \"%s\" \"%s\" \"%s\"", phf_binary.c_str(),
      filename, filename_out, pfiname);
  printf ("Starting photoflow: %s\n",cmd);
  system(cmd);
/*
  if (g_spawn_sync (NULL,
                    argv,
                    NULL,
//                     G_SPAWN_STDOUT_TO_DEV_NULL |
                    G_SPAWN_STDERR_TO_DEV_NULL |
                    G_SPAWN_SEARCH_PATH,
                    NULL,
                    NULL,
                    &photoflow_stdout,
                    NULL,
                    NULL,
                    error))
    {
      image_ID = gimp_file_load (run_mode, filename_out, filename_out);
      if (image_ID != -1) {
        gimp_image_set_filename (image_ID, filename);
        gint nlayers;
        gint* layers = gimp_image_get_layers(image_ID, &nlayers);
        gint layer = layers[nlayers-1];
        std::ifstream t;
        std::stringstream strstr;
        t.open( pfiname );
        strstr << t.rdbuf();
        char* buffer = strdup( strstr.str().c_str() );
        t.close();

        GimpParasite *cfg_parasite;
        cfg_parasite = gimp_parasite_new("phf-config",
            GIMP_PARASITE_PERSISTENT, strlen(buffer), buffer);
        gimp_item_attach_parasite(layer, cfg_parasite);
        gimp_parasite_free(cfg_parasite);
      }
    }
*/
  printf ("photoflow_stdout: %p\n", (void*)photoflow_stdout);
  if (photoflow_stdout) printf ("%s\n", photoflow_stdout);
  g_free(photoflow_stdout);

  printf ("filename_out: %s\n", filename_out);
  printf ("pfiname: %s\n", pfiname);

  g_unlink (filename_out);
  g_unlink (pfiname);
  g_free (filename_out);

  gimp_progress_update (1.0);

  return image_ID;
}

static gint32
load_thumbnail_image (const gchar   *filename,
                      gint           thumb_size,
                      gint          *width,
                      gint          *height,
                      GError       **error)
{
  gint32  image_ID         = -1;
  gchar  *filename_out     = gimp_temp_name ("jpg");
  gchar  *size             = g_strdup_printf ("%d", thumb_size);
  GFile  *lua_file         = gimp_data_directory_file ("file-photoflow",
                                                       "get-size.lua",
                                                       NULL);
  gchar  *lua_script       = g_file_get_path (lua_file);
  gchar  *lua_quoted       = g_shell_quote (lua_script);
  gchar  *lua_cmd          = g_strdup_printf ("dofile(%s)", lua_quoted);
  gchar  *photoflow_stdout = NULL;

  gchar *argv[] =
    {
      "photoflow-cli",
      (gchar *) filename, filename_out,
      "--width",          size,
      "--height",         size,
      "--hq",             "false",
      "--core",
      "--conf",           "plugins/lighttable/export/icctype=3",
      "--luacmd",         lua_cmd,
      NULL
    };

  g_object_unref (lua_file);
  g_free (lua_script);
  g_free (lua_quoted);

  gimp_progress_init_printf (_("Opening thumbnail for '%s'"),
                             gimp_filename_to_utf8 (filename));

  *width = *height = thumb_size;

  if (g_spawn_sync (NULL,
                    argv,
                    NULL,
                    G_SPAWN_STDERR_TO_DEV_NULL |
                    G_SPAWN_SEARCH_PATH,
                    NULL,
                    NULL,
                    &photoflow_stdout,
                    NULL,
                    NULL,
                    error))
    {
      gimp_progress_update (0.5);

      image_ID = gimp_file_load (GIMP_RUN_NONINTERACTIVE,
                                 filename_out,
                                 filename_out);
      if (image_ID != -1)
        {
          /* the size reported by raw files isn't precise,
           * but it should be close enough to get an idea.
           */
          gchar *start_of_size = g_strstr_len (photoflow_stdout,
                                               -1,
                                               "[dt4gimp]");
          if (start_of_size)
            sscanf (start_of_size, "[dt4gimp] %d %d", width, height);

          /* is this needed for thumbnails? */
          gimp_image_set_filename (image_ID, filename);
        }
    }

  gimp_progress_update (1.0);

  g_unlink (filename_out);
  g_free (filename_out);
  g_free (size);
  g_free (lua_cmd);
  g_free (photoflow_stdout);

  return image_ID;
}
<commit_msg>A portion of the code was commented by mistake; fixed.<commit_after>/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * file-photoflow.c -- raw file format plug-in that uses photoflow
 * Copyright (C) 2012 Simon Budig <simon@gimp.org>
 * Copyright (C) 2016 Tobias Ellinghaus <me@houz.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

//#include "config.h"

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fstream>
#include <sstream>

#include <glib/gstdio.h>
#include <glib/gi18n.h>

#define INIT_I18N()

#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>

/*#include "libgimp/stdplugins-intl.h"*/

#include "file-formats.h"

#define LOAD_THUMB_PROC "file-raw-load-thumb"

static std::string phf_binary;

static void     query                (void);
static void     run                  (const gchar      *name,
                                      gint              nparams,
                                      const GimpParam  *param,
                                      gint             *nreturn_vals,
                                      GimpParam       **return_vals);
static gint32   load_image           (const gchar      *filename,
                                      GimpRunMode       run_mode,
                                      GError          **error);

static gint32   load_thumbnail_image (const gchar      *filename,
                                      gint             thumb_size,
                                      gint             *width,
                                      gint             *height,
                                      GError          **error);

const GimpPlugInInfo PLUG_IN_INFO =
{
  NULL,  /* init_proc */
  NULL,  /* quit_proc */
  query, /* query proc */
  run,   /* run_proc */
};

MAIN ()

void
query (void)
{
  phf_binary = "photoflow";
  char* phf_path = getenv("PHOTOFLOW_PATH");
  if( phf_path ) phf_binary = phf_path;

  printf("file-photoflow query() called, phf_binary=%s\n",phf_binary.c_str());

  static const GimpParamDef load_args[] =
  {
    { GIMP_PDB_INT32,  "run-mode",     "The run mode { RUN-INTERACTIVE (0) }" },
    { GIMP_PDB_STRING, "filename",     "The name of the file to load." },
    { GIMP_PDB_STRING, "raw-filename", "The name entered" },
  };

  static const GimpParamDef load_return_vals[] =
  {
    { GIMP_PDB_IMAGE,  "image",        "Output image" }
  };

  static const GimpParamDef thumb_args[] =
  {
    { GIMP_PDB_STRING, "filename",     "The name of the file to load"  },
    { GIMP_PDB_INT32,  "thumb-size",   "Preferred thumbnail size"      }
  };

  static const GimpParamDef thumb_return_vals[] =
  {
    { GIMP_PDB_IMAGE,  "image",        "Thumbnail image"               },
    { GIMP_PDB_INT32,  "image-width",  "Width of full-sized image"     },
    { GIMP_PDB_INT32,  "image-height", "Height of full-sized image"    }
  };

  /* check if photoflow is installed
   * TODO: allow setting the location of the executable in preferences
   */
  gchar    *argv[]           = { phf_binary.c_str(), "--version", NULL };
  gchar    *photoflow_stdout = NULL;
  gboolean  have_photoflow   = FALSE;
  gint      i;

  if (g_spawn_sync (NULL,
      argv,
      NULL,
      G_SPAWN_STDERR_TO_DEV_NULL |
      G_SPAWN_SEARCH_PATH,
      NULL,
      NULL,
      &photoflow_stdout,
      NULL,
      NULL,
      NULL)) {
    gint major, minor, patch;

    printf("stdout:\n%s\n",photoflow_stdout);
    gchar* version_str = strstr(photoflow_stdout, "this is photoflow");
    if(version_str) {
      int nread = sscanf (version_str,
          "this is photoflow %d.%d.%d",
          &major, &minor, &patch);
      printf("nread: %d\n",nread);
      if ( nread == 3) {
        printf("Photoflow version: %d.%d.%d\n", major, minor, patch);
        if( major >= 0 && minor >= 2 && patch >= 8 ) {
          have_photoflow = TRUE;
        }
      }
    }

    g_free (photoflow_stdout);
  } else {
    printf("file-photoflow query(): failed to run photoflow (%s)\n",phf_binary.c_str());
  }

  if (! have_photoflow)
    return;

  /*
  gimp_install_procedure (LOAD_THUMB_PROC,
                          "Load thumbnail from a raw image via photoflow",
                          "This plug-in loads a thumbnail from a raw image by calling photoflow-cli.",
                          "Tobias Ellinghaus",
                          "Tobias Ellinghaus",
                          "2016",
                          NULL,
                          NULL,
                          GIMP_PLUGIN,
                          G_N_ELEMENTS (thumb_args),
                          G_N_ELEMENTS (thumb_return_vals),
                          thumb_args, thumb_return_vals);
  */
  for (i = 0; i < G_N_ELEMENTS (file_formats); i++)
    {
      const FileFormat *format = &file_formats[i];

      gimp_install_procedure (format->load_proc,
                              format->load_blurb,
                              format->load_help,
                              "Tobias Ellinghaus",
                              "Tobias Ellinghaus",
                              "2016",
                              format->file_type,
                              NULL,
                              GIMP_PLUGIN,
                              G_N_ELEMENTS (load_args),
                              G_N_ELEMENTS (load_return_vals),
                              load_args, load_return_vals);

      gimp_register_file_handler_mime (format->load_proc,
                                       format->mime_type);
      gimp_register_magic_load_handler (format->load_proc,
                                        format->extensions,
                                        "",
                                        format->magic);

      gimp_register_thumbnail_loader (format->load_proc, LOAD_THUMB_PROC);
    }
}

static void
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
{
  static GimpParam   values[6];
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
  GimpRunMode        run_mode;
  gint               image_ID;
  GError            *error = NULL;
  gint               i;

  INIT_I18N ();

  run_mode = param[0].data.d_int32;

  *nreturn_vals = 1;
  *return_vals  = values;

  values[0].type          = GIMP_PDB_STATUS;
  values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;

  phf_binary = "photoflow";
  char* phf_path = getenv("PHOTOFLOW_PATH");
  if( phf_path ) phf_binary = phf_path;

  printf("file-photoflow: run() procedure called, name=%s, phf_binary=%s\n", name, phf_binary.c_str());

  /* check if the format passed is actually supported & load */
  for (i = 0; i < G_N_ELEMENTS (file_formats); i++)
    {
      const FileFormat *format = &file_formats[i];

      if (format->load_proc && ! strcmp (name, format->load_proc))
        {
          image_ID = load_image (param[1].data.d_string, run_mode, &error);

          if (image_ID != -1)
            {
              *nreturn_vals = 2;
              values[1].type         = GIMP_PDB_IMAGE;
              values[1].data.d_image = image_ID;
            }
          else
            {
              status = GIMP_PDB_EXECUTION_ERROR;
            }

          break;
        }
      else if (! strcmp (name, LOAD_THUMB_PROC))
        {
          gint width  = 0;
          gint height = 0;

          image_ID = load_thumbnail_image (param[0].data.d_string,
                                           param[1].data.d_int32,
                                           &width,
                                           &height,
                                           &error);

          if (image_ID != -1)
            {
              *nreturn_vals = 6;
              values[1].type         = GIMP_PDB_IMAGE;
              values[1].data.d_image = image_ID;
              values[2].type         = GIMP_PDB_INT32;
              values[2].data.d_int32 = width;
              values[3].type         = GIMP_PDB_INT32;
              values[3].data.d_int32 = height;
              values[4].type         = GIMP_PDB_INT32;
              values[4].data.d_int32 = GIMP_RGB_IMAGE;
              values[5].type         = GIMP_PDB_INT32;
              values[5].data.d_int32 = 1; /* num_layers */
            }
          else
            {
              status = GIMP_PDB_EXECUTION_ERROR;
            }

          break;
        }
    }

  if (i == G_N_ELEMENTS (file_formats))
    status = GIMP_PDB_CALLING_ERROR;

  if (status != GIMP_PDB_SUCCESS && error)
    {
      *nreturn_vals = 2;
      values[1].type           = GIMP_PDB_STRING;
      values[1].data.d_string  = error->message;
    }

  values[0].data.d_status = status;
}

static gint32
load_image (const gchar  *filename,
            GimpRunMode   run_mode,
            GError      **error)
{
  gint32  image_ID        = -1;
  gchar  *filename_out    = gimp_temp_name ("tif");
  gchar  *pfiname         = gimp_temp_name ("pfi");

  gchar *photoflow_stdout = NULL;

  /* linear sRGB for now as GIMP uses that internally in many places anyway */
  gchar *argv[] =
    {
        phf_binary.c_str(),
      "--plugin",
      (gchar *) filename,
      (gchar *) filename_out,
      (gchar *) pfiname,
      NULL
    };

  gimp_progress_init_printf (_("Opening '%s'"),
                             gimp_filename_to_utf8 (filename));

  char cmd[1000];
  sprintf(cmd,"%s --plugin \"%s\" \"%s\" \"%s\"", phf_binary.c_str(),
      filename, filename_out, pfiname);
  printf ("Starting photoflow: %s\n",cmd);
  system(cmd);
/*
  if (g_spawn_sync (NULL,
                    argv,
                    NULL,
//                     G_SPAWN_STDOUT_TO_DEV_NULL |
                    G_SPAWN_STDERR_TO_DEV_NULL |
                    G_SPAWN_SEARCH_PATH,
                    NULL,
                    NULL,
                    &photoflow_stdout,
                    NULL,
                    NULL,
                    error))*/
    {
      image_ID = gimp_file_load (run_mode, filename_out, filename_out);
      if (image_ID != -1) {
        gimp_image_set_filename (image_ID, filename);
        gint nlayers;
        gint* layers = gimp_image_get_layers(image_ID, &nlayers);
        gint layer = layers[nlayers-1];
        std::ifstream t;
        std::stringstream strstr;
        t.open( pfiname );
        strstr << t.rdbuf();
        char* buffer = strdup( strstr.str().c_str() );
        t.close();

        GimpParasite *cfg_parasite;
        cfg_parasite = gimp_parasite_new("phf-config",
            GIMP_PARASITE_PERSISTENT, strlen(buffer), buffer);
        gimp_item_attach_parasite(layer, cfg_parasite);
        gimp_parasite_free(cfg_parasite);
      }
    }

  printf ("photoflow_stdout: %p\n", (void*)photoflow_stdout);
  if (photoflow_stdout) printf ("%s\n", photoflow_stdout);
  g_free(photoflow_stdout);

  printf ("filename_out: %s\n", filename_out);
  printf ("pfiname: %s\n", pfiname);

  g_unlink (filename_out);
  g_unlink (pfiname);
  g_free (filename_out);
  g_free (pfiname);

  gimp_progress_update (1.0);

  return image_ID;
}

static gint32
load_thumbnail_image (const gchar   *filename,
                      gint           thumb_size,
                      gint          *width,
                      gint          *height,
                      GError       **error)
{
  gint32  image_ID         = -1;
  gchar  *filename_out     = gimp_temp_name ("jpg");
  gchar  *size             = g_strdup_printf ("%d", thumb_size);
  GFile  *lua_file         = gimp_data_directory_file ("file-photoflow",
                                                       "get-size.lua",
                                                       NULL);
  gchar  *lua_script       = g_file_get_path (lua_file);
  gchar  *lua_quoted       = g_shell_quote (lua_script);
  gchar  *lua_cmd          = g_strdup_printf ("dofile(%s)", lua_quoted);
  gchar  *photoflow_stdout = NULL;

  gchar *argv[] =
    {
      "photoflow-cli",
      (gchar *) filename, filename_out,
      "--width",          size,
      "--height",         size,
      "--hq",             "false",
      "--core",
      "--conf",           "plugins/lighttable/export/icctype=3",
      "--luacmd",         lua_cmd,
      NULL
    };

  g_object_unref (lua_file);
  g_free (lua_script);
  g_free (lua_quoted);

  gimp_progress_init_printf (_("Opening thumbnail for '%s'"),
                             gimp_filename_to_utf8 (filename));

  *width = *height = thumb_size;

  if (g_spawn_sync (NULL,
                    argv,
                    NULL,
                    G_SPAWN_STDERR_TO_DEV_NULL |
                    G_SPAWN_SEARCH_PATH,
                    NULL,
                    NULL,
                    &photoflow_stdout,
                    NULL,
                    NULL,
                    error))
    {
      gimp_progress_update (0.5);

      image_ID = gimp_file_load (GIMP_RUN_NONINTERACTIVE,
                                 filename_out,
                                 filename_out);
      if (image_ID != -1)
        {
          /* the size reported by raw files isn't precise,
           * but it should be close enough to get an idea.
           */
          gchar *start_of_size = g_strstr_len (photoflow_stdout,
                                               -1,
                                               "[dt4gimp]");
          if (start_of_size)
            sscanf (start_of_size, "[dt4gimp] %d %d", width, height);

          /* is this needed for thumbnails? */
          gimp_image_set_filename (image_ID, filename);
        }
    }

  gimp_progress_update (1.0);

  g_unlink (filename_out);
  g_free (filename_out);
  g_free (size);
  g_free (lua_cmd);
  g_free (photoflow_stdout);

  return image_ID;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "Font.h"

#include <cairo-win32.h>
#include "FontData.h"
#include "FontFallbackList.h"
#include "GraphicsContext.h"
#include "IntRect.h"

namespace WebCore {

FontData* getFontData(const FontDescription& fontDescription, const AtomicString& fontFace)
{
    // FIXME: Look this up in a hashtable so that we can cache Cairo fonts.  For now we just grab the
    // font over and over.
    LOGFONTW winfont;
    winfont.lfHeight = -fontDescription.computedPixelSize(); // The negative number is intentional.
    winfont.lfWidth = 0;
    winfont.lfEscapement = 0;
    winfont.lfOrientation = 0;
    winfont.lfUnderline = false;
    winfont.lfStrikeOut = false;
    winfont.lfCharSet = DEFAULT_CHARSET;
    winfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
    const int CLEARTYPE_QUALITY = 5;
    winfont.lfQuality = CLEARTYPE_QUALITY; // FIXME: This is the Windows XP constant to force ClearType on.
    winfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
    winfont.lfItalic = fontDescription.italic();
    winfont.lfWeight = fontDescription.weight() == cBoldWeight ? 700 : 400; // FIXME: Support weights for real.
    int len = min(fontFace.length(), LF_FACESIZE - 1);
    memcpy(winfont.lfFaceName, fontFace.characters(), len * sizeof(WORD));
    winfont.lfFaceName[len] = '\0';

    HFONT font = CreateFontIndirectW(&winfont);

    // Windows will always give us a valid pointer here, even if the face name is non-existent.  We have to double-check
    // and see if the family name was really used.
    HDC dc = GetDC((HWND)0);
    SaveDC(dc);
    SelectObject(dc, font);

    int ascent, descent, xHeight, lineSpacing;

    TEXTMETRIC tm;
    GetTextMetrics(dc, &tm);
    ascent = tm.tmAscent;
    descent = tm.tmDescent;
    xHeight = ascent * 0.56f;  // Best guess for xHeight for non-Truetype fonts.
    lineSpacing = tm.tmExternalLeading + tm.tmHeight;

    OUTLINETEXTMETRIC otm;
    if (GetOutlineTextMetrics(dc, sizeof(otm), &otm) > 0) {
        // This is a TrueType font.  We might be able to get an accurate xHeight.
        GLYPHMETRICS gm;
        MAT2 mat = { 1, 0, 0, 1 }; // The identity matrix.
        DWORD len = GetGlyphOutlineW(dc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
        if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
            xHeight = int(gm.gmptGlyphOrigin.y + 0.5f);
    }

    WCHAR name[LF_FACESIZE];
    unsigned resultLength = GetTextFaceW(dc, LF_FACESIZE, name);
    if (resultLength > 0)
        resultLength--; // ignore the null terminator
    RestoreDC(dc, -1);
    ReleaseDC(0, dc);
    dc = 0;
    if (!equalIgnoringCase(fontFace, String(name, resultLength))) {
        DeleteObject(font);
        return 0;
    }

    // This font face is valid.  Create a FontData now.
    FontData* result = new FontData(font, fontDescription);
    result->setMetrics(ascent, descent, xHeight, lineSpacing);
    return result;
}

FontFallbackList::FontFallbackList()
:m_pitch(UnknownPitch)
{

}

FontFallbackList::~FontFallbackList()
{
    deleteAllValues(m_fontList);
}

void FontFallbackList::determinePitch(const Font* font) const
{
    // FIXME: Implement this.
    m_pitch = VariablePitch;
}

void FontFallbackList::invalidate()
{
    // Delete the Cairo fonts.
    m_pitch = UnknownPitch;
    deleteAllValues(m_fontList);
    m_fontList.clear();
}

const FontData* FontFallbackList::fontDataAt(const Font* font, unsigned index) const
{
    // FIXME: Only returning the primary font on Windows right now.
    if (!m_fontList.isEmpty())
        return m_fontList[0];

    // We want to ensure that the primary Cairo font face exists.
    for (const FontFamily* currFamily = &font->fontDescription().family();
         currFamily;
         currFamily = currFamily->next()) {
        if (!currFamily->familyIsEmpty()) {
            // Attempt to create a FontData.
            FontData* font = getFontData(font->fontDescription(), currFamily->family());
            if (font) {
                m_fontList.append(font);
                return font;
            }
        }
    }

    // FIXME: Go ahead and use the serif default.  For now hardcode Times New Roman.
    // We'll need a way to either get to the settings without going through a frame, or we'll
    // need this to be passed in as part of the fallback list.
    FontData* defaultFont = getFontData(font->fontDescription(), AtomicString("Times New Roman"));
    if (defaultFont)
        m_fontList.append(defaultFont);
    return defaultFont;
}

const FontData* FontFallbackList::fontDataForCharacters(const Font*, const UChar* characters, int length) const
{
    // FIXME: Not used yet on Windows.
    return 0;
}

static IntSize hackishExtentForString(HDC dc, FontData* font, const TextRun& run, int tabWidth, int xpos)
{
    SaveDC(dc);

    SelectObject(dc, font->platformData().hfont());

    // Get the text extent of the characters.
    // FIXME: Eventually we will have to go glyph by glyph.  For now we just assume that all
    // glyphs are present in the primary font.
    // FIXME: Support letter-spacing, word-spacing, smallcaps.
    // FIXME: Handle tabs (the tabWidth and xpos parameters)
    // FIXME: Handle RTL.
    SIZE s;
    BOOL result = GetTextExtentPoint32W(dc, (WCHAR*)(run.characters()), run.length(), &s);

    RestoreDC(dc, -1);

    if (!result)
        return IntSize();
    return s;
}

float Font::floatWidth(const TextRun& run, const TextStyle& textStyle) const
{
    FontData* font = m_fontList->primaryFont(fontDescription());
    if (!font)
        return 0;

    HDC dc = GetDC((HWND)0); // FIXME: Need a way to get to the real HDC.
    IntSize runSize = hackishExtentForString(dc, font, run, textStyle.tabWidth(), textStyle.tabWidth());
    ReleaseDC(0, dc);
    return runSize.width();
}

void Font::drawText(GraphicsContext* context, const TextRun& run, const TextStyle& textStyle, const FloatPoint& point) const
{
    FontData* font = m_fontList->primaryFont(fontDescription());
    if (!font)
        return;

    cairo_surface_t* surface = cairo_get_target(context->platformContext());
    HDC dc = cairo_win32_surface_get_dc(surface);

    SaveDC(dc);
    SelectObject(dc, font->platformData().hfont());

    int x = (int)point.x();
    int y = (int)point.y();
    y -= font->ascent();

    SetBkMode(dc, TRANSPARENT);
    const Color& color = context->pen().color();
    SetTextColor(dc, RGB(color.red(), color.green(), color.blue())); // FIXME: Need to support alpha in the text color.
    TextOutW(dc, x, y, (LPCWSTR)(run.characters()), run.length());

    RestoreDC(dc, -1);
    // No need to ReleaseDC the HDC borrowed from cairo
}

FloatRect Font::selectionRectForText(const TextRun& run, const TextStyle& textStyle, const IntPoint& point, int h) const
{
    FontData* font = m_fontList->primaryFont(fontDescription());
    if (!font)
        return IntRect();

    HDC dc = GetDC((HWND)0); // FIXME: Need a way to get to the real HDC.
    IntSize runSize = hackishExtentForString(dc, font, run, textStyle.tabWidth(), textStyle.xPos());
    ReleaseDC(0, dc);
    return FloatRect(point, runSize);
}

int Font::offsetForPosition(const TextRun& run, const TextStyle& style, int x, bool includePartialGlyphs) const
{
    FontData* font = m_fontList->primaryFont(fontDescription());
    if (!font)
        return 0;

    HDC dc = GetDC((HWND)0); // FIXME: Need a way to get to the real HDC.

    SaveDC(dc);
    SelectObject(dc, font->platformData().hfont());

    int* caretPositions = (int*)fastMalloc(run.length() * sizeof(int));
    GCP_RESULTS results;
    memset(&results, 0, sizeof(GCP_RESULTS));
    results.lStructSize = sizeof(GCP_RESULTS);
    results.lpCaretPos = caretPositions;
    results.nGlyphs = run.length();

    GetCharacterPlacement(dc, (LPCTSTR)(run.characters()), run.length(), 0, &results, 0);

    unsigned selectionOffset = 0;
    while (selectionOffset < run.length() && caretPositions[selectionOffset] < x)
        selectionOffset++;

    fastFree(caretPositions);

    RestoreDC(dc, -1);
    ReleaseDC(0, dc);
    return selectionOffset;
}

}
<commit_msg>Fix Win32 build bustage.<commit_after>/*
 * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "Font.h"

#include <cairo-win32.h>
#include "FontData.h"
#include "FontFallbackList.h"
#include "GraphicsContext.h"
#include "IntRect.h"

namespace WebCore {

FontData* getFontData(const FontDescription& fontDescription, const AtomicString& fontFace)
{
    // FIXME: Look this up in a hashtable so that we can cache Cairo fonts.  For now we just grab the
    // font over and over.
    LOGFONTW winfont;
    winfont.lfHeight = -fontDescription.computedPixelSize(); // The negative number is intentional.
    winfont.lfWidth = 0;
    winfont.lfEscapement = 0;
    winfont.lfOrientation = 0;
    winfont.lfUnderline = false;
    winfont.lfStrikeOut = false;
    winfont.lfCharSet = DEFAULT_CHARSET;
    winfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
    const int CLEARTYPE_QUALITY = 5;
    winfont.lfQuality = CLEARTYPE_QUALITY; // FIXME: This is the Windows XP constant to force ClearType on.
    winfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
    winfont.lfItalic = fontDescription.italic();
    winfont.lfWeight = fontDescription.weight() == cBoldWeight ? 700 : 400; // FIXME: Support weights for real.
    int len = min(fontFace.length(), LF_FACESIZE - 1);
    memcpy(winfont.lfFaceName, fontFace.characters(), len * sizeof(WORD));
    winfont.lfFaceName[len] = '\0';

    HFONT font = CreateFontIndirectW(&winfont);

    // Windows will always give us a valid pointer here, even if the face name is non-existent.  We have to double-check
    // and see if the family name was really used.
    HDC dc = GetDC((HWND)0);
    SaveDC(dc);
    SelectObject(dc, font);

    int ascent, descent, xHeight, lineSpacing;

    TEXTMETRIC tm;
    GetTextMetrics(dc, &tm);
    ascent = tm.tmAscent;
    descent = tm.tmDescent;
    xHeight = ascent * 0.56f;  // Best guess for xHeight for non-Truetype fonts.
    lineSpacing = tm.tmExternalLeading + tm.tmHeight;

    OUTLINETEXTMETRIC otm;
    if (GetOutlineTextMetrics(dc, sizeof(otm), &otm) > 0) {
        // This is a TrueType font.  We might be able to get an accurate xHeight.
        GLYPHMETRICS gm;
        MAT2 mat = { 1, 0, 0, 1 }; // The identity matrix.
        DWORD len = GetGlyphOutlineW(dc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
        if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
            xHeight = int(gm.gmptGlyphOrigin.y + 0.5f);
    }

    WCHAR name[LF_FACESIZE];
    unsigned resultLength = GetTextFaceW(dc, LF_FACESIZE, name);
    if (resultLength > 0)
        resultLength--; // ignore the null terminator
    RestoreDC(dc, -1);
    ReleaseDC(0, dc);
    dc = 0;
    if (!equalIgnoringCase(fontFace, String(name, resultLength))) {
        DeleteObject(font);
        return 0;
    }

    // This font face is valid.  Create a FontData now.
    FontData* result = new FontData(font, fontDescription);
    result->setMetrics(ascent, descent, xHeight, lineSpacing);
    return result;
}

FontFallbackList::FontFallbackList()
:m_pitch(UnknownPitch)
{

}

FontFallbackList::~FontFallbackList()
{
    deleteAllValues(m_fontList);
}

void FontFallbackList::determinePitch(const Font* font) const
{
    // FIXME: Implement this.
    m_pitch = VariablePitch;
}

void FontFallbackList::invalidate()
{
    // Delete the Cairo fonts.
    m_pitch = UnknownPitch;
    deleteAllValues(m_fontList);
    m_fontList.clear();
}

const FontData* FontFallbackList::fontDataAt(const Font* font, unsigned index) const
{
    // FIXME: Only returning the primary font on Windows right now.
    if (!m_fontList.isEmpty())
        return m_fontList[0];

    // We want to ensure that the primary Cairo font face exists.
    for (const FontFamily* currFamily = &font->fontDescription().family();
         currFamily;
         currFamily = currFamily->next()) {
        if (!currFamily->familyIsEmpty()) {
            // Attempt to create a FontData.
            FontData* font = getFontData(font->fontDescription(), currFamily->family());
            if (font) {
                m_fontList.append(font);
                return font;
            }
        }
    }

    // FIXME: Go ahead and use the serif default.  For now hardcode Times New Roman.
    // We'll need a way to either get to the settings without going through a frame, or we'll
    // need this to be passed in as part of the fallback list.
    FontData* defaultFont = getFontData(font->fontDescription(), AtomicString("Times New Roman"));
    if (defaultFont)
        m_fontList.append(defaultFont);
    return defaultFont;
}

const FontData* FontFallbackList::fontDataForCharacters(const Font*, const UChar* characters, int length) const
{
    // FIXME: Not used yet on Windows.
    return 0;
}

static IntSize hackishExtentForString(HDC dc, FontData* font, const TextRun& run, int tabWidth, int xpos)
{
    SaveDC(dc);

    SelectObject(dc, font->platformData().hfont());

    // Get the text extent of the characters.
    // FIXME: Eventually we will have to go glyph by glyph.  For now we just assume that all
    // glyphs are present in the primary font.
    // FIXME: Support letter-spacing, word-spacing, smallcaps.
    // FIXME: Handle tabs (the tabWidth and xpos parameters)
    // FIXME: Handle RTL.
    SIZE s;
    BOOL result = GetTextExtentPoint32W(dc, (WCHAR*)(run.characters()), run.length(), &s);

    RestoreDC(dc, -1);

    if (!result)
        return IntSize();
    return s;
}

float Font::floatWidth(const TextRun& run, const TextStyle& textStyle) const
{
    FontData* font = m_fontList->primaryFont();
    if (!font)
        return 0;

    HDC dc = GetDC((HWND)0); // FIXME: Need a way to get to the real HDC.
    IntSize runSize = hackishExtentForString(dc, font, run, textStyle.tabWidth(), textStyle.tabWidth());
    ReleaseDC(0, dc);
    return runSize.width();
}

void Font::drawText(GraphicsContext* context, const TextRun& run, const TextStyle& textStyle, const FloatPoint& point) const
{
    FontData* font = m_fontList->primaryFont();
    if (!font)
        return;

    cairo_surface_t* surface = cairo_get_target(context->platformContext());
    HDC dc = cairo_win32_surface_get_dc(surface);

    SaveDC(dc);
    SelectObject(dc, font->platformData().hfont());

    int x = (int)point.x();
    int y = (int)point.y();
    y -= font->ascent();

    SetBkMode(dc, TRANSPARENT);
    const Color& color = context->pen().color();
    SetTextColor(dc, RGB(color.red(), color.green(), color.blue())); // FIXME: Need to support alpha in the text color.
    TextOutW(dc, x, y, (LPCWSTR)(run.characters()), run.length());

    RestoreDC(dc, -1);
    // No need to ReleaseDC the HDC borrowed from cairo
}

FloatRect Font::selectionRectForText(const TextRun& run, const TextStyle& textStyle, const IntPoint& point, int h) const
{
    FontData* font = m_fontList->primaryFont();
    if (!font)
        return IntRect();

    HDC dc = GetDC((HWND)0); // FIXME: Need a way to get to the real HDC.
    IntSize runSize = hackishExtentForString(dc, font, run, textStyle.tabWidth(), textStyle.xPos());
    ReleaseDC(0, dc);
    return FloatRect(point, runSize);
}

int Font::offsetForPosition(const TextRun& run, const TextStyle& style, int x, bool includePartialGlyphs) const
{
    FontData* font = m_fontList->primaryFont();
    if (!font)
        return 0;

    HDC dc = GetDC((HWND)0); // FIXME: Need a way to get to the real HDC.

    SaveDC(dc);
    SelectObject(dc, font->platformData().hfont());

    int* caretPositions = (int*)fastMalloc(run.length() * sizeof(int));
    GCP_RESULTS results;
    memset(&results, 0, sizeof(GCP_RESULTS));
    results.lStructSize = sizeof(GCP_RESULTS);
    results.lpCaretPos = caretPositions;
    results.nGlyphs = run.length();

    GetCharacterPlacement(dc, (LPCTSTR)(run.characters()), run.length(), 0, &results, 0);

    unsigned selectionOffset = 0;
    while (selectionOffset < run.length() && caretPositions[selectionOffset] < x)
        selectionOffset++;

    fastFree(caretPositions);

    RestoreDC(dc, -1);
    ReleaseDC(0, dc);
    return selectionOffset;
}

}
<|endoftext|>


<commit_before>#include "MetalinkEditor.hpp"

MetalinkEditor::MetalinkEditor()
{
    selection_ = 0;
}

bool MetalinkEditor::is_empty() const
{
    return metalink_.is_empty();
}

int MetalinkEditor::num_files() const
{
    return metalink_.num_files();
}

const wxString& MetalinkEditor::get_filename(int file) const
{
    return metalink_.get_file(file).get_filename();
}

void MetalinkEditor::add_file(const wxString& filename)
{
    add_file(MetalinkFile(filename));
}

void MetalinkEditor::add_file(const MetalinkFile& file)
{
    metalink_.add_file(file);
    selection_ = metalink_.num_files() - 1;
    update();
}

void MetalinkEditor::add_listener(MetalinkEditorListener* listener)
{
    listeners_.push_back(listener);
}

void MetalinkEditor::select(int file)
{
    if(file < 0 || file >= metalink_.num_files()) return;
    selection_ = file;
    update();
}

int MetalinkEditor::get_selection() const
{
    return selection_;
}

void MetalinkEditor::remove_file()
{
    // Remove the file
    metalink_.remove_file(selection_);
    // Fix selection
    if(metalink_.is_empty()) {
        selection_ = 0;
    } else if(selection_ >= metalink_.num_files()) {
        selection_ = metalink_.num_files() - 1;
    }
    // Update
    update();
}

const MetalinkFile& MetalinkEditor::get_file() const
{
    return metalink_.get_file(selection_);
}

const std::vector<MetalinkFile>& MetalinkEditor::get_files() const
{
    return metalink_.get_files();
}

void MetalinkEditor::set_file(const MetalinkFile& file)
{
    metalink_.set_file(selection_, file);
    update();
}

const wxString& MetalinkEditor::get_filename() const
{
    return filename_;
}

const Metalink& MetalinkEditor::get_metalink() const
{
    return metalink_;
}

void MetalinkEditor::set_filename(const wxString& filename)
{
    filename_ = filename;
}

void MetalinkEditor::update()
{
    for(int i = 0; i < listeners_.size(); i++) {
        listeners_.at(i)->update();
    }
}

void MetalinkEditor::save()
{
    if(filename_.empty()) return;
    metalink_.save(filename_);
}

void MetalinkEditor::open(const wxString& filename)
{
    metalink_ = Metalink::load(filename);
    filename_ = filename;
    update();
}

void MetalinkEditor::clear()
{
    metalink_.clear();
    filename_.clear();
    selection_ = 0;
    update();
}
<commit_msg>Fix bug. Current selection could get out of range.<commit_after>#include "MetalinkEditor.hpp"

MetalinkEditor::MetalinkEditor()
{
    selection_ = 0;
}

bool MetalinkEditor::is_empty() const
{
    return metalink_.is_empty();
}

int MetalinkEditor::num_files() const
{
    return metalink_.num_files();
}

const wxString& MetalinkEditor::get_filename(int file) const
{
    return metalink_.get_file(file).get_filename();
}

void MetalinkEditor::add_file(const wxString& filename)
{
    add_file(MetalinkFile(filename));
}

void MetalinkEditor::add_file(const MetalinkFile& file)
{
    metalink_.add_file(file);
    selection_ = metalink_.num_files() - 1;
    update();
}

void MetalinkEditor::add_listener(MetalinkEditorListener* listener)
{
    listeners_.push_back(listener);
}

void MetalinkEditor::select(int file)
{
    if(file < 0 || file >= metalink_.num_files()) return;
    selection_ = file;
    update();
}

int MetalinkEditor::get_selection() const
{
    return selection_;
}

void MetalinkEditor::remove_file()
{
    // Remove the file
    metalink_.remove_file(selection_);
    // Update
    update();
}

const MetalinkFile& MetalinkEditor::get_file() const
{
    return metalink_.get_file(selection_);
}

const std::vector<MetalinkFile>& MetalinkEditor::get_files() const
{
    return metalink_.get_files();
}

void MetalinkEditor::set_file(const MetalinkFile& file)
{
    metalink_.set_file(selection_, file);
    update();
}

const wxString& MetalinkEditor::get_filename() const
{
    return filename_;
}

const Metalink& MetalinkEditor::get_metalink() const
{
    return metalink_;
}

void MetalinkEditor::set_filename(const wxString& filename)
{
    filename_ = filename;
}

void MetalinkEditor::update()
{
    // Fix selection, if needed.
    if(metalink_.is_empty()) {
        selection_ = 0;
    } else if(selection_ >= metalink_.num_files()) {
        selection_ = metalink_.num_files() - 1;
    }
    // Notify listeners
    for(int i = 0; i < listeners_.size(); i++) {
        listeners_.at(i)->update();
    }
}

void MetalinkEditor::save()
{
    if(filename_.empty()) return;
    metalink_.save(filename_);
}

void MetalinkEditor::open(const wxString& filename)
{
    metalink_ = Metalink::load(filename);
    filename_ = filename;
    update();
}

void MetalinkEditor::clear()
{
    metalink_.clear();
    filename_.clear();
    selection_ = 0;
    update();
}
<|endoftext|>