<commit_before>//************************************************************************
/*
 Servo.cpp - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
 Copyright (c) 2009 Michael Margolis.  All right reserved.
 Revision date: 08/18/2011(Michelle Yu)

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
//************************************************************************

/*

 A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method.
 The servos are pulsed in the background using the value most recently written using the write() method

 Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached.
 Timers are seized as needed in groups of 8 servos - 16 servos use two timers, 32 servos will use four.

 The methods are:

 Servo - Class for manipulating servo motors connected to Arduino pins.

 attach(pin )  - Attaches a servo motor to an i/o pin.
 attach(pin, min, max  ) - Attaches to a pin setting min and max values in microseconds
 default min is 544, max is 2400

 write()     - Sets the servo angle in degrees.  (invalid angle that is valid as pulse in microseconds is treated as microseconds)
 writeMicroseconds() - Sets the servo pulse width in microseconds
 read()      - Gets the last written servo pulse width as an angle between 0 and 179.
 readMicroseconds()   - Gets the last written servo pulse width in microseconds.
 attached()  - Returns true if there is a servo attached.
 detach()    - Stops an attached servos from pulsing its i/o pin.

*/
//************************************************************************
//*	Edit History
//************************************************************************
//*	Aug 21,	2011	<GeneApperson> fixed floating point issue by changing to interger math
//*	Sep  1,	2011	<MLS> Cleaning up formatting
//*	Sep  1,	2011	<MLS> Cleaning up formatting
//*	Sep  1,	2011	<MLS> issue #112, changed assigment to compare in finISR
//************************************************************************

#include "Servo.h"

extern "C"{
	#include "int.h"
}

#define usToTicks(_us)	(((_us)*5)/4)					// converts microseconds to tick
#define ticksToUs(_ticks) ((((unsigned)(_ticks))*4)/5)	// converts from ticks back to microseconds

#define TRIM_DURATION		2								// compensation ticks to trim adjust for digitalWrite delays // 12 August 200

static servo_t servos[MAX_SERVOS];						  // static array of servo structures
int	channel[3];											//channel for the current servo

uint8_t ServoCount	=	0;									 // the total number of attached servos

#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4)  // minimum value in uS for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4)  // maximum value in uS for this servo
#define SERVO_INDEX(_timer,_channel)  ((_timer*SERVOS_PER_TIMER) + _channel)	 // macro to access servo index by timer and channel
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((int)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
#define SERVO(_timer,_channel)  (servos[SERVO_INDEX(_timer,_channel)])			// macro to access servo class by timer and channel
/************ static functions common to all instances ***********************/

//************************************************************************
void handle_interrupts(int timer, volatile unsigned int *TMRn, volatile unsigned int *PR)
{

	if ( channel[timer] < 0 )
	{
		*TMRn	=	0; // channel set to -1 indicated that refresh interval completed so reset the timer
	}
	else
	{
		if ( SERVO_INDEX(timer,channel[timer]) < ServoCount && SERVO(timer,channel[timer]).Pin.isActive == true )
		{
			digitalWrite( SERVO(timer,channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated
		}
	}

	channel[timer]++;	// increment to the next channel
	if ( SERVO_INDEX(timer,channel[timer]) < ServoCount && channel[timer] < SERVOS_PER_TIMER)
	{
		*PR	=	*TMRn + SERVO(timer,channel[timer]).ticks;
		if (SERVO(timer,channel[timer]).Pin.isActive == true)	 // check if activated
		{
			digitalWrite( SERVO(timer,channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high
		}
	}
	else
	{
		*TMRn	=	channel[timer] * usToTicks(MAX_PULSE_WIDTH);
		// finished all channels so wait for the refresh period to expire before starting over
		if ( (unsigned)*TMRn < (usToTicks(REFRESH_INTERVAL) + 4) )	// allow a few ticks to ensure the next OCR1A not missed
		{
			*PR	=	(unsigned int)usToTicks(REFRESH_INTERVAL);
		}
		else
		{
			*PR	=	*TMRn + 4;  // at least REFRESH_INTERVAL has elapsed
		}
		channel[timer]	=	-1; // this will get incremented at the end of the refresh period to start again at the first channel
	}
}

//************************************************************************
static void finISR(int timer)
{
	//disable use of the given timer
	if (timer == TIMER3)
	{
		IEC0CLR = 0x1000;// disable T4 interrupt
	}
	if (timer == TIMER4)
	{
		IEC0CLR = 0x10000;// disable T4 interrupt
	}
	if (timer == TIMER5)
	{
		IEC0CLR = 0x100000;// disable T5 interrupt
	}
}

//************************************************************************
static boolean isTimerActive(int timer)
{
	// returns true if any servo is active on this timer
	for (uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++)
	{
		if (SERVO(timer,channel).Pin.isActive == true)
			return true;
	}
	return false;
}

/****************** end of static functions ******************************/

Servo::Servo()
{
	if ( ServoCount < MAX_SERVOS)
	{
		this->servoIndex = ServoCount++;									// assign a servo index to this instance
		servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH);	// store default to neutral position
  	}
	else
		this->servoIndex = INVALID_SERVO ;  // too many servos
}

//************************************************************************
uint8_t Servo::attach(int pin)
{
	return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}

//************************************************************************
uint8_t Servo::attach(int pin, int min, int max)
{
	if (this->servoIndex < MAX_SERVOS )
	{
		if (pin == 0 | pin == 1)
		{
			// disable UART
			U1MODE = 0x0;

		}

		pinMode( pin, OUTPUT) ;								// set servo pin to output
		servos[this->servoIndex].Pin.nbr = pin;
		this->min	=	(MIN_PULSE_WIDTH - min)/4;				//resolution of min/max is 4 uS
		this->max	=	(MAX_PULSE_WIDTH - max)/4;
		// initialize the timer if it has not already been initialized
		int timer = SERVO_INDEX_TO_TIMER(this->servoIndex);
		if (isTimerActive(timer) == false)
		{
			initISR(timer);
		}
		servos[this->servoIndex].Pin.isActive = true;		// this must be set after the check for isTimerActive

		return this->servoIndex ;
	}
}

//************************************************************************
void Servo::detach()
{
	servos[this->servoIndex].Pin.isActive = false;
	int timer = SERVO_INDEX_TO_TIMER(servoIndex);
	if (isTimerActive(timer) == false)
	{
		finISR(timer);
	}
}

//************************************************************************
void Servo::write(int value)
{
	if (value < MIN_PULSE_WIDTH)
	{
		// treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
		if (value < 0) value = 0;
		if (value > 179) value = 179;

		value = map(value, 0, 179, SERVO_MIN(), SERVO_MAX());
	}
	this->writeMicroseconds(value);
}

//************************************************************************
void Servo::writeMicroseconds(int value)
{
	// calculate and store the values for the given channel
	byte channel = this->servoIndex;
	if ( (channel >= 0) && (channel < MAX_SERVOS) )	// ensure channel is valid
	{
		if ( value < SERVO_MIN() )			// ensure pulse width is valid
			value = SERVO_MIN();
		else if ( value > SERVO_MAX() )
			value = SERVO_MAX();

		value = value - TRIM_DURATION;
		value = usToTicks(value);			// convert to ticks after compensating for interrupt overhead

		unsigned int status;
		status = INTDisableInterrupts();
		servos[channel].ticks = value;

		INTRestoreInterrupts(status);
	}
}

//************************************************************************
int Servo::read() // return the value as degrees
{
	return map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
}

//************************************************************************
int Servo::readMicroseconds()
{
	unsigned int pulsewidth;
	if ( this->servoIndex != INVALID_SERVO )
		pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION ;	// 12 aug 2009
	else
		pulsewidth	=	0;

	return pulsewidth;
}

//************************************************************************
bool Servo::attached()
{
	return servos[this->servoIndex].Pin.isActive ;
}
<commit_msg>Issue #114 fixed plib.h issues<commit_after>//************************************************************************
/*
 Servo.cpp - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
 Copyright (c) 2009 Michael Margolis.  All right reserved.
 Revision date: 08/18/2011(Michelle Yu)

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
//************************************************************************

/*

 A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method.
 The servos are pulsed in the background using the value most recently written using the write() method

 Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached.
 Timers are seized as needed in groups of 8 servos - 16 servos use two timers, 32 servos will use four.

 The methods are:

 Servo - Class for manipulating servo motors connected to Arduino pins.

 attach(pin )  - Attaches a servo motor to an i/o pin.
 attach(pin, min, max  ) - Attaches to a pin setting min and max values in microseconds
 default min is 544, max is 2400

 write()		- Sets the servo angle in degrees.  (invalid angle that is valid as pulse in microseconds is treated as microseconds)
 writeMicroseconds() - Sets the servo pulse width in microseconds
 read()			- Gets the last written servo pulse width as an angle between 0 and 179.
 readMicroseconds()   - Gets the last written servo pulse width in microseconds.
 attached()		- Returns true if there is a servo attached.
 detach()		- Stops an attached servos from pulsing its i/o pin.

*/
//************************************************************************
//*	Edit History
//************************************************************************
//*	Aug 21,	2011	<GeneApperson> fixed floating point issue by changing to integer math
//*	Sep  1,	2011	<MLS> Cleaning up formatting
//*	Sep  1,	2011	<MLS> Cleaning up formatting
//*	Sep  1,	2011	<MLS> issue #112, changed assigment to compare in finISR
//* Sep  5, 2011	<GeneApperson> added include of plib.h to fix compile errors
//*						introduced when plib.h was removed from HardwareSerial.h
//************************************************************************

#include <plib.h>
#include "Servo.h"

extern "C"{
	#include "int.h"
}

#define usToTicks(_us)	(((_us)*5)/4)					// converts microseconds to tick
#define ticksToUs(_ticks) ((((unsigned)(_ticks))*4)/5)	// converts from ticks back to microseconds

#define TRIM_DURATION		2							// compensation ticks to trim adjust for digitalWrite delays // 12 August 200

static servo_t servos[MAX_SERVOS];						// static array of servo structures
int	channel[3];											// channel for the current servo

uint8_t ServoCount	=	0;								// the total number of attached servos

#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4)  // minimum value in uS for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4)  // maximum value in uS for this servo
#define SERVO_INDEX(_timer,_channel)  ((_timer*SERVOS_PER_TIMER) + _channel)	// macro to access servo index by timer and channel
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((int)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
#define SERVO(_timer,_channel)  (servos[SERVO_INDEX(_timer,_channel)])			// macro to access servo class by timer and channel
/************ static functions common to all instances ***********************/

//************************************************************************
void handle_interrupts(int timer, volatile unsigned int *TMRn, volatile unsigned int *PR)
{

	if ( channel[timer] < 0 )
	{
		*TMRn	=	0; // channel set to -1 indicated that refresh interval completed so reset the timer
	}
	else
	{
		if ( SERVO_INDEX(timer,channel[timer]) < ServoCount && SERVO(timer,channel[timer]).Pin.isActive == true )
		{
			digitalWrite( SERVO(timer,channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated
		}
	}

	channel[timer]++;	// increment to the next channel
	if ( SERVO_INDEX(timer,channel[timer]) < ServoCount && channel[timer] < SERVOS_PER_TIMER)
	{
		*PR	=	*TMRn + SERVO(timer,channel[timer]).ticks;
		if (SERVO(timer,channel[timer]).Pin.isActive == true)			// check if activated
		{
			digitalWrite( SERVO(timer,channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high
		}
	}
	else
	{
		*TMRn	=	channel[timer] * usToTicks(MAX_PULSE_WIDTH);
		// finished all channels so wait for the refresh period to expire before starting over
		if ( (unsigned)*TMRn < (usToTicks(REFRESH_INTERVAL) + 4) )	// allow a few ticks to ensure the next OCR1A not missed
		{
			*PR	=	(unsigned int)usToTicks(REFRESH_INTERVAL);
		}
		else
		{
			*PR	=	*TMRn + 4;  // at least REFRESH_INTERVAL has elapsed
		}
		channel[timer]	=	-1; // this will get incremented at the end of the refresh period to start again at the first channel
	}
}

//************************************************************************
static void finISR(int timer)
{
	//disable use of the given timer
	if (timer == TIMER3)
	{
		IEC0CLR = 0x1000;		// disable T4 interrupt
	}
	if (timer == TIMER4)
	{
		IEC0CLR = 0x10000;		// disable T4 interrupt
	}
	if (timer == TIMER5)
	{
		IEC0CLR = 0x100000;		// disable T5 interrupt
	}
}

//************************************************************************
static boolean isTimerActive(int timer)
{
	// returns true if any servo is active on this timer
	for (uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++)
	{
		if (SERVO(timer,channel).Pin.isActive == true)
			return true;
	}
	return false;
}

/****************** end of static functions ******************************/

Servo::Servo()
{
	if ( ServoCount < MAX_SERVOS)
	{
		this->servoIndex = ServoCount++;									// assign a servo index to this instance
		servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH);	// store default to neutral position
  	}
	else
		this->servoIndex = INVALID_SERVO ;  // too many servos
}

//************************************************************************
uint8_t Servo::attach(int pin)
{
	return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}

//************************************************************************
uint8_t Servo::attach(int pin, int min, int max)
{
	if (this->servoIndex < MAX_SERVOS )
	{
		if (pin == 0 | pin == 1)
		{
			// disable UART
			U1MODE = 0x0;

		}

		pinMode( pin, OUTPUT) ;								// set servo pin to output
		servos[this->servoIndex].Pin.nbr = pin;
		this->min	=	(MIN_PULSE_WIDTH - min)/4;			// resolution of min/max is 4 uS
		this->max	=	(MAX_PULSE_WIDTH - max)/4;
		// initialize the timer if it has not already been initialized
		int timer = SERVO_INDEX_TO_TIMER(this->servoIndex);
		if (isTimerActive(timer) == false)
		{
			initISR(timer);
		}
		servos[this->servoIndex].Pin.isActive = true;		// this must be set after the check for isTimerActive

		return this->servoIndex;
	}
}

//************************************************************************
void Servo::detach()
{
	servos[this->servoIndex].Pin.isActive = false;
	int timer = SERVO_INDEX_TO_TIMER(servoIndex);
	if (isTimerActive(timer) == false)
	{
		finISR(timer);
	}
}

//************************************************************************
void Servo::write(int value)
{
	if (value < MIN_PULSE_WIDTH)
	{
		// treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
		if (value < 0) value = 0;
		if (value > 179) value = 179;

		value = map(value, 0, 179, SERVO_MIN(), SERVO_MAX());
	}
	this->writeMicroseconds(value);
}

//************************************************************************
void Servo::writeMicroseconds(int value)
{
	// calculate and store the values for the given channel
	byte channel = this->servoIndex;
	if ( (channel >= 0) && (channel < MAX_SERVOS) )	// ensure channel is valid
	{
		if ( value < SERVO_MIN() )			// ensure pulse width is valid
			value = SERVO_MIN();
		else if ( value > SERVO_MAX() )
			value = SERVO_MAX();

		value = value - TRIM_DURATION;
		value = usToTicks(value);			// convert to ticks after compensating for interrupt overhead

		unsigned int status;
		status = INTDisableInterrupts();
		servos[channel].ticks = value;

		INTRestoreInterrupts(status);
	}
}

//************************************************************************
int Servo::read() // return the value as degrees
{
	return map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
}

//************************************************************************
int Servo::readMicroseconds()
{
	unsigned int pulsewidth;
	if ( this->servoIndex != INVALID_SERVO )
		pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION ;	// 12 aug 2009
	else
		pulsewidth	=	0;

	return pulsewidth;
}

//************************************************************************
bool Servo::attached()
{
	return servos[this->servoIndex].Pin.isActive ;
}
<|endoftext|>


<commit_before>// Vertex.hpp

/*
* (C) Copyright 2015 Noah Roth
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/

#pragma once

#include "stdafx.hpp"

namespace RCT3Asset
{

	struct Vector3
	{
		float X;
		float Y;
		float Z;

		Vector3() : X(0.0f), Y(0.0f), Z(0.0f) { }
	};

	struct GameColor
	{
		unsigned int Color1;
		unsigned int Color2;
		unsigned int Color3;;

		GameColor() : Color1(0), Color2(0), Color3(0) { }
	};

	struct BGRAColor
	{
		unsigned char B;
		unsigned char G;
		unsigned char R;
		unsigned char A;

		BGRAColor() : B(0), G(0), R(0), A(0) { }
	};

	// For use with libsquish
	struct U8Color
	{
		squish::u8 R;
		squish::u8 G;
		squish::u8 B;
		squish::u8 A;

		U8Color() : R(0), G(0), B(0), A(0) { }
	};

}<commit_msg>Added Triangle and Matrix4x4 structs<commit_after>// Vertex.hpp

/*
* (C) Copyright 2015 Noah Roth
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/

#pragma once

#include "stdafx.hpp"

namespace RCT3Asset
{

	struct Vector3
	{
		float X;
		float Y;
		float Z;

		Vector3() : X(0.0f), Y(0.0f), Z(0.0f) { }
	};

	struct Triangle
	{
		unsigned int A;
		unsigned int B;
		unsigned int C;
	};

	struct Matrix4x4
	{
		float M[4][4];
	};

	struct GameColor
	{
		unsigned int Color1;
		unsigned int Color2;
		unsigned int Color3;;

		GameColor() : Color1(0), Color2(0), Color3(0) { }
	};

	struct BGRAColor
	{
		unsigned char B;
		unsigned char G;
		unsigned char R;
		unsigned char A;

		BGRAColor() : B(0), G(0), R(0), A(0) { }
	};

	// For use with libsquish
	struct U8Color
	{
		squish::u8 R;
		squish::u8 G;
		squish::u8 B;
		squish::u8 A;

		U8Color() : R(0), G(0), B(0), A(0) { }
	};

}<|endoftext|>


<commit_before>/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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 <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <ctype.h>

#include "port_dso.h"
#include "port_malloc.h"
#include "stack_dump.h"

static char* g_curdir = NULL;
static char* g_cmdline = NULL;

static inline native_segment_t* sd_find_segment(native_module_t* module, void* ip)
{
    for (size_t i = 0; i < module->seg_count; i++)
    {
        if (module->segments[i].base <= ip &&
            (char*)module->segments[i].base + module->segments[i].size > ip)
            return &module->segments[i];
    }

    assert(0);
    return NULL;
}

void sd_get_c_method_info(CFunInfo* info, native_module_t* module, void* ip)
{
    *info->name = 0;
    *info->filename = 0;
    info->line = -1;

    if (!module || !module->filename)
        return;

    POINTER_SIZE_INT offset = (POINTER_SIZE_INT)ip;

    if (strstr(module->filename, PORT_DSO_EXT) != NULL) // Shared object
    { // IP for addr2line should be an offset within shared library
        native_segment_t* seg = sd_find_segment(module, ip);
        offset -= (POINTER_SIZE_INT)seg->base;
    }

    int po[2];
    pipe(po);

    char ip_str[20];
    sprintf(ip_str, "0x%"PI_FMT"x\n", offset);

    if (!fork())
    {
        close(po[0]);
        dup2(po[1], 1);
        execlp("addr2line", "addr2line", "-f", "-s", "-e", module->filename, "-C", ip_str, NULL);
        //fprintf(stderr, "Warning: Cannot run addr2line. No symbolic information will be available\n");
        printf("??\n??:0\n"); // Emulate addr2line output
        exit(-1);
    }
    else
    {
        close(po[1]);
        char buf[sizeof(info->name) + sizeof(info->filename)];
        int status;
        wait(&status);
        int count = read(po[0], buf, sizeof(buf) - 1);
        close(po[0]);

        if (count < 0)
        {
            fprintf(stderr, "read() failed during addr2line execution\n");
            return;
        }

        while (isspace(buf[count-1]))
            count--;

        buf[count] = '\0';
        int i = 0;

        for (; i < count; i++)
        {
            if (buf[i] == '\n')
            { // Function name is limited by '\n'
                buf[i] = '\0';
                strncpy(info->name, buf, sizeof(info->name));
                break;
            }
        }

        if (i == count)
            return;

        char* fn = buf + i + 1;

        for (; i < count && buf[i] != ':'; i++); // File name and line number are separated by ':'

        if (i == count)
            return;

        buf[i] = '\0';
        strncpy(info->filename, fn, sizeof(info->filename));

        info->line = atoi(buf + i + 1); // Line number

        if (info->line == 0)
            info->line = -1;
    }
}

void sd_init_crash_handler()
{
    // Get current directory
    char buf[PATH_MAX + 1];
    char* cwd = getcwd(buf, sizeof(buf));

    if (cwd)
    {
        cwd = (char*)STD_MALLOC(strlen(cwd) + 1);
        g_curdir = cwd;
        if (cwd)
            strcpy(cwd, buf);
    }

    // Get command line
    sprintf(buf, "/proc/%d/cmdline", getpid());
    int file = open(buf, O_RDONLY);

    if (file > 0)
    {
        size_t size = 0;
        char rdbuf[256];
        ssize_t rd;
        do
        {
            rd = read(file, rdbuf, sizeof(rdbuf));
            size += (rd > 0) ? rd : 0;
        } while (rd == sizeof(rdbuf));

        if (size)
        {
            char* cmd = (char*)STD_MALLOC(size + 1);
            g_cmdline = cmd;
            if (cmd)
            {
                cmd[size] = '\0';
                lseek(file, 0, SEEK_SET);
                read(file, cmd, size);
            }
        }
        close(file);
    }
}

void sd_cleanup_crash_handler()
{
    STD_FREE(g_curdir);
    STD_FREE(g_cmdline);
}

void sd_print_cmdline_cwd()
{
    fprintf(stderr, "\nCommand line:\n");
    for (const char* ptr = g_cmdline; *ptr; ptr += strlen(ptr) + 1)
        fprintf(stderr, "%s ", ptr);
    fprintf(stderr, "\n");

    fprintf(stderr, "\nWorking directory:\n%s\n", g_curdir ? g_curdir : "'null'");
}

void sd_print_environment()
{
    fprintf(stderr, "\nEnvironment variables:\n");
    for (char** env = environ; *env; ++env)
        fprintf(stderr, "%s\n", *env);
}
<commit_msg>Make sure environ is defined correctly.<commit_after>/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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 <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <ctype.h>

#include "port_dso.h"
#include "port_malloc.h"
#include "stack_dump.h"

#if defined(MACOSX)
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#else
extern char** environ;
#endif

static char* g_curdir = NULL;
static char* g_cmdline = NULL;

static inline native_segment_t* sd_find_segment(native_module_t* module, void* ip)
{
    for (size_t i = 0; i < module->seg_count; i++)
    {
        if (module->segments[i].base <= ip &&
            (char*)module->segments[i].base + module->segments[i].size > ip)
            return &module->segments[i];
    }

    assert(0);
    return NULL;
}

void sd_get_c_method_info(CFunInfo* info, native_module_t* module, void* ip)
{
    *info->name = 0;
    *info->filename = 0;
    info->line = -1;

    if (!module || !module->filename)
        return;

    POINTER_SIZE_INT offset = (POINTER_SIZE_INT)ip;

    if (strstr(module->filename, PORT_DSO_EXT) != NULL) // Shared object
    { // IP for addr2line should be an offset within shared library
        native_segment_t* seg = sd_find_segment(module, ip);
        offset -= (POINTER_SIZE_INT)seg->base;
    }

    int po[2];
    pipe(po);

    char ip_str[20];
    sprintf(ip_str, "0x%"PI_FMT"x\n", offset);

    if (!fork())
    {
        close(po[0]);
        dup2(po[1], 1);
        execlp("addr2line", "addr2line", "-f", "-s", "-e", module->filename, "-C", ip_str, NULL);
        //fprintf(stderr, "Warning: Cannot run addr2line. No symbolic information will be available\n");
        printf("??\n??:0\n"); // Emulate addr2line output
        exit(-1);
    }
    else
    {
        close(po[1]);
        char buf[sizeof(info->name) + sizeof(info->filename)];
        int status;
        wait(&status);
        int count = read(po[0], buf, sizeof(buf) - 1);
        close(po[0]);

        if (count < 0)
        {
            fprintf(stderr, "read() failed during addr2line execution\n");
            return;
        }

        while (isspace(buf[count-1]))
            count--;

        buf[count] = '\0';
        int i = 0;

        for (; i < count; i++)
        {
            if (buf[i] == '\n')
            { // Function name is limited by '\n'
                buf[i] = '\0';
                strncpy(info->name, buf, sizeof(info->name));
                break;
            }
        }

        if (i == count)
            return;

        char* fn = buf + i + 1;

        for (; i < count && buf[i] != ':'; i++); // File name and line number are separated by ':'

        if (i == count)
            return;

        buf[i] = '\0';
        strncpy(info->filename, fn, sizeof(info->filename));

        info->line = atoi(buf + i + 1); // Line number

        if (info->line == 0)
            info->line = -1;
    }
}

void sd_init_crash_handler()
{
    // Get current directory
    char buf[PATH_MAX + 1];
    char* cwd = getcwd(buf, sizeof(buf));

    if (cwd)
    {
        cwd = (char*)STD_MALLOC(strlen(cwd) + 1);
        g_curdir = cwd;
        if (cwd)
            strcpy(cwd, buf);
    }

    // Get command line
    sprintf(buf, "/proc/%d/cmdline", getpid());
    int file = open(buf, O_RDONLY);

    if (file > 0)
    {
        size_t size = 0;
        char rdbuf[256];
        ssize_t rd;
        do
        {
            rd = read(file, rdbuf, sizeof(rdbuf));
            size += (rd > 0) ? rd : 0;
        } while (rd == sizeof(rdbuf));

        if (size)
        {
            char* cmd = (char*)STD_MALLOC(size + 1);
            g_cmdline = cmd;
            if (cmd)
            {
                cmd[size] = '\0';
                lseek(file, 0, SEEK_SET);
                read(file, cmd, size);
            }
        }
        close(file);
    }
}

void sd_cleanup_crash_handler()
{
    STD_FREE(g_curdir);
    STD_FREE(g_cmdline);
}

void sd_print_cmdline_cwd()
{
    fprintf(stderr, "\nCommand line:\n");
    for (const char* ptr = g_cmdline; *ptr; ptr += strlen(ptr) + 1)
        fprintf(stderr, "%s ", ptr);
    fprintf(stderr, "\n");

    fprintf(stderr, "\nWorking directory:\n%s\n", g_curdir ? g_curdir : "'null'");
}

void sd_print_environment()
{
    fprintf(stderr, "\nEnvironment variables:\n");
    for (char** env = environ; *env; ++env)
        fprintf(stderr, "%s\n", *env);
}
<|endoftext|>


<commit_before>#include "laneDetector.hpp"

#include <ros/ros.h>
#include <stdlib.h>
#include <string>

#include <iostream>
#include <vector>

void exit_with_help(){
	std::cout<<
	"Usage: lane-detector [options]\n"
	"options:\n"
	"-d  : Toggle debug mode\n"
	"	   0 -- Debug mode OFF\n"
	"	   1 -- Debug mode ON\n"
	"	   2 -- Debug mode ON with obstacle detector thresholding toolBox.\n"
	"	   3 -- Debug mode ON with Canny Hough thresholding toolBox.\n"
	"	   4 -- Debug mode ON with Binary thresholding toolBox.\n"
    "      5 -- Set inverse perpective transform matrix. \n"
    "      6 -- Debug mode ON for inverse perspective transform. \n"
    "      7 -- Inverse perspective transform off, so resizing image. \n"
	"-i  : Node Id\n"
	"-s  : Subscriber topic name\n"
	"-t  : Time functions\n"
	"      1: Net FPS\n"
	"      2: Indivisual functions\n"
	;
	exit(1);

}

int main (int argc, char *argv[]){
	std::string node_id="0", subscribe_topic_name="/camera/image";
	int debug_mode = 0 ;
	int time_functions=0;
	// parse options
	for(int i=1;i<argc;i++) {
		if(argv[i][0] != '-') {
			break;
		}

		if (++i>=argc) {
			exit_with_help();
		}
		switch(argv[i-1][1])
		{
			case 'd':
				debug_mode = atoi(argv[i]);
				break;
			case 'i':
				node_id = std::string(argv[i]);
				break;
			case 's':
				subscribe_topic_name = std::string(argv[i]);
				break;
			case 't':
				time_functions = atoi(argv[i]);
				break;
            // case 'n':
            //     do_not_usek
			default:
				fprintf(stderr, "Unknown option: -%c\n", argv[i-1][1]);
				exit_with_help();
		}
	}
	std::string node_name, publisher_topic_name;
	node_name = std::string("interpreter_lane_detector_") + node_id;
	publisher_topic_name = std::string("/interpreter/lane_detector/") + node_id;

	ros::init(argc, argv, node_name.c_str());
	//ros::NodeHandle nh;

	LaneDetector lane_detector(publisher_topic_name, subscribe_topic_name, time_functions,debug_mode);

	ros::spin();
return 0;
}
<commit_msg>Updated help in lane_detector_test<commit_after>#include "laneDetector.hpp"

#include <ros/ros.h>
#include <stdlib.h>
#include <string>

#include <iostream>
#include <vector>

void exit_with_help(){
	std::cout<<
	"Usage: lane-detector [options]\n"
	"options:\n"
	"-d  : Toggle debug mode\n"
	"	   0 -- Debug mode OFF\n"
	"	   1 -- Debug mode ON\n"
	"	   2 -- Debug mode ON with obstacle detector thresholding toolBox.\n"
	"	   3 -- Debug mode ON with Canny Hough thresholding toolBox.\n"
	"	   4 -- Debug mode ON with Binary thresholding toolBox.\n"
    "      5 -- Set inverse perpective transform matrix. \n"
    "      6 -- Debug mode ON for inverse perspective transform. \n"
    "      7 -- Inverse perspective transform off, so resizing image. \n"
    "      9 -- Blah \n"
	"-i  : Node Id\n"
	"-s  : Subscriber topic name\n"
	"-t  : Time functions\n"
	"      1: Net FPS\n"
	"      2: Indivisual functions\n"
	;
	exit(1);

}

int main (int argc, char *argv[]){
	std::string node_id="0", subscribe_topic_name="/camera/image";
	int debug_mode = 0 ;
	int time_functions=0;
	// parse options
	for(int i=1;i<argc;i++) {
		if(argv[i][0] != '-') {
			break;
		}

		if (++i>=argc) {
			exit_with_help();
		}
		switch(argv[i-1][1])
		{
			case 'd':
				debug_mode = atoi(argv[i]);
				break;
			case 'i':
				node_id = std::string(argv[i]);
				break;
			case 's':
				subscribe_topic_name = std::string(argv[i]);
				break;
			case 't':
				time_functions = atoi(argv[i]);
				break;
            // case 'n':
            //     do_not_usek
			default:
				fprintf(stderr, "Unknown option: -%c\n", argv[i-1][1]);
				exit_with_help();
		}
	}
	std::string node_name, publisher_topic_name;
	node_name = std::string("interpreter_lane_detector_") + node_id;
	publisher_topic_name = std::string("/interpreter/lane_detector/") + node_id;

	ros::init(argc, argv, node_name.c_str());
	//ros::NodeHandle nh;

	LaneDetector lane_detector(publisher_topic_name, subscribe_topic_name, time_functions,debug_mode);

	ros::spin();
return 0;
}
<|endoftext|>


<commit_before>/* Learn.cpp
 *
 * Kubo Ryosuke
 */

#ifndef NLEARN

#include "./Learn.h"
#include "core/move/MoveGenerator.h"
#include "core/record/CsaReader.h"
#include "core/util/FileList.h"
#include "core/def.h"
#include "logger/Logger.h"
#include <algorithm>
#include <cmath>
#include <ctime>

#define CONF_KIFU               "kifu"
#define CONF_DEPTH              "depth"
#define CONF_THREADS            "threads"

#define CONFPATH                "learn.conf"

#define SEARCH_WINDOW           256
#define NUMBER_OF_SIBLING_NODES 16
#define MINI_BATCH_COUNT        32

namespace sunfish {

namespace {

  void applySearcherConfig(Searcher& searcher, int depth, int snt) {
    auto searchConfig = searcher.getConfig();
    searchConfig.maxDepth = depth;
    searchConfig.workerSize = snt;
    searchConfig.treeSize = Searcher::standardTreeSize(snt);
    searchConfig.enableLimit = false;
    searchConfig.enableTimeManagement = false;
    searchConfig.ponder = false;
    searchConfig.logging = false;
    searcher.setConfig(searchConfig);
  }

  Board getPvLeaf(const Board& root, const Move& rmove, const Pv& pv) {
    Board board = root;
    board.makeMoveIrr(rmove);
    for (int d = 0; d < pv.size(); d++) {
      Move move = pv.get(d).move;
      if (move.isEmpty() || !board.makeMove(move)) {
        break;
      }
    }
    return board;
  }

  inline float sigmoid(float x) {
    return 1.0f / (1.0f + std::exp(-x));
  }

  inline float gradient(float x) {
    CONSTEXPR float a = 0.025f;
    CONSTEXPR float b = 4.0f;
    float s = sigmoid(a * x);
    return (1.0f * s - s * s) * b;
  }

  inline float norm(float x) {
    CONSTEXPR float n = 0.01f;
    if (x > 0.0f) {
      return -n;
    } else if (x < 0.0f) {
      return n;
    } else {
      return 0.0f;
    }
  }

}

/**
 * コンストラクタ
 */
Learn::Learn() {
  _config.addDef(CONF_KIFU, "");
  _config.addDef(CONF_DEPTH, "3");
  _config.addDef(CONF_THREADS, "1");
}

/**
 * 勾配を計算します.
 *
 */
void Learn::genGradient(int wn, Board board, Move move0) {
  Value val0;
  Pv pv0;
  Move tmpMove;

  bool black = board.isBlack();

  // 合法手生成
  Moves moves;
  MoveGenerator::generate(board, moves);

  if (moves.size() < 2) {
    return;
  }

  // シャッフル
  std::shuffle(moves.begin(), moves.end(), _rgens[wn]);

  // 棋譜の手
  {
    // 探索
    board.makeMove(move0);
    _searchers[wn]->idsearch(board, tmpMove);
    board.unmakeMove(move0);

    // PV と評価値
    const auto& info = _searchers[wn]->getInfo();
    const auto& pv = info.pv;
    val0 = -info.eval;
    pv0.copy(pv);

    // 詰みは除外
    if (val0 <= -Value::Mate || val0 >= Value::Mate) {
      return;
    }
  }

  // 棋譜の手の評価値から window を決定
  Value alpha = -val0 - SEARCH_WINDOW;
  Value beta = -val0 + SEARCH_WINDOW;

  // その他の手
  int nmove = 0;
  float gsum = 0;
  for (auto& move : moves) {
    // 探索
    bool valid = board.makeMove(move);
    if (!valid) { continue; }
    _searchers[wn]->idsearch(board, tmpMove, alpha, beta);
    board.unmakeMove(move);

    // PV と評価値
    const auto& info = _searchers[wn]->getInfo();
    const auto& pv = info.pv;
    Value val = -info.eval;

    // window を外れた場合は除外
    if (val <= alpha || val >= beta) {
      continue;
    }

    // leaf 局面
    Board leaf = getPvLeaf(board, move, pv);

    // 特徴抽出
    float g = gradient(val.int32() - val0.int32());
    g = g * (black ? 1 : -1);
    g = g * (4.0f / (NUMBER_OF_SIBLING_NODES * MINI_BATCH_COUNT));
    g = g * ValuePair::PositionalScale;
    {
      std::lock_guard<std::mutex> lock(_mutex);
      _g.extract<float, true>(leaf, -g);
    }
    gsum += g;

    nmove++;
    if (nmove >= NUMBER_OF_SIBLING_NODES) {
      break;
    }
  }

  {
    std::lock_guard<std::mutex> lock(_mutex);

    // leaf 局面
    Board leaf = getPvLeaf(board, move0, pv0);

    // 特徴抽出
    _g.extract<float, true>(leaf, gsum);
  }
}

/**
 * ジョブを拾います。
 */
void Learn::work(int wn) {
  while (!_shutdown) {
    std::this_thread::yield();

    Job job;

    // dequeue
    {
      std::lock_guard<std::mutex> lock(_mutex);
      if (_jobQueue.empty()) {
        continue;
      }
      job = _jobQueue.front();
      _jobQueue.pop();
      _activeCount++;
    }

    genGradient(wn, job.board, job.move);

    _activeCount--;
  }
}

/**
 * パラメータを更新します。
 */
bool Learn::putJob(Board board, Move move0) {

  {
    std::lock_guard<std::mutex> lock(_mutex);
    _jobQueue.push({ board, move0 });
  }

  if (++_miniBatchCount >= MINI_BATCH_COUNT) {
    // キューが空になるのを待つ
    while (true) {
      {
        std::lock_guard<std::mutex> lock(_mutex);
        if (_jobQueue.empty() && _activeCount == 0) {
          break;
        }
      }
      std::this_thread::yield();
    }

    // 値更新
    float max = 0.0f;
    float magnitude = 0.0f;
    for (int i = 0; i < KPP_ALL; i++) {
      float g = _g._t->kpp[0][i] + norm(_w._t->kpp[0][i]);
      _g._t->kpp[0][i] = 0.0f;
      _w._t->kpp[0][i] += g;
      _u._t->kpp[0][i] += g * _count;
      _eval._t->kpp[0][i] = _w._t->kpp[0][i];
      max = std::max(max, std::abs(_w._t->kpp[0][i]));
      magnitude += std::abs(_w._t->kpp[0][i]);
    }
    for (int i = 0; i < KKP_ALL; i++) {
      float g = _g._t->kkp[0][0][i] + norm(_w._t->kkp[0][0][i]);
      _g._t->kkp[0][0][i] = 0.0f;
      _w._t->kkp[0][0][i] += g;
      _u._t->kkp[0][0][i] += g * _count;
      _eval._t->kkp[0][0][i] = _w._t->kkp[0][0][i];
      max = std::max(max, std::abs(_w._t->kkp[0][0][i]));
      magnitude += std::abs(_w._t->kkp[0][0][i]);
    }

    Loggers::message << "max=" << max << " magnitude=" << magnitude;

    double elapsed = _timer.get();
    Loggers::message << "elapsed: " << elapsed;

    _count++;
    _miniBatchCount = 0;

    // TT を初期化
    for (int wn = 0; wn < _nt; wn++) {
      _searchers[wn]->clearTT();
    }
  }

  return true;
}

/**
 * 棋譜ファイルを読み込んで学習します。
 */
bool Learn::readCsa(size_t count, size_t total, const char* path) {
  Loggers::message << "load(" << count << "/" << total << "): [" << path << "]";

  Record record;
  if (!CsaReader::read(path, record)) {
    Loggers::warning << "Could not read csa file. [" << path << "]";
    return false;
  }

  // 棋譜の先頭へ
  while (record.unmakeMove())
    ;

  while (true) {
    // 次の1手を取得
    Move move = record.getNextMove();
    if (move.isEmpty()) {
      break;
    }

    bool ok = putJob(record.getBoard(), move);

    if (!ok) {
      return false;
    }

    // 1手進める
    if (!record.makeMove()) {
      break;
    }
  }

  return true;
}

/**
 * 機械学習を実行します。
 */
bool Learn::run() {
  // 設定読み込み
  if (!_config.read(CONFPATH)) {
    return false;
  }
  Loggers::message << _config.toString();

  _timer.set();

  // csa ファイルを列挙
  FileList fileList;
  std::string dir = _config.getString(CONF_KIFU);
  fileList.enumerate(dir.c_str(), "csa");

  // 初期化
	_eval.init();
  _count = 1;
  _miniBatchCount = 0;
  _g.init();
  _w.init();
  _u.init();

  // 学習スレッド数
  _nt = _config.getInt(CONF_THREADS);

  // 探索スレッド数
  int snt = _nt >= 4 ? 2 : 1;
  _nt = _nt / snt;

  // Searcher生成
  uint32_t seed = static_cast<uint32_t>(time(NULL));
  _rgens.clear();
  _searchers.clear();
  for (int wn = 0; wn < _nt; wn++) {
    _rgens.emplace_back(seed);
    seed = _rgens.back()();
    _searchers.emplace_back(new Searcher(_eval));
    applySearcherConfig(*_searchers.back().get(), _config.getInt(CONF_DEPTH), snt);
  }

  // ワーカースレッド生成
  _shutdown = false;
  _threads.clear();
  for (int wn = 0; wn < _nt; wn++) {
    _threads.emplace_back(std::bind(std::mem_fn(&Learn::work), this, wn));
  }

  _activeCount = 0;

  // 学習処理の実行
  size_t count = 0;
  for (const auto& filename : fileList) {
    readCsa(++count, fileList.size(), filename.c_str());
  }

  // ワーカースレッド停止
  _shutdown = true;
  for (int wn = 0; wn < _nt; wn++) {
    _threads[wn].join();
  }

  Loggers::message << "publishing..";

  // 平均を取る
  uint16_t max = 0u;
  uint64_t magnitude = 0ull;
  uint32_t nonZero = 0u;
  for (int i = 0; i < KPP_ALL; i++) {
    _eval._t->kpp[0][i] = _w._t->kpp[0][i] - _u._t->kpp[0][i] / _count;
    max = std::max(max, (uint16_t)std::abs(_eval._t->kpp[0][i]));
    magnitude += std::abs(_eval._t->kpp[0][i]);
    nonZero += _eval._t->kpp[0][i] != 0 ? 1 : 0;
  }
  for (int i = 0; i < KKP_ALL; i++) {
    _eval._t->kkp[0][0][i] = _w._t->kkp[0][0][i] - _u._t->kkp[0][0][i] / _count;
    max = std::max(max, (uint16_t)std::abs(_eval._t->kkp[0][0][i]));
    magnitude += std::abs(_eval._t->kkp[0][0][i]);
    nonZero += _eval._t->kkp[0][0][i] != 0 ? 1 : 0;
  }

  Loggers::message << "[final] max=" << max << " magnitude=" << magnitude;
  Loggers::message << "[final] nonZero=" << nonZero << " zero=" << (KPP_ALL + KKP_ALL);

  // 重みベクトルを保存
  _eval.writeFile();

  double elapsed = _timer.get();
  Loggers::message << "[final] elapsed: " << elapsed;

  return true;
}

}

#endif // NLEARN
<commit_msg>Modify<commit_after>/* Learn.cpp
 *
 * Kubo Ryosuke
 */

#ifndef NLEARN

#include "./Learn.h"
#include "core/move/MoveGenerator.h"
#include "core/record/CsaReader.h"
#include "core/util/FileList.h"
#include "core/def.h"
#include "logger/Logger.h"
#include <algorithm>
#include <chrono>
#include <cmath>
#include <ctime>

#define CONF_KIFU               "kifu"
#define CONF_DEPTH              "depth"
#define CONF_THREADS            "threads"

#define CONFPATH                "learn.conf"

#define SEARCH_WINDOW           256
#define NUMBER_OF_SIBLING_NODES 16
#define MINI_BATCH_COUNT        32

namespace sunfish {

namespace {

  void initSearcherConfig(Searcher& searcher, int snt) {
    auto searchConfig = searcher.getConfig();
    searchConfig.workerSize = snt;
    searchConfig.treeSize = Searcher::standardTreeSize(snt);
    searchConfig.enableLimit = false;
    searchConfig.enableTimeManagement = false;
    searchConfig.ponder = false;
    searchConfig.logging = false;
    searcher.setConfig(searchConfig);
  }

  void setSearcherDepth(Searcher& searcher, int depth) {
    auto searchConfig = searcher.getConfig();
    searchConfig.maxDepth = depth;
    searcher.setConfig(searchConfig);
  }

  Board getPvLeaf(const Board& root, const Move& rmove, const Pv& pv) {
    Board board = root;
    board.makeMoveIrr(rmove);
    for (int d = 0; d < pv.size(); d++) {
      Move move = pv.get(d).move;
      if (move.isEmpty() || !board.makeMove(move)) {
        break;
      }
    }
    return board;
  }

  inline float sigmoid(float x) {
    return 1.0f / (1.0f + std::exp(-x));
  }

  inline float gradient(float x) {
    CONSTEXPR float a = 0.025f;
    CONSTEXPR float b = 4.0f;
    float s = sigmoid(a * x);
    return (1.0f * s - s * s) * b;
  }

  inline float norm(float x) {
    CONSTEXPR float n = 0.01f;
    if (x > 0.0f) {
      return -n;
    } else if (x < 0.0f) {
      return n;
    } else {
      return 0.0f;
    }
  }

}

/**
 * コンストラクタ
 */
Learn::Learn() {
  _config.addDef(CONF_KIFU, "");
  _config.addDef(CONF_DEPTH, "3");
  _config.addDef(CONF_THREADS, "1");
}

/**
 * 勾配を計算します.
 *
 */
void Learn::genGradient(int wn, Board board, Move move0) {
  Value val0;
  Pv pv0;
  Move tmpMove;

  bool black = board.isBlack();

  // 合法手生成
  Moves moves;
  MoveGenerator::generate(board, moves);

  if (moves.size() < 2) {
    return;
  }

  // シャッフル
  std::shuffle(moves.begin(), moves.end(), _rgens[wn]);

  // 棋譜の手
  {
    // 探索
    board.makeMove(move0);
    setSearcherDepth(*_searchers[wn], _config.getInt(CONF_DEPTH));
    _searchers[wn]->idsearch(board, tmpMove);
    board.unmakeMove(move0);

    // PV と評価値
    const auto& info = _searchers[wn]->getInfo();
    const auto& pv = info.pv;
    val0 = -info.eval;
    pv0.copy(pv);

    // 詰みは除外
    if (val0 <= -Value::Mate || val0 >= Value::Mate) {
      return;
    }
  }

  // 棋譜の手の評価値から window を決定
  Value alpha = -val0 - SEARCH_WINDOW;
  Value beta = -val0 + SEARCH_WINDOW;

  // その他の手
  int nmove = 0;
  float gsum = 0;
  for (auto& move : moves) {
    // 探索
		CONSTEXPR int reduction = 1;
    bool valid = board.makeMove(move);
    if (!valid) { continue; }
    setSearcherDepth(*_searchers[wn], _config.getInt(CONF_DEPTH) - reduction);
    _searchers[wn]->idsearch(board, tmpMove, alpha, beta);
    board.unmakeMove(move);

    // PV と評価値
    const auto& info = _searchers[wn]->getInfo();
    const auto& pv = info.pv;
    Value val = -info.eval;

    // window を外れた場合は除外
    if (val <= alpha || val >= beta) {
      continue;
    }

    // leaf 局面
    Board leaf = getPvLeaf(board, move, pv);

    // 特徴抽出
    float g = gradient(val.int32() - val0.int32());
    g = g * (black ? 1 : -1);
    g = g * (4.0f / (NUMBER_OF_SIBLING_NODES * MINI_BATCH_COUNT));
    g = g * ValuePair::PositionalScale;
    {
      std::lock_guard<std::mutex> lock(_mutex);
      _g.extract<float, true>(leaf, -g);
    }
    gsum += g;

    nmove++;
    if (nmove >= NUMBER_OF_SIBLING_NODES) {
      break;
    }
  }

  {
    std::lock_guard<std::mutex> lock(_mutex);

    // leaf 局面
    Board leaf = getPvLeaf(board, move0, pv0);

    // 特徴抽出
    _g.extract<float, true>(leaf, gsum);
  }
}

/**
 * ジョブを拾います。
 */
void Learn::work(int wn) {
  while (!_shutdown) {
    std::this_thread::sleep_for(std::chrono::milliseconds(1));

    Job job;

    // dequeue
    {
      std::lock_guard<std::mutex> lock(_mutex);
      if (_jobQueue.empty()) {
        continue;
      }
      job = _jobQueue.front();
      _jobQueue.pop();
      _activeCount++;
    }

    genGradient(wn, job.board, job.move);

    _activeCount--;
  }
}

/**
 * パラメータを更新します。
 */
bool Learn::putJob(Board board, Move move0) {

  {
    std::lock_guard<std::mutex> lock(_mutex);
    _jobQueue.push({ board, move0 });
  }

  if (++_miniBatchCount >= MINI_BATCH_COUNT) {
    // キューが空になるのを待つ
    while (true) {
      {
        std::lock_guard<std::mutex> lock(_mutex);
        if (_jobQueue.empty() && _activeCount == 0) {
          break;
        }
      }
			std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }

    // 値更新
    float max = 0.0f;
    float magnitude = 0.0f;
    for (int i = 0; i < KPP_ALL; i++) {
      float g = _g._t->kpp[0][i] + norm(_w._t->kpp[0][i]);
      _g._t->kpp[0][i] = 0.0f;
      _w._t->kpp[0][i] += g;
      _u._t->kpp[0][i] += g * _count;
      _eval._t->kpp[0][i] = _w._t->kpp[0][i];
      max = std::max(max, std::abs(_w._t->kpp[0][i]));
      magnitude += std::abs(_w._t->kpp[0][i]);
    }
    for (int i = 0; i < KKP_ALL; i++) {
      float g = _g._t->kkp[0][0][i] + norm(_w._t->kkp[0][0][i]);
      _g._t->kkp[0][0][i] = 0.0f;
      _w._t->kkp[0][0][i] += g;
      _u._t->kkp[0][0][i] += g * _count;
      _eval._t->kkp[0][0][i] = _w._t->kkp[0][0][i];
      max = std::max(max, std::abs(_w._t->kkp[0][0][i]));
      magnitude += std::abs(_w._t->kkp[0][0][i]);
    }

    Loggers::message << "max=" << max << " magnitude=" << magnitude;

    double elapsed = _timer.get();
    Loggers::message << "elapsed: " << elapsed;

    _count++;
    _miniBatchCount = 0;

    // TT を初期化
    for (int wn = 0; wn < _nt; wn++) {
      _searchers[wn]->clearTT();
    }
  }

  return true;
}

/**
 * 棋譜ファイルを読み込んで学習します。
 */
bool Learn::readCsa(size_t count, size_t total, const char* path) {
  Loggers::message << "load(" << count << "/" << total << "): [" << path << "]";

  Record record;
  if (!CsaReader::read(path, record)) {
    Loggers::warning << "Could not read csa file. [" << path << "]";
    return false;
  }

  // 棋譜の先頭へ
  while (record.unmakeMove())
    ;

  while (true) {
    // 次の1手を取得
    Move move = record.getNextMove();
    if (move.isEmpty()) {
      break;
    }

    bool ok = putJob(record.getBoard(), move);

    if (!ok) {
      return false;
    }

    // 1手進める
    if (!record.makeMove()) {
      break;
    }
  }

  return true;
}

/**
 * 機械学習を実行します。
 */
bool Learn::run() {
  // 設定読み込み
  if (!_config.read(CONFPATH)) {
    return false;
  }
  Loggers::message << _config.toString();

  _timer.set();

  // csa ファイルを列挙
  FileList fileList;
  std::string dir = _config.getString(CONF_KIFU);
  fileList.enumerate(dir.c_str(), "csa");

  // 初期化
	_eval.init();
  _count = 1;
  _miniBatchCount = 0;
  _g.init();
  _w.init();
  _u.init();

  // 学習スレッド数
  _nt = _config.getInt(CONF_THREADS);

  // 探索スレッド数
  int snt = _nt >= 4 ? 2 : 1;
  _nt = _nt / snt;

  // Searcher生成
  uint32_t seed = static_cast<uint32_t>(time(NULL));
  _rgens.clear();
  _searchers.clear();
  for (int wn = 0; wn < _nt; wn++) {
    _rgens.emplace_back(seed);
    seed = _rgens.back()();
    _searchers.emplace_back(new Searcher(_eval));
    initSearcherConfig(*_searchers.back().get(), snt);
  }

  // ワーカースレッド生成
  _shutdown = false;
  _threads.clear();
  for (int wn = 0; wn < _nt; wn++) {
    _threads.emplace_back(std::bind(std::mem_fn(&Learn::work), this, wn));
  }

  _activeCount = 0;

  // 学習処理の実行
  size_t count = 0;
  for (const auto& filename : fileList) {
    readCsa(++count, fileList.size(), filename.c_str());
  }

  // ワーカースレッド停止
  _shutdown = true;
  for (int wn = 0; wn < _nt; wn++) {
    _threads[wn].join();
  }

  Loggers::message << "publishing..";

  // 平均を取る
  uint16_t max = 0u;
  uint64_t magnitude = 0ull;
  uint32_t nonZero = 0u;
  for (int i = 0; i < KPP_ALL; i++) {
    _eval._t->kpp[0][i] = _w._t->kpp[0][i] - _u._t->kpp[0][i] / _count;
    max = std::max(max, (uint16_t)std::abs(_eval._t->kpp[0][i]));
    magnitude += std::abs(_eval._t->kpp[0][i]);
    nonZero += _eval._t->kpp[0][i] != 0 ? 1 : 0;
  }
  for (int i = 0; i < KKP_ALL; i++) {
    _eval._t->kkp[0][0][i] = _w._t->kkp[0][0][i] - _u._t->kkp[0][0][i] / _count;
    max = std::max(max, (uint16_t)std::abs(_eval._t->kkp[0][0][i]));
    magnitude += std::abs(_eval._t->kkp[0][0][i]);
    nonZero += _eval._t->kkp[0][0][i] != 0 ? 1 : 0;
  }

  Loggers::message << "[final] max=" << max << " magnitude=" << magnitude;
  Loggers::message << "[final] nonZero=" << nonZero << " zero=" << (KPP_ALL + KKP_ALL);

  // 重みベクトルを保存
  _eval.writeFile();

  double elapsed = _timer.get();
  Loggers::message << "[final] elapsed: " << elapsed;

  return true;
}

}

#endif // NLEARN
<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2016 Roman Lebedev

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "CameraMetadataException.h"
#include "CiffParserException.h"
#include "FileIOException.h"
#include "IOException.h"
#include "RawDecoderException.h"
#include "TiffParserException.h"
#include <gmock/gmock.h>

using namespace RawSpeed;

static const std::string msg("my very Smart error Message #1 !");

template <class T> class ExceptionsTest : public testing::Test {};

typedef testing::Types<CameraMetadataException, CiffParserException,
                       FileIOException, IOException, RawDecoderException,
                       TiffParserException>
    Classes;

TYPED_TEST_CASE(ExceptionsTest, Classes);

TYPED_TEST(ExceptionsTest, Constructor) {
  ASSERT_NO_THROW({ TypeParam Exception(msg); });
  ASSERT_NO_THROW({
    TypeParam *Exception = new TypeParam(msg);
    delete Exception;
  });
}

TYPED_TEST(ExceptionsTest, AssignmentConstructor) {
  ASSERT_NO_THROW({
    const TypeParam ExceptionOne(msg);
    TypeParam ExceptionTwo(ExceptionOne);
  });

  ASSERT_NO_THROW({
    const TypeParam *const ExceptionOne = new TypeParam(msg);
    TypeParam *ExceptionTwo = new TypeParam(*ExceptionOne);
    delete ExceptionTwo;
    delete ExceptionOne;
  });

  ASSERT_NO_THROW({
    const TypeParam ExceptionOne(msg);
    TypeParam *ExceptionTwo = new TypeParam(ExceptionOne);
    delete ExceptionTwo;
  });

  ASSERT_NO_THROW({
    const TypeParam *const ExceptionOne = new TypeParam(msg);
    TypeParam ExceptionTwo(*ExceptionOne);
    delete ExceptionOne;
  });
}

TYPED_TEST(ExceptionsTest, Throw) {
  ASSERT_ANY_THROW(throw TypeParam(msg));
  EXPECT_THROW(throw TypeParam(msg), TypeParam);
  EXPECT_THROW(throw TypeParam(msg), std::runtime_error);

  ASSERT_ANY_THROW({
    TypeParam Exception(msg);
    throw Exception;
  });
  EXPECT_THROW(
      {
        TypeParam Exception(msg);
        throw Exception;
      },
      std::runtime_error);
  EXPECT_THROW(
      {
        TypeParam Exception(msg);
        throw Exception;
      },
      TypeParam);

  ASSERT_ANY_THROW({
    TypeParam *Exception = new TypeParam(msg);
    throw * Exception;
    delete Exception;
  });
  EXPECT_THROW(
      {
        TypeParam *Exception = new TypeParam(msg);
        throw * Exception;
        delete Exception;
      },
      std::runtime_error);
  EXPECT_THROW(
      {
        TypeParam *Exception = new TypeParam(msg);
        throw * Exception;
        delete Exception;
      },
      TypeParam);
}

TYPED_TEST(ExceptionsTest, ThrowMessage) {
  try {
    throw TypeParam(msg);
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }

  try {
    TypeParam Exception(msg);
    throw Exception;
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }

  try {
    TypeParam *Exception = new TypeParam(msg);
    throw * Exception;
    delete Exception;
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }

  try {
    const TypeParam ExceptionOne(msg);
    TypeParam ExceptionTwo(ExceptionOne);
    throw ExceptionTwo;
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }

  try {
    const TypeParam *const ExceptionOne = new TypeParam(msg);
    TypeParam *ExceptionTwo = new TypeParam(*ExceptionOne);
    throw * ExceptionTwo;
    delete ExceptionTwo;
    delete ExceptionOne;
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }

  try {
    const TypeParam ExceptionOne(msg);
    TypeParam *ExceptionTwo = new TypeParam(ExceptionOne);
    throw * ExceptionTwo;
    delete ExceptionTwo;
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }

  try {
    const TypeParam *const ExceptionOne = new TypeParam(msg);
    TypeParam ExceptionTwo(*ExceptionOne);
    throw ExceptionTwo;
    delete ExceptionOne;
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}

TEST(CameraMetadataException, ThrowCMETest) {
  ASSERT_ANY_THROW(ThrowCME("%s", msg.c_str()));
  EXPECT_THROW(ThrowCME("%s", msg.c_str()), std::runtime_error);
  EXPECT_THROW(ThrowCME("%s", msg.c_str()), CameraMetadataException);
}

TEST(CameraMetadataException, ThrowCMETestMessage) {
  try {
    ThrowCME("%s", msg.c_str());
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}

TEST(CiffParserException, ThrowCPETest) {
  ASSERT_ANY_THROW(ThrowCPE("%s", msg.c_str()));
  EXPECT_THROW(ThrowCPE("%s", msg.c_str()), std::runtime_error);
  EXPECT_THROW(ThrowCPE("%s", msg.c_str()), CiffParserException);
}

TEST(CiffParserException, ThrowCPETestMessage) {
  try {
    ThrowCPE("%s", msg.c_str());
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}

TEST(FileIOException, ThrowFIETest) {
  ASSERT_ANY_THROW(ThrowFIE("%s", msg.c_str()));
  EXPECT_THROW(ThrowFIE("%s", msg.c_str()), std::runtime_error);
  EXPECT_THROW(ThrowFIE("%s", msg.c_str()), FileIOException);
}

TEST(FileIOException, ThrowFIETestMessage) {
  try {
    ThrowFIE("%s", msg.c_str());
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}

TEST(IOException, ThrowIOETest) {
  ASSERT_ANY_THROW(ThrowIOE("%s", msg.c_str()));
  EXPECT_THROW(ThrowIOE("%s", msg.c_str()), std::runtime_error);
  EXPECT_THROW(ThrowIOE("%s", msg.c_str()), IOException);
}

TEST(IOException, ThrowIOETestMessage) {
  try {
    ThrowIOE("%s", msg.c_str());
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}

TEST(RawDecoderException, ThrowRDETest) {
  ASSERT_ANY_THROW(ThrowRDE("%s", msg.c_str()));
  EXPECT_THROW(ThrowRDE("%s", msg.c_str()), std::runtime_error);
  EXPECT_THROW(ThrowRDE("%s", msg.c_str()), RawDecoderException);
}

TEST(RawDecoderException, ThrowRDETestMessage) {
  try {
    ThrowRDE("%s", msg.c_str());
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}

TEST(TiffParserException, ThrowTPETest) {
  ASSERT_ANY_THROW(ThrowTPE("%s", msg.c_str()));
  EXPECT_THROW(ThrowTPE("%s", msg.c_str()), std::runtime_error);
  EXPECT_THROW(ThrowTPE("%s", msg.c_str()), TiffParserException);
}

TEST(TiffParserException, ThrowTPEMessage) {
  try {
    ThrowTPE("%s", msg.c_str());
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}
<commit_msg>ExceptionsTest: do not leak stuff, use unique_ptr<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2016 Roman Lebedev

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "CameraMetadataException.h"
#include "CiffParserException.h"
#include "FileIOException.h"
#include "IOException.h"
#include "RawDecoderException.h"
#include "TiffParserException.h"
#include <gmock/gmock.h>
#include <memory>

using namespace RawSpeed;

static const std::string msg("my very Smart error Message #1 !");

template <class T> class ExceptionsTest : public testing::Test {};

typedef testing::Types<CameraMetadataException, CiffParserException,
                       FileIOException, IOException, RawDecoderException,
                       TiffParserException>
    Classes;

TYPED_TEST_CASE(ExceptionsTest, Classes);

TYPED_TEST(ExceptionsTest, Constructor) {
  ASSERT_NO_THROW({ TypeParam Exception(msg); });
  ASSERT_NO_THROW({
    TypeParam *Exception = new TypeParam(msg);
    delete Exception;
  });
}

TYPED_TEST(ExceptionsTest, AssignmentConstructor) {
  ASSERT_NO_THROW({
    const TypeParam ExceptionOne(msg);
    TypeParam ExceptionTwo(ExceptionOne);
  });

  ASSERT_NO_THROW({
    const TypeParam *const ExceptionOne = new TypeParam(msg);
    TypeParam *ExceptionTwo = new TypeParam(*ExceptionOne);
    delete ExceptionTwo;
    delete ExceptionOne;
  });

  ASSERT_NO_THROW({
    const TypeParam ExceptionOne(msg);
    TypeParam *ExceptionTwo = new TypeParam(ExceptionOne);
    delete ExceptionTwo;
  });

  ASSERT_NO_THROW({
    const TypeParam *const ExceptionOne = new TypeParam(msg);
    TypeParam ExceptionTwo(*ExceptionOne);
    delete ExceptionOne;
  });
}

TYPED_TEST(ExceptionsTest, Throw) {
  ASSERT_ANY_THROW(throw TypeParam(msg));
  EXPECT_THROW(throw TypeParam(msg), TypeParam);
  EXPECT_THROW(throw TypeParam(msg), std::runtime_error);

  ASSERT_ANY_THROW({
    TypeParam Exception(msg);
    throw Exception;
  });
  EXPECT_THROW(
      {
        TypeParam Exception(msg);
        throw Exception;
      },
      std::runtime_error);
  EXPECT_THROW(
      {
        TypeParam Exception(msg);
        throw Exception;
      },
      TypeParam);

  ASSERT_ANY_THROW({
    std::unique_ptr<TypeParam> Exception(new TypeParam(msg));
    throw * Exception.get();
  });
  EXPECT_THROW(
      {
        std::unique_ptr<TypeParam> Exception(new TypeParam(msg));
        throw * Exception.get();
      },
      std::runtime_error);
  EXPECT_THROW(
      {
        std::unique_ptr<TypeParam> Exception(new TypeParam(msg));
        throw * Exception.get();
      },
      TypeParam);
}

TYPED_TEST(ExceptionsTest, ThrowMessage) {
  try {
    throw TypeParam(msg);
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }

  try {
    TypeParam Exception(msg);
    throw Exception;
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }

  try {
    std::unique_ptr<TypeParam> Exception(new TypeParam(msg));
    throw * Exception.get();
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }

  try {
    const TypeParam ExceptionOne(msg);
    TypeParam ExceptionTwo(ExceptionOne);
    throw ExceptionTwo;
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }

  try {
    std::unique_ptr<TypeParam> ExceptionOne(new TypeParam(msg));
    const std::unique_ptr<const TypeParam> ExceptionTwo(new TypeParam(msg));
    throw * ExceptionTwo.get();
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }

  try {
    const TypeParam ExceptionOne(msg);
    std::unique_ptr<TypeParam> ExceptionTwo(new TypeParam(msg));
    throw * ExceptionTwo.get();
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }

  try {
    const std::unique_ptr<const TypeParam> ExceptionOne(new TypeParam(msg));
    TypeParam ExceptionTwo(*ExceptionOne.get());
    throw ExceptionTwo;
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}

TEST(CameraMetadataException, ThrowCMETest) {
  ASSERT_ANY_THROW(ThrowCME("%s", msg.c_str()));
  EXPECT_THROW(ThrowCME("%s", msg.c_str()), std::runtime_error);
  EXPECT_THROW(ThrowCME("%s", msg.c_str()), CameraMetadataException);
}

TEST(CameraMetadataException, ThrowCMETestMessage) {
  try {
    ThrowCME("%s", msg.c_str());
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}

TEST(CiffParserException, ThrowCPETest) {
  ASSERT_ANY_THROW(ThrowCPE("%s", msg.c_str()));
  EXPECT_THROW(ThrowCPE("%s", msg.c_str()), std::runtime_error);
  EXPECT_THROW(ThrowCPE("%s", msg.c_str()), CiffParserException);
}

TEST(CiffParserException, ThrowCPETestMessage) {
  try {
    ThrowCPE("%s", msg.c_str());
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}

TEST(FileIOException, ThrowFIETest) {
  ASSERT_ANY_THROW(ThrowFIE("%s", msg.c_str()));
  EXPECT_THROW(ThrowFIE("%s", msg.c_str()), std::runtime_error);
  EXPECT_THROW(ThrowFIE("%s", msg.c_str()), FileIOException);
}

TEST(FileIOException, ThrowFIETestMessage) {
  try {
    ThrowFIE("%s", msg.c_str());
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}

TEST(IOException, ThrowIOETest) {
  ASSERT_ANY_THROW(ThrowIOE("%s", msg.c_str()));
  EXPECT_THROW(ThrowIOE("%s", msg.c_str()), std::runtime_error);
  EXPECT_THROW(ThrowIOE("%s", msg.c_str()), IOException);
}

TEST(IOException, ThrowIOETestMessage) {
  try {
    ThrowIOE("%s", msg.c_str());
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}

TEST(RawDecoderException, ThrowRDETest) {
  ASSERT_ANY_THROW(ThrowRDE("%s", msg.c_str()));
  EXPECT_THROW(ThrowRDE("%s", msg.c_str()), std::runtime_error);
  EXPECT_THROW(ThrowRDE("%s", msg.c_str()), RawDecoderException);
}

TEST(RawDecoderException, ThrowRDETestMessage) {
  try {
    ThrowRDE("%s", msg.c_str());
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}

TEST(TiffParserException, ThrowTPETest) {
  ASSERT_ANY_THROW(ThrowTPE("%s", msg.c_str()));
  EXPECT_THROW(ThrowTPE("%s", msg.c_str()), std::runtime_error);
  EXPECT_THROW(ThrowTPE("%s", msg.c_str()), TiffParserException);
}

TEST(TiffParserException, ThrowTPEMessage) {
  try {
    ThrowTPE("%s", msg.c_str());
  } catch (std::exception &ex) {
    ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
    EXPECT_THAT(ex.what(), testing::StrEq(msg));
  }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: macmgr.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2007-07-05 08:48:59 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <cstdarg>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <osl/thread.h>
#include <rtl/strbuf.hxx>

#include <vcl/svapp.hxx>
#include <plugin/impl.hxx>

using namespace rtl;
using namespace std;
using namespace com::sun::star::uno;
using namespace com::sun::star::plugin;

// Unix specific implementation
static bool CheckPlugin( const ByteString& rPath, list< PluginDescription* >& rDescriptions )
{
#if OSL_DEBUG_LEVEL > 1
    fprintf( stderr, "Trying plugin %s ... ", rPath.GetBuffer() );
#endif

    xub_StrLen nPos = rPath.SearchBackward( '/' );
    if( nPos == STRING_NOTFOUND )
    {
#if OSL_DEBUG_LEVEL > 1
        fprintf( stderr, "no absolute path to plugin\n" );
#endif
        return false;
    }

    ByteString aBaseName = rPath.Copy( nPos+1 );
    if( aBaseName.Equals( "libnullplugin.so" ) )
    {
#if OSL_DEBUG_LEVEL > 1
        fprintf( stderr, "don't like %s\n", aBaseName.GetBuffer() );
#endif
        return false;
    }

    struct stat aStat;
    if( stat( rPath.GetBuffer(), &aStat ) || ! S_ISREG( aStat.st_mode ) )
    {
#if OSL_DEBUG_LEVEL > 1
        fprintf( stderr, "%s is not a regular file\n", rPath.GetBuffer() );
#endif
        return false;
    }

    rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();

    ByteString aCommand( "pluginapp.bin \"" );
    aCommand.Append( rPath );
    aCommand.Append( '"' );

    FILE* pResult = popen( aCommand.GetBuffer(), "r" );
    int nDescriptions = 0;
    if( pResult )
    {
        OStringBuffer aMIME;
        char buf[256];
        while( fgets( buf, sizeof( buf ), pResult ) )
        {
            for( int i = 0; i < sizeof(buf) && buf[i]; ++i )
            {
                if( buf[i] == '\n' )
                    buf[i] = ';';
            }
            aMIME.append( buf );
        }
        pclose( pResult );

        if( aMIME.getLength() > 0 )
        {
            OString aLine = aMIME.makeStringAndClear();

            sal_Int32 nIndex = 0;
            while( nIndex != -1 )
            {
                OString aType = aLine.getToken( 0, ';', nIndex );

                sal_Int32 nTypeIndex = 0;
                OString aMimetype   = aType.getToken( 0, ':', nTypeIndex );
                OString aExtLine    = aType.getToken( 0, ':', nTypeIndex );
                if( nTypeIndex < 0 ) // ensure at least three tokens
                    continue;
                OString aDesc       = aType.getToken( 0, ':', nTypeIndex );

                // create extension list string
                sal_Int32 nExtIndex = 0;
                OStringBuffer aExtension;
                while( nExtIndex != -1 )
                {
                    OString aExt = aExtLine.getToken( 0, ',', nExtIndex);
                    if( aExt.indexOf( "*." ) != 0 )
                        aExtension.append( "*." );
                    aExtension.append( aExt );
                    if( nExtIndex != -1 )
                        aExtension.append( ';' );
                }

                PluginDescription* pNew = new PluginDescription;
                // set plugin name (path to library)
                pNew->PluginName    = OStringToOUString( rPath, aEncoding );
                // set mimetype
                pNew->Mimetype  = OStringToOUString( aMimetype, aEncoding );
                // set extension line
                pNew->Extension = OStringToOUString( aExtension.makeStringAndClear(), aEncoding );
                // set description
                pNew->Description= OStringToOUString( aDesc, aEncoding );
                rDescriptions.push_back( pNew );
#if OSL_DEBUG_LEVEL > 1
                fprintf( stderr, "Mimetype: %s\nExtension: %s\n"
                         "Description: %s\n",
                         OUStringToOString( pNew->Mimetype, aEncoding ).getStr(),
                         OUStringToOString( pNew->Extension, aEncoding ).getStr(),
                         OUStringToOString( pNew->Description, aEncoding ).getStr()
                         );
#endif
            }
        }
#if OSL_DEBUG_LEVEL > 1
        else
            fprintf( stderr, "result of \"%s\" contains no mimtype\n",
                     aCommand.GetBuffer() );
#endif
    }
#if OSL_DEBUG_LEVEL > 1
    else
        fprintf( stderr, "command \"%s\" failed\n", aCommand.GetBuffer() );
#endif
    return nDescriptions > 0;
}

Sequence<PluginDescription> XPluginManager_Impl::getPluginDescriptions() throw()
{
    static Sequence<PluginDescription> aDescriptions;
    static BOOL bHavePlugins = FALSE;
    if( ! bHavePlugins )
    {
        rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
        list<PluginDescription*> aPlugins;
        int i;

        // unix: search for plugins in /usr/lib/netscape/plugins,
        //       ~/.netscape/plugins und NPX_PLUGIN_PATH
        // additionally: search in PluginsPath
        static const char* pHome = getenv( "HOME" );
        static const char* pNPXPluginPath = getenv( "NPX_PLUGIN_PATH" );

        ByteString aSearchPath( "/usr/lib/netscape/plugins" );
        if( pHome )
        {
            aSearchPath.Append( ':' );
            aSearchPath.Append( pHome );
            aSearchPath += "/.netscape/plugins";
        }
        if( pNPXPluginPath )
        {
            aSearchPath.Append( ':' );
            aSearchPath += pNPXPluginPath;
        }

        const Sequence< ::rtl::OUString >& rPaths( PluginManager::getAdditionalSearchPaths() );
        for( i = 0; i < rPaths.getLength(); i++ )
        {
            aSearchPath += ":";
            aSearchPath += ByteString( String( rPaths.getConstArray()[i] ), aEncoding );
        }

        long aBuffer[ sizeof( struct dirent ) + _PC_NAME_MAX +1 ];
        int nPaths = aSearchPath.GetTokenCount( ':' );
        for( i = 0; i < nPaths; i++ )
        {
            ByteString aPath( aSearchPath.GetToken( i, ':' ) );
            if( aPath.Len() )
            {
                DIR* pDIR = opendir( aPath.GetBuffer() );
                struct dirent* pDirEnt = NULL;
                while( pDIR && ! readdir_r( pDIR, (struct dirent*)aBuffer, &pDirEnt ) && pDirEnt )
                {
                    char* pBaseName = ((struct dirent*)aBuffer)->d_name;
                    if( pBaseName[0] != '.' ||
                        pBaseName[1] != '.' ||
                        pBaseName[2] != 0 )
                    {
                        ByteString aFileName( aPath );
                        aFileName += "/";
                        aFileName += pBaseName;
                        CheckPlugin( aFileName, aPlugins );
                    }
                }
                if( pDIR )
                    closedir( pDIR );
            }
        }

        // try ~/.mozilla/pluginreg.dat
        ByteString aMozPluginreg( pHome );
        aMozPluginreg.Append( "/.mozilla/pluginreg.dat" );
        FILE* fp = fopen( aMozPluginreg.GetBuffer(), "r" );
        if( fp )
        {
#if OSL_DEBUG_LEVEL > 1
            fprintf( stderr, "parsing %s\n", aMozPluginreg.GetBuffer() );
#endif
            char aLine[1024];
            while( fgets( aLine, sizeof( aLine ), fp ) )
            {
                int nLineLen = strlen( aLine );
                int nDotPos;
                for( nDotPos = nLineLen-1; nDotPos > 0 && aLine[nDotPos] != ':'; nDotPos-- )
                    ;
                if( aLine[0] == '/' && aLine[nDotPos] == ':' && aLine[nDotPos+1] == '$' )
                    CheckPlugin( ByteString( aLine, nDotPos ), aPlugins );
            }
            fclose( fp );
        }

        // create return value
        aDescriptions = Sequence<PluginDescription>( aPlugins.size() );
#if OSL_DEBUG_LEVEL > 1
        fprintf( stderr, "found %d plugins\n", aPlugins.size() );
#endif
        list<PluginDescription*>::iterator iter;
        for( iter = aPlugins.begin(), i=0; iter != aPlugins.end(); ++iter ,i++ )
        {
            aDescriptions.getArray()[ i ] = **iter;
            delete *iter;
        }
        aPlugins.clear();
        bHavePlugins = TRUE;
    }
    return aDescriptions;
}

<commit_msg>INTEGRATION: CWS wae4extensions (1.2.44); FILE MERGED 2007/10/04 15:40:09 ericb 1.2.44.1: #i81612# fix warning (missing type)<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: macmgr.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: ihi $ $Date: 2008-01-14 14:49:36 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <cstdarg>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <osl/thread.h>
#include <rtl/strbuf.hxx>

#include <vcl/svapp.hxx>
#include <plugin/impl.hxx>

using namespace rtl;
using namespace std;
using namespace com::sun::star::uno;
using namespace com::sun::star::plugin;

// Unix specific implementation
static bool CheckPlugin( const ByteString& rPath, list< PluginDescription* >& rDescriptions )
{
#if OSL_DEBUG_LEVEL > 1
    fprintf( stderr, "Trying plugin %s ... ", rPath.GetBuffer() );
#endif

    xub_StrLen nPos = rPath.SearchBackward( '/' );
    if( nPos == STRING_NOTFOUND )
    {
#if OSL_DEBUG_LEVEL > 1
        fprintf( stderr, "no absolute path to plugin\n" );
#endif
        return false;
    }

    ByteString aBaseName = rPath.Copy( nPos+1 );
    if( aBaseName.Equals( "libnullplugin.so" ) )
    {
#if OSL_DEBUG_LEVEL > 1
        fprintf( stderr, "don't like %s\n", aBaseName.GetBuffer() );
#endif
        return false;
    }

    struct stat aStat;
    if( stat( rPath.GetBuffer(), &aStat ) || ! S_ISREG( aStat.st_mode ) )
    {
#if OSL_DEBUG_LEVEL > 1
        fprintf( stderr, "%s is not a regular file\n", rPath.GetBuffer() );
#endif
        return false;
    }

    rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();

    ByteString aCommand( "pluginapp.bin \"" );
    aCommand.Append( rPath );
    aCommand.Append( '"' );

    FILE* pResult = popen( aCommand.GetBuffer(), "r" );
    int nDescriptions = 0;
    if( pResult )
    {
        OStringBuffer aMIME;
        char buf[256];
        while( fgets( buf, sizeof( buf ), pResult ) )
        {
            for( size_t i = 0; i < sizeof(buf) && buf[i]; ++i )
            {
                if( buf[i] == '\n' )
                    buf[i] = ';';
            }
            aMIME.append( buf );
        }
        pclose( pResult );

        if( aMIME.getLength() > 0 )
        {
            OString aLine = aMIME.makeStringAndClear();

            sal_Int32 nIndex = 0;
            while( nIndex != -1 )
            {
                OString aType = aLine.getToken( 0, ';', nIndex );

                sal_Int32 nTypeIndex = 0;
                OString aMimetype   = aType.getToken( 0, ':', nTypeIndex );
                OString aExtLine    = aType.getToken( 0, ':', nTypeIndex );
                if( nTypeIndex < 0 ) // ensure at least three tokens
                    continue;
                OString aDesc       = aType.getToken( 0, ':', nTypeIndex );

                // create extension list string
                sal_Int32 nExtIndex = 0;
                OStringBuffer aExtension;
                while( nExtIndex != -1 )
                {
                    OString aExt = aExtLine.getToken( 0, ',', nExtIndex);
                    if( aExt.indexOf( "*." ) != 0 )
                        aExtension.append( "*." );
                    aExtension.append( aExt );
                    if( nExtIndex != -1 )
                        aExtension.append( ';' );
                }

                PluginDescription* pNew = new PluginDescription;
                // set plugin name (path to library)
                pNew->PluginName    = OStringToOUString( rPath, aEncoding );
                // set mimetype
                pNew->Mimetype  = OStringToOUString( aMimetype, aEncoding );
                // set extension line
                pNew->Extension = OStringToOUString( aExtension.makeStringAndClear(), aEncoding );
                // set description
                pNew->Description= OStringToOUString( aDesc, aEncoding );
                rDescriptions.push_back( pNew );
#if OSL_DEBUG_LEVEL > 1
                fprintf( stderr, "Mimetype: %s\nExtension: %s\n"
                         "Description: %s\n",
                         OUStringToOString( pNew->Mimetype, aEncoding ).getStr(),
                         OUStringToOString( pNew->Extension, aEncoding ).getStr(),
                         OUStringToOString( pNew->Description, aEncoding ).getStr()
                         );
#endif
            }
        }
#if OSL_DEBUG_LEVEL > 1
        else
            fprintf( stderr, "result of \"%s\" contains no mimtype\n",
                     aCommand.GetBuffer() );
#endif
    }
#if OSL_DEBUG_LEVEL > 1
    else
        fprintf( stderr, "command \"%s\" failed\n", aCommand.GetBuffer() );
#endif
    return nDescriptions > 0;
}

Sequence<PluginDescription> XPluginManager_Impl::getPluginDescriptions() throw()
{
    static Sequence<PluginDescription> aDescriptions;
    static BOOL bHavePlugins = FALSE;
    if( ! bHavePlugins )
    {
        rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
        list<PluginDescription*> aPlugins;
        int i;

        // unix: search for plugins in /usr/lib/netscape/plugins,
        //       ~/.netscape/plugins und NPX_PLUGIN_PATH
        // additionally: search in PluginsPath
        static const char* pHome = getenv( "HOME" );
        static const char* pNPXPluginPath = getenv( "NPX_PLUGIN_PATH" );

        ByteString aSearchPath( "/usr/lib/netscape/plugins" );
        if( pHome )
        {
            aSearchPath.Append( ':' );
            aSearchPath.Append( pHome );
            aSearchPath += "/.netscape/plugins";
        }
        if( pNPXPluginPath )
        {
            aSearchPath.Append( ':' );
            aSearchPath += pNPXPluginPath;
        }

        const Sequence< ::rtl::OUString >& rPaths( PluginManager::getAdditionalSearchPaths() );
        for( i = 0; i < rPaths.getLength(); i++ )
        {
            aSearchPath += ":";
            aSearchPath += ByteString( String( rPaths.getConstArray()[i] ), aEncoding );
        }

        long aBuffer[ sizeof( struct dirent ) + _PC_NAME_MAX +1 ];
        int nPaths = aSearchPath.GetTokenCount( ':' );
        for( i = 0; i < nPaths; i++ )
        {
            ByteString aPath( aSearchPath.GetToken( i, ':' ) );
            if( aPath.Len() )
            {
                DIR* pDIR = opendir( aPath.GetBuffer() );
                struct dirent* pDirEnt = NULL;
                while( pDIR && ! readdir_r( pDIR, (struct dirent*)aBuffer, &pDirEnt ) && pDirEnt )
                {
                    char* pBaseName = ((struct dirent*)aBuffer)->d_name;
                    if( pBaseName[0] != '.' ||
                        pBaseName[1] != '.' ||
                        pBaseName[2] != 0 )
                    {
                        ByteString aFileName( aPath );
                        aFileName += "/";
                        aFileName += pBaseName;
                        CheckPlugin( aFileName, aPlugins );
                    }
                }
                if( pDIR )
                    closedir( pDIR );
            }
        }

        // try ~/.mozilla/pluginreg.dat
        ByteString aMozPluginreg( pHome );
        aMozPluginreg.Append( "/.mozilla/pluginreg.dat" );
        FILE* fp = fopen( aMozPluginreg.GetBuffer(), "r" );
        if( fp )
        {
#if OSL_DEBUG_LEVEL > 1
            fprintf( stderr, "parsing %s\n", aMozPluginreg.GetBuffer() );
#endif
            char aLine[1024];
            while( fgets( aLine, sizeof( aLine ), fp ) )
            {
                int nLineLen = strlen( aLine );
                int nDotPos;
                for( nDotPos = nLineLen-1; nDotPos > 0 && aLine[nDotPos] != ':'; nDotPos-- )
                    ;
                if( aLine[0] == '/' && aLine[nDotPos] == ':' && aLine[nDotPos+1] == '$' )
                    CheckPlugin( ByteString( aLine, nDotPos ), aPlugins );
            }
            fclose( fp );
        }

        // create return value
        aDescriptions = Sequence<PluginDescription>( aPlugins.size() );
#if OSL_DEBUG_LEVEL > 1
        fprintf( stderr, "found %d plugins\n", aPlugins.size() );
#endif
        list<PluginDescription*>::iterator iter;
        for( iter = aPlugins.begin(), i=0; iter != aPlugins.end(); ++iter ,i++ )
        {
            aDescriptions.getArray()[ i ] = **iter;
            delete *iter;
        }
        aPlugins.clear();
        bHavePlugins = TRUE;
    }
    return aDescriptions;
}

<|endoftext|>