<commit_before>
#include "llcp.h"
#include "PN532_debug.h"

// LLCP PDU Type Values
#define PDU_SYMM    0x00
#define PDU_PAX     0x01
#define PDU_CONNECT 0x04
#define PDU_DISC    0x05
#define PDU_CC      0x06
#define PDU_DM      0x07
#define PDU_I       0x0c
#define PDU_RR      0x0d

uint8_t LLCP::SYMM_PDU[2] = {0, 0};

inline uint8_t getPType(const uint8_t *buf)
{
    return ((buf[0] & 0x3) << 2) + (buf[1] >> 6);
}

inline uint8_t getSSAP(const uint8_t *buf)
{
    return  buf[1] & 0x3f;
}

inline uint8_t getDSAP(const uint8_t *buf)
{
    return buf[0] >> 2;
}

int8_t LLCP::activate(uint16_t timeout)
{
    return link.activateAsTarget(timeout);
}

int8_t LLCP::waitForConnection(uint16_t timeout)
{
    uint8_t type;

    mode = 1;
    ns = 0;
    nr = 0;

    // Get CONNECT PDU
    DMSG("wait for a CONNECT PDU\n");
    do {
        if (2 > link.read(headerBuf, headerBufLen)) {
            return -1;
        }

        type = getPType(headerBuf);
        if (PDU_CONNECT == type) {
            break;
        } else if (PDU_SYMM == type) {
            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
                return -2;
            }
        } else {
            return -3;
        }

    } while (1);

    // Put CC PDU
    DMSG("put a CC(Connection Complete) PDU to response the CONNECT PDU\n");
    ssap = getDSAP(headerBuf);
    dsap = getSSAP(headerBuf);
    headerBuf[0] = (dsap << 2) + ((PDU_CC >> 2) & 0x3);
    headerBuf[1] = ((PDU_CC & 0x3) << 6) + ssap;
    if (!link.write(headerBuf, 2)) {
        return -2;
    }

    return 1;
}

int8_t LLCP::waitForDisconnection(uint16_t timeout)
{
    uint8_t type;

    // Get DISC PDU
    DMSG("wait for a DISC PDU\n");
    do {
        if (2 > link.read(headerBuf, headerBufLen)) {
            return -1;
        }

        type = getPType(headerBuf);
        if (PDU_DISC == type) {
            break;
        } else if (PDU_SYMM == type) {
            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
                return -2;
            }
        } else {
            return -3;
        }

    } while (1);

    // Put DM PDU
    DMSG("put a DM(Disconnect Mode) PDU to response the DISC PDU\n");
    // ssap = getDSAP(headerBuf);
    // dsap = getSSAP(headerBuf);
    headerBuf[0] = (dsap << 2) + (PDU_DM >> 2);
    headerBuf[1] = ((PDU_DM & 0x3) << 6) + ssap;
    if (!link.write(headerBuf, 2)) {
        return -2;
    }

    return 1;
}

int8_t LLCP::connect(uint16_t timeout)
{
    uint8_t type;

    mode = 0;
    dsap = LLCP_DEFAULT_DSAP;
    ssap = LLCP_DEFAULT_SSAP;
    ns = 0;
    nr = 0;

    // try to get a SYMM PDU
    if (2 > link.read(headerBuf, headerBufLen)) {
        return -1;
    }
    type = getPType(headerBuf);
    if (PDU_SYMM != type) {
        return -1;
    }

    // put a CONNECT PDU
    headerBuf[0] = (LLCP_DEFAULT_DSAP << 2) + (PDU_CONNECT >> 2);
    headerBuf[1] = ((PDU_CONNECT & 0x03) << 6) + LLCP_DEFAULT_SSAP;
    uint8_t body[] = "  urn:nfc:sn:snep";
    body[0] = 0x06;
    body[1] = sizeof(body) - 2 - 1;
    if (!link.write(headerBuf, 2, body, sizeof(body) - 1)) {
        return -2;
    }

    // wait for a CC PDU
    DMSG("wait for a CC PDU\n");
    do {
        if (2 > link.read(headerBuf, headerBufLen)) {
            return -1;
        }

        type = getPType(headerBuf);
        if (PDU_CC == type) {
            break;
        } else if (PDU_SYMM == type) {
            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
                return -2;
            }
        } else {
            return -3;
        }

    } while (1);

    return 1;
}

int8_t LLCP::disconnect(uint16_t timeout)
{
    uint8_t type;

    // try to get a SYMM PDU
    if (2 > link.read(headerBuf, headerBufLen)) {
        return -1;
    }
    type = getPType(headerBuf);
    if (PDU_SYMM != type) {
        return -1;
    }

    // put a DISC PDU
    headerBuf[0] = (LLCP_DEFAULT_DSAP << 2) + (PDU_DISC >> 2);
    headerBuf[1] = ((PDU_DISC & 0x03) << 6) + LLCP_DEFAULT_SSAP;
    if (!link.write(headerBuf, 2)) {
        return -2;
    }

    // wait for a DM PDU
    DMSG("wait for a DM PDU\n");
    do {
        if (2 > link.read(headerBuf, headerBufLen)) {
            return -1;
        }

        type = getPType(headerBuf);
        if (PDU_CC == type) {
            break;
        } else if (PDU_DM == type) {
            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
                return -2;
            }
        } else {
            return -3;
        }

    } while (1);

    return 1;
}

bool LLCP::write(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
{
    uint8_t type;
    uint8_t buf[3];

    if (mode) {
        // Get a SYMM PDU
        if (2 != link.read(buf, sizeof(buf))) {
            return false;
        }
    }

    if (headerBufLen < (hlen + 3)) {
        return false;
    }

    for (int8_t i = hlen - 1; i >= 0; i--) {
        headerBuf[i + 3] = header[i];
    }

    headerBuf[0] = (dsap << 2) + (PDU_I >> 2);
    headerBuf[1] = ((PDU_I & 0x3) << 6) + ssap;
    headerBuf[2] = (ns << 4) + nr;
    if (!link.write(headerBuf, 3 + hlen, body, blen)) {
        return false;
    }

    ns++;

    // Get a RR PDU
    int16_t status;
    do {
        status = link.read(headerBuf, headerBufLen);
        if (2 > status) {
            return false;
        }

        type = getPType(headerBuf);
        if (PDU_RR == type) {
            break;
        } else if (PDU_SYMM == type) {
            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
                return false;
            }
        } else {
            return false;
        }
    } while (1);

    if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
        return false;
    }

    return true;
}

int16_t LLCP::read(uint8_t *buf, uint8_t length)
{
    uint8_t type;
    uint16_t status;

    // Get INFO PDU
    do {
        status = link.read(buf, length);
        if (2 > status) {
            return -1;
        }

        type = getPType(buf);
        if (PDU_I == type) {
            break;
        } else if (PDU_SYMM == type) {
            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
                return -2;
            }
        } else {
            return -3;
        }

    } while (1);

    uint8_t len = status - 3;
    ssap = getDSAP(buf);
    dsap = getSSAP(buf);

    headerBuf[0] = (dsap << 2) + (PDU_RR >> 2);
    headerBuf[1] = ((PDU_RR & 0x3) << 6) + ssap;
    headerBuf[2] = (buf[2] >> 4) + 1;
    if (!link.write(headerBuf, 3)) {
        return -2;
    }

    for (uint8_t i = 0; i < len; i++) {
        buf[i] = buf[i + 3];
    }

    nr++;

    return len;
}
<commit_msg>bugfix<commit_after>
#include "llcp.h"
#include "PN532_debug.h"

// LLCP PDU Type Values
#define PDU_SYMM    0x00
#define PDU_PAX     0x01
#define PDU_CONNECT 0x04
#define PDU_DISC    0x05
#define PDU_CC      0x06
#define PDU_DM      0x07
#define PDU_I       0x0c
#define PDU_RR      0x0d

uint8_t LLCP::SYMM_PDU[2] = {0, 0};

inline uint8_t getPType(const uint8_t *buf)
{
    return ((buf[0] & 0x3) << 2) + (buf[1] >> 6);
}

inline uint8_t getSSAP(const uint8_t *buf)
{
    return  buf[1] & 0x3f;
}

inline uint8_t getDSAP(const uint8_t *buf)
{
    return buf[0] >> 2;
}

int8_t LLCP::activate(uint16_t timeout)
{
    return link.activateAsTarget(timeout);
}

int8_t LLCP::waitForConnection(uint16_t timeout)
{
    uint8_t type;

    mode = 1;
    ns = 0;
    nr = 0;

    // Get CONNECT PDU
    DMSG("wait for a CONNECT PDU\n");
    do {
        if (2 > link.read(headerBuf, headerBufLen)) {
            return -1;
        }

        type = getPType(headerBuf);
        if (PDU_CONNECT == type) {
            break;
        } else if (PDU_SYMM == type) {
            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
                return -2;
            }
        } else {
            return -3;
        }

    } while (1);

    // Put CC PDU
    DMSG("put a CC(Connection Complete) PDU to response the CONNECT PDU\n");
    ssap = getDSAP(headerBuf);
    dsap = getSSAP(headerBuf);
    headerBuf[0] = (dsap << 2) + ((PDU_CC >> 2) & 0x3);
    headerBuf[1] = ((PDU_CC & 0x3) << 6) + ssap;
    if (!link.write(headerBuf, 2)) {
        return -2;
    }

    return 1;
}

int8_t LLCP::waitForDisconnection(uint16_t timeout)
{
    uint8_t type;

    // Get DISC PDU
    DMSG("wait for a DISC PDU\n");
    do {
        if (2 > link.read(headerBuf, headerBufLen)) {
            return -1;
        }

        type = getPType(headerBuf);
        if (PDU_DISC == type) {
            break;
        } else if (PDU_SYMM == type) {
            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
                return -2;
            }
        } else {
            return -3;
        }

    } while (1);

    // Put DM PDU
    DMSG("put a DM(Disconnect Mode) PDU to response the DISC PDU\n");
    // ssap = getDSAP(headerBuf);
    // dsap = getSSAP(headerBuf);
    headerBuf[0] = (dsap << 2) + (PDU_DM >> 2);
    headerBuf[1] = ((PDU_DM & 0x3) << 6) + ssap;
    if (!link.write(headerBuf, 2)) {
        return -2;
    }

    return 1;
}

int8_t LLCP::connect(uint16_t timeout)
{
    uint8_t type;

    mode = 0;
    dsap = LLCP_DEFAULT_DSAP;
    ssap = LLCP_DEFAULT_SSAP;
    ns = 0;
    nr = 0;

    // try to get a SYMM PDU
    if (2 > link.read(headerBuf, headerBufLen)) {
        return -1;
    }
    type = getPType(headerBuf);
    if (PDU_SYMM != type) {
        return -1;
    }

    // put a CONNECT PDU
    headerBuf[0] = (LLCP_DEFAULT_DSAP << 2) + (PDU_CONNECT >> 2);
    headerBuf[1] = ((PDU_CONNECT & 0x03) << 6) + LLCP_DEFAULT_SSAP;
    uint8_t body[] = "  urn:nfc:sn:snep";
    body[0] = 0x06;
    body[1] = sizeof(body) - 2 - 1;
    if (!link.write(headerBuf, 2, body, sizeof(body) - 1)) {
        return -2;
    }

    // wait for a CC PDU
    DMSG("wait for a CC PDU\n");
    do {
        if (2 > link.read(headerBuf, headerBufLen)) {
            return -1;
        }

        type = getPType(headerBuf);
        if (PDU_CC == type) {
            break;
        } else if (PDU_SYMM == type) {
            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
                return -2;
            }
        } else {
            return -3;
        }

    } while (1);

    return 1;
}

int8_t LLCP::disconnect(uint16_t timeout)
{
    uint8_t type;

    // try to get a SYMM PDU
    if (2 > link.read(headerBuf, headerBufLen)) {
        return -1;
    }
    type = getPType(headerBuf);
    if (PDU_SYMM != type) {
        return -1;
    }

    // put a DISC PDU
    headerBuf[0] = (LLCP_DEFAULT_DSAP << 2) + (PDU_DISC >> 2);
    headerBuf[1] = ((PDU_DISC & 0x03) << 6) + LLCP_DEFAULT_SSAP;
    if (!link.write(headerBuf, 2)) {
        return -2;
    }

    // wait for a DM PDU
    DMSG("wait for a DM PDU\n");
    do {
        if (2 > link.read(headerBuf, headerBufLen)) {
            return -1;
        }

        type = getPType(headerBuf);
        if (PDU_CC == type) {
            break;
        } else if (PDU_DM == type) {
            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
                return -2;
            }
        } else {
            return -3;
        }

    } while (1);

    return 1;
}

bool LLCP::write(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
{
    uint8_t type;
    uint8_t buf[3];

    if (mode) {
        // Get a SYMM PDU
        if (2 != link.read(buf, sizeof(buf))) {
            return false;
        }
    }

    if (headerBufLen < (hlen + 3)) {
        return false;
    }

    for (int8_t i = hlen - 1; i >= 0; i--) {
        headerBuf[i + 3] = header[i];
    }

    headerBuf[0] = (dsap << 2) + (PDU_I >> 2);
    headerBuf[1] = ((PDU_I & 0x3) << 6) + ssap;
    headerBuf[2] = (ns << 4) + nr;
    if (!link.write(headerBuf, 3 + hlen, body, blen)) {
        return false;
    }

    ns++;

    // Get a RR PDU
    int16_t status;
    do {
        status = link.read(headerBuf, headerBufLen);
        if (2 > status) {
            return false;
        }

        type = getPType(headerBuf);
        if (PDU_RR == type) {
            break;
        } else if (PDU_SYMM == type) {
            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
                return false;
            }
        } else {
            return false;
        }
    } while (1);

    if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
        return false;
    }

    return true;
}

int16_t LLCP::read(uint8_t *buf, uint8_t length)
{
    uint8_t type;
    int16_t status;

    // Get INFO PDU
    do {
        status = link.read(buf, length);
        if (2 > status) {
            return -1;
        }

        type = getPType(buf);
        if (PDU_I == type) {
            break;
        } else if (PDU_SYMM == type) {
            if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) {
                return -2;
            }
        } else {
            return -3;
        }

    } while (1);

    uint8_t len = status - 3;
    ssap = getDSAP(buf);
    dsap = getSSAP(buf);

    headerBuf[0] = (dsap << 2) + (PDU_RR >> 2);
    headerBuf[1] = ((PDU_RR & 0x3) << 6) + ssap;
    headerBuf[2] = (buf[2] >> 4) + 1;
    if (!link.write(headerBuf, 3)) {
        return -2;
    }

    for (uint8_t i = 0; i < len; i++) {
        buf[i] = buf[i + 3];
    }

    nr++;

    return len;
}
<|endoftext|>


<commit_before>/**
 * Unit Tests for Piezas
**/

#include <gtest/gtest.h>
#include "Piezas.h"

class PiezasTest : public ::testing::Test
{
	protected:
		PiezasTest(){} //constructor runs before each test
		virtual ~PiezasTest(){} //destructor cleans up after tests
		virtual void SetUp(){} //sets up before each test (after constructor)
		virtual void TearDown(){} //clean up after each test, (before destructor)
};

TEST(PiezasTest, sanityCheck)
{
	ASSERT_TRUE(true);
}<commit_msg>added first few tests<commit_after>/**
 * Unit Tests for Piezas
**/

#include <gtest/gtest.h>
#include "Piezas.h"

class PiezasTest : public ::testing::Test
{
	protected:
		PiezasTest(){} //constructor runs before each test
		virtual ~PiezasTest(){} //destructor cleans up after tests
		virtual void SetUp(){} //sets up before each test (after constructor)
		virtual void TearDown(){} //clean up after each test, (before destructor)
};

TEST(PiezasTest, sanityCheck)
{
	ASSERT_TRUE(true);
}

TEST(PiezasTest,CheckPiezas)
{

  bool check1=true;
  Piezas p;
  for(int i=0;i<BOARD_ROWS;i++)
  {
	for(int j=0;j<BOARD_COLS;j++)
	{
         if(p.pieceAt(i,j)!=Blank)
	{
          check1=false;
     	 }
        }
  }
  ASSERT_TRUE(check1);
}

TEST(PiezasTest, CheckReset)
{

  Piezas p;
  p.dropPiece(0);
  p.reset();
  bool check2=true;

  for(int i = 0; i < BOARD_ROWS; i++)
  {
	for(int j = 0; j < BOARD_COLS; j++)
	{
	 if(p.pieceAt(i,j) != Blank)
	 {
		check2=false;
	 }

	}
   }

  ASSERT_TRUE(check2);

}

TEST(PiezasTest, toggleCheckO)
{

  Piezas p;
  bool check3=true;
  if(p.toggle_piece_turn()!=O)
  {

    check3=false;
  }
  ASSERT_TRUE(check3);

}

TEST(PiezasTest, toggleCheckX)
{

  Piezas p;
  bool check4=true;
  p.toggle_piece_turn();
  if(p.toggle_piece_turn()!=X)
  {

    check4=false;

  }

  ASSERT_TRUE(check4);

}

TEST(PiezasTest, InvalidplacePiece)

{

	Piezas p;
	ASSERT_TRUE(p.pieceAt(5,1) == Invalid);

}

TEST(PiezasTest, InvaliddropPiece)

{

  Piezas p;
  bool check5= false;

  if(p.dropPiece(5)==Invalid)
  {
   check5=true;
  }

  ASSERT_TRUE(check5);

}

TEST(PiezasTest, fullColumndropPiece)

{

 Piezas p;

 bool check6=false;

 p.dropPiece(0);

 p.dropPiece(0);

 p.dropPiece(0);

 if(p.dropPiece(0)==Blank)
 {
  check6=true;
 }

 ASSERT_TRUE(check6);

}
<|endoftext|>


<commit_before>#include "Ray.h"

Ray::Ray(sf::Vector2f const& origin, sf::Vector2f const& direction):
    m_origin(origin),
    m_direction(direction),
    m_intersectionFound(false),
    m_minT(0),
    m_obj(nullptr)
{}

void Ray::intersect(INCollisionable & object)
{
    object.collision(this);
}

bool Ray::validIntersectionFound() const
{
    return m_intersectionFound;
}

bool Ray::intersectionIsObject() const
{
    return m_obj != nullptr;
}

Object * Ray::intersectionObject() const
{
    return m_obj;
}

sf::Vector2f Ray::intersection() const
{
    return m_origin + m_direction*m_minT;
}

float Ray::distanceToIntersection() const
{
	return m_minT;
}

void Ray::resetDistance()
{
	m_minT = 0;
	m_intersectionFound = false;
}

sf::Vector2f Ray::getOrigin() const
{
    return m_origin;
}

sf::Vector2f Ray::getDirection() const
{
    return m_direction;
}

void Ray::setIntersection(float t, Object * obj)
{
	if(t >= 0)
	{
		if(!m_intersectionFound)
			m_minT = t;
		else
			m_minT = min(m_minT, t);

		m_intersectionFound = true;
        m_obj = obj;
	}
}

bool Ray::intersectCircle(sf::Vector2f circleCenter, float radius, bool saveIntersection)
{
    float t = -scalar((m_origin - circleCenter), m_direction) / normSquare(m_direction);
    sf::Vector2f point = m_origin + t * m_direction;
    float dist = norm(point - circleCenter);

    bool intersection = dist <= radius;

    if(intersection && saveIntersection)
        setIntersection(t);

	return intersection;
}

bool Ray::intersectSquare(sf::Vector2f pointMin, sf::Vector2f pointMax, bool saveIntersection, Object * obj)
{
    float t1 = (pointMin.x - m_origin.x)/m_direction.x;
    float t2 = (pointMax.x - m_origin.x)/m_direction.x;

    float minX = min(t1, t2);
    float maxX = max(t1, t2);

    t1 = (pointMin.y - m_origin.y)/m_direction.y;
    t2 = (pointMax.y - m_origin.y)/m_direction.y;

    float minY = min(t1, t2);
    float maxY = max(t1, t2);

    float I = max(minX, minY);
    float M = min(maxX, maxY);

	//sf::Vector2f center(pointMin.x + 16, pointMin.y + 16);
	//float distanceIntersection = norm(center - m_origin);

    bool intersection = I <= M;

    if(intersection && saveIntersection)
        setIntersection(I, obj);

    return intersection;
}
<commit_msg>bugfix<commit_after>#include "Ray.h"

#include <iostream>

Ray::Ray(sf::Vector2f const& origin, sf::Vector2f const& direction):
    m_origin(origin),
    m_direction(direction),
    m_intersectionFound(false),
    m_minT(0),
    m_obj(nullptr)
{}

void Ray::intersect(INCollisionable & object)
{
    object.collision(this);
}

bool Ray::validIntersectionFound() const
{
    return m_intersectionFound;
}

bool Ray::intersectionIsObject() const
{
    return m_obj != nullptr;
}

Object * Ray::intersectionObject() const
{
    return m_obj;
}

sf::Vector2f Ray::intersection() const
{
    return m_origin + m_direction*m_minT;
}

float Ray::distanceToIntersection() const
{
	return m_minT;
}

void Ray::resetDistance()
{
	m_minT = 0;
	m_intersectionFound = false;
}

sf::Vector2f Ray::getOrigin() const
{
    return m_origin;
}

sf::Vector2f Ray::getDirection() const
{
    return m_direction;
}

void Ray::setIntersection(float t, Object * obj)
{
	if(t >= 0)
	{
		if(!m_intersectionFound || t < m_minT)
        {
			m_minT = t;
            m_obj = obj;
        }

		m_intersectionFound = true;
	}
}

bool Ray::intersectCircle(sf::Vector2f circleCenter, float radius, bool saveIntersection)
{
    float t = -scalar((m_origin - circleCenter), m_direction) / normSquare(m_direction);
    sf::Vector2f point = m_origin + t * m_direction;
    float dist = norm(point - circleCenter);

    bool intersection = dist <= radius;

    if(intersection && saveIntersection)
        setIntersection(t);

	return intersection;
}

bool Ray::intersectSquare(sf::Vector2f pointMin, sf::Vector2f pointMax, bool saveIntersection, Object * obj)
{
    float t1 = (pointMin.x - m_origin.x)/m_direction.x;
    float t2 = (pointMax.x - m_origin.x)/m_direction.x;

    float minX = min(t1, t2);
    float maxX = max(t1, t2);

    t1 = (pointMin.y - m_origin.y)/m_direction.y;
    t2 = (pointMax.y - m_origin.y)/m_direction.y;

    float minY = min(t1, t2);
    float maxY = max(t1, t2);

    float I = max(minX, minY);
    float M = min(maxX, maxY);

	//sf::Vector2f center(pointMin.x + 16, pointMin.y + 16);
	//float distanceIntersection = norm(center - m_origin);

    bool intersection = I <= M;

    if(intersection && saveIntersection)
        setIntersection(I, obj);

    return intersection;
}
<|endoftext|>


<commit_before>#include <QtGui>
#include "Renderer.h"

const int IdRole = Qt::UserRole;

Renderer::Renderer(QWidget *parent)
    : QWidget(parent)
{
	// Initialize a couple variables
	hasPattern = false;
	hasImage = false;
    antialiased = true;
	paintedOutline = false;
	hasImageChanged = false;
	gridX = 1;
	gridY = 1;
	outline = Qt::black;
	brush = Qt::white;
	background = Qt::white;

	this->setAttribute(Qt::WA_NoBackground);
}

Renderer::~Renderer()
{
	if (hasImage)
	{
		hasImage = false;
	}
}

void Renderer::newImage(int x, int y)
{
	image = QImage(x,y,QImage::Format_RGB32);
	image.fill(brush.rgb());

	gridX = x;
	gridY = y;
	hasImage = true;
	hasImageChanged = true;

	updatePatternSize();
}

bool Renderer::loadImage(QString imagePath)
{
	image.load(imagePath);
	if (!image.isNull())
	{
		gridX = image.width();
		gridY = image.height();;

		hasImage = true;
		hasImageChanged = false;
		updatePatternSize();
		return true;
	}
	return false;
}

bool Renderer::smartResize(int x, int y)
{
	QImage imageSource;
	imageSource = image;
	if (!imageSource.isNull() && hasPattern)
	{
		int pixelXCount = x/pattern.getReadX();
		int pixelYCount = y/pattern.getReadY();
		if (pixelXCount%pattern.getReadX()==0)
			pixelXCount--;
		if (pixelYCount%pattern.getReadY()==0)
			pixelYCount--;

		pixelXCount = pattern.getX()*pixelXCount+pattern.getLargestTileOffsetX();
		pixelYCount = pattern.getY()*pixelYCount+pattern.getLargestTileOffsetY();

		image = QImage(x, y, QImage::Format_RGB32);

		for (int i=0; i<x; i++)
		{
			for (int j=0; j<y; j++)
			{
				int tileX = i%pattern.getReadX();
				int tileY = j%pattern.getReadY();
				float displaceX = pattern.getX()*(i/pattern.getReadX())+pattern.getTileW(tileX, tileY)/2.0+pattern.getTileX(tileX,tileY);
				float displaceY = pattern.getY()*(j/pattern.getReadY())+pattern.getTileH(tileX, tileY)/2.0+pattern.getTileY(tileX,tileY);
				int ii = int(imageSource.width()/float(pixelXCount)*displaceX);
				int jj = int(imageSource.height()/float(pixelYCount)*displaceY);

				if (ii > imageSource.width()-1)
					ii = imageSource.width()-1;
				if (jj > imageSource.height()-1)
					jj = imageSource.height()-1;
				image.setPixel(i, j, imageSource.pixel(ii, jj));
			}
		}

		// Set the remainder of the values
		gridX = image.width();
		gridY = image.height();

		hasImage = true;
		hasImageChanged = true;
		updatePatternSize();
		return true;
	}
	return false;
}

QSize Renderer::smartResizeTip()
{
	if (hasPattern && hasImage)
	{
		return QSize(image.width()*pattern.getReadX()*20/pattern.getX(),image.height()*pattern.getReadY()*20/pattern.getY());
	}
	if (hasImage)
		return QSize(image.size());
	return QSize(1,1);
}

void Renderer::resizeImage(int x, int y)
{
	if (!image.isNull())
	{
		image = image.scaled(x,y);

		gridX = image.width();
		gridY = image.height();

		updatePatternSize();
		hasImageChanged = true;
	}
}

void Renderer::changePalette(QString colorFile)
{
	if (!image.isNull())
	{
		QVector<QRgb> newColorTable;
		QImage paletteImage;
		paletteImage.load(colorFile);
		if (!paletteImage.isNull())
		{
			for (int i=0; i<paletteImage.width(); i++)
			{
				newColorTable.push_back(paletteImage.pixel(i,0));
			}
			image = image.convertToFormat(QImage::Format_Indexed8, newColorTable, Qt::ColorOnly);
			image = image.convertToFormat(QImage::Format_RGB32, newColorTable, Qt::ColorOnly);
			update();
			hasImageChanged = true;
		}
	}
}

void Renderer::setBackgroundColor(QColor color)
{
	background = color;
	paintedOutline = false;
}

void Renderer::setOutlineColor(QColor color)
{
	outline = color;
	paintedOutline = false;
}

void Renderer::setBrushColor(QColor color)
{
	brush = color;
}

void Renderer::rotateTranspose()
{
	rotate(QTransform(0,-1,-1,0,1,1));
}

void Renderer::rotateClockwise()
{
	rotate(QTransform(0,1,-1,0,1,1));
}

void Renderer::rotateCounterClockwise()
{
	rotate(QTransform(0,-1,1,0,1,1));
}

void Renderer::rotate180()
{
	rotate(QTransform(-1,0,0,-1,1,1));
}

void Renderer::rotateFlipX()
{
	rotate(QTransform(-1,0,0,1,1,1));
}

void Renderer::rotateFlipY()
{
	rotate(QTransform(1,0,0,-1,1,1));
}

void Renderer::zoomIn()
{
	zoom*=1.1;
	updatePatternSize();
}

void Renderer::zoomOut()
{
	zoom*=0.9;
	updatePatternSize();
}

void Renderer::zoomNormal()
{
	zoom=1.0;
	updatePatternSize();
}

bool Renderer::setPattern(QDir dir)
{
	//std::cout << "Loaded Pattern: " << dir.dirName().toStdString() << "\n";
	if (pattern.loadPattern(dir))
	{
		zoom = 1;
		hasPattern = true;
		updatePatternSize();
		return true;
	}
	else
		hasPattern = false;
	updatePatternSize();
	return false;
}

QSize Renderer::getMinSize()
{
	updatePatternSize();
	return QSize(sizeX,sizeY);
}

QSize Renderer::getImageSize()
{
	if (!image.isNull())
		return image.size();
	return QSize(1,1);
}

bool Renderer::saveImage(QString saveFileName)
{
	if (hasImage)
	{
		bool wasSaved = image.save(saveFileName);
		if (wasSaved)
			hasImageChanged = false;
		return wasSaved;
	}
	return false;
}

bool Renderer::imageChanged()
{
	if (hasImage && hasPattern)
		return hasImageChanged;
	return false;
}

bool Renderer::hasPatternSelected()
{
	return hasPattern;
}

void Renderer::countColors(QVector<QRgb> *colors, QVector<int> *counts)
{
	if (hasImage)
	{
		colors->clear();
		counts->clear();
		QImage newImage = image.convertToFormat(QImage::Format_Indexed8, Qt::ColorOnly);

		for (int i=0; i<image.width(); i++)
		{
			for (int j=0; j<image.height(); j++)
			{
				int location = colors->indexOf(image.pixel(i,j));
				if (location >= 0)
				{
					counts->replace(location,counts->value(location)+1);
				}
				else
				{
					colors->push_back(image.pixel(i,j));
					counts->push_back(1);
				}
			}
		}
	}
}

void Renderer::paintEvent(QPaintEvent *e)
{
	QPainter painter(this);

	if (hasPattern && hasImage)
	{
		int x=0;
		int y=0;
		int gridCountX = int(gridX/pattern.getReadX());
		int gridXStart = int(e->region().boundingRect().left()/zoom/zoom/pattern.getX())-1;
		int gridXEnd = int(e->region().boundingRect().right()/zoom/zoom/pattern.getX())+2;
		int gridCountY = int(gridY/pattern.getReadY());
		int gridYStart = int(e->region().boundingRect().top()/zoom/zoom/pattern.getY())-1;
		int gridYEnd = int(e->region().boundingRect().bottom()/zoom/zoom/pattern.getY())+2;

		if (gridXStart<0)
			gridXStart=0;
		if (gridYStart<0)
			gridYStart=0;
		if (gridXEnd>gridCountX)
			gridXEnd=gridCountX;
		if (gridYEnd>gridCountY)
			gridYEnd=gridCountY;

		// Paint the outline and background
		painter.setBackgroundMode(Qt::OpaqueMode);
		painter.setBackground(QBrush(background));
		for (int i=gridXStart; i<=gridXEnd+1; i++)
		{
			x=int(pattern.getX()*zoom)*i;
			for (int j=gridYStart; j<=gridYEnd+1; j++)
			{
				y=int(pattern.getY()*zoom)*j;
				painter.save();
				painter.scale(zoom,zoom);
				painter.translate(x,y);
				painter.scale(zoom,zoom);

				painter.setPen(outline);
				painter.drawPixmap(0,0,QBitmap(pattern.getBackground()));

				painter.restore();
			}
		}
		painter.setBackgroundMode(Qt::TransparentMode);

		// Paint the imageGrid
		for (int i=gridXStart; i<=gridXEnd; i++)
		{
			x=int(pattern.getX()*zoom)*i;
			for (int j=gridYStart; j<=gridYEnd; j++)
			{
				y=int(pattern.getY()*zoom)*j;
				painter.save();
				painter.scale(zoom,zoom);
				painter.translate(x,y);
				painter.scale(zoom,zoom);

				// Paint tiles
				for (int tileX=0; tileX < pattern.getReadX(); tileX++)
				{
					for (int tileY=0; tileY < pattern.getReadY(); tileY++)
					{
						int pixelX = i*(pattern.getReadX())+pattern.getTileReadX(tileX, tileY);
						int pixelY = j*(pattern.getReadY())+pattern.getTileReadY(tileX, tileY);
						if (pixelX < gridX && pixelY < gridY)
						{
							painter.setPen(image.pixel(pixelX, pixelY));
							painter.drawPixmap(pattern.getTileX(tileX, tileY),pattern.getTileY(tileX, tileY), QBitmap(pattern.getTile(tileX, tileY)));
						}
					}
				}
				painter.restore();
			}
		}
	}
	painter.end();
}

void Renderer::mousePressEvent(QMouseEvent *e)
{
	if (hasImage && hasPattern)
	{
		// Starting positions to test
		int eX = int(e->x()/zoom/zoom);
		int eY = int(e->y()/zoom/zoom);
		int startX = int(e->x()/zoom/zoom/pattern.getX());
		int startY = int(e->y()/zoom/zoom/pattern.getY());

		// Search 3x3 patterned area
		for (int i=-1; i<2; i++)
		{
			for (int j=-1; j<2; j++)
			{
				int curX = i+startX;
				int curY = j+startY;

				if (curX >= 0 && curX < gridX && curY >= 0 && curY < gridY)
				{
					// Search all subtiles
					for (int tileX=0; tileX<pattern.getReadX(); tileX++)
					{
						for (int tileY=0; tileY<pattern.getReadY(); tileY++)
						{
							QBitmap tile = pattern.getTile(tileX,tileY);
							int xTest = eX-(curX*pattern.getX()+pattern.getTileX(tileX,tileY));
							int yTest = eY-(curY*pattern.getY()+pattern.getTileY(tileX,tileY));
							if (tile.rect().contains(xTest,yTest))
							{
								// Check if clicked pixel is within tile mask
								if (QColor(tile.toImage().pixel(xTest,yTest)).black()>0)
								{
									int pixelX = curX*pattern.getReadX()+pattern.getTileReadX(tileX,tileY);
									int pixelY = curY*pattern.getReadY()+pattern.getTileReadY(tileX,tileY);
									// Make sure clicked image pixel is inside the image
									if (pixelX < gridX && pixelY < gridY)
									{
										image.setPixel(pixelX,pixelY,brush.rgb());
										update();
										hasImageChanged = true;
									}
								}
							}
						}
					}
				}
			}
		}
	}
}

void Renderer::updatePatternSize()
{
	if (hasImage && hasPattern)
	{
		float gridXCount = gridX/pattern.getReadX();
		float gridYCount = gridY/pattern.getReadY();
		if (gridX%pattern.getReadX()==0)
			gridXCount--;
		if (gridY%pattern.getReadY()==0)
			gridYCount--;

		sizeX = int((pattern.getX()*gridXCount+pattern.getLargestTileOffsetX())*zoom*zoom);
		sizeY = int((pattern.getY()*gridYCount+pattern.getLargestTileOffsetY())*zoom*zoom);

		paintedOutline = false;
		update();
	}
	else
	{
		sizeX = 1;
		sizeY = 1;
	}
}

void Renderer::rotate(QTransform matrix)
{
	if (hasImage)
	{
		QImage newImage = image.transformed(matrix);
		image.swap(newImage);

		gridX = image.width();
		gridY = image.height();

		updatePatternSize();
		hasImageChanged = true;
	}
}

<commit_msg>Fixing artifacts created during zooming<commit_after>#include <QtGui>
#include "Renderer.h"

Renderer::Renderer(QWidget *parent)
    : QWidget(parent)
{
	// Initialize a couple variables
	hasPattern = false;
	hasImage = false;
    antialiased = true;
	paintedOutline = false;
	hasImageChanged = false;
	gridX = 1;
	gridY = 1;
	outline = Qt::black;
	brush = Qt::white;
	background = Qt::white;

	this->setAttribute(Qt::WA_NoBackground);
}

Renderer::~Renderer()
{
	if (hasImage)
	{
		hasImage = false;
	}
}

void Renderer::newImage(int x, int y)
{
	image = QImage(x,y,QImage::Format_RGB32);
	image.fill(brush.rgb());

	gridX = x;
	gridY = y;
	hasImage = true;
	hasImageChanged = true;

	updatePatternSize();
}

bool Renderer::loadImage(QString imagePath)
{
	image.load(imagePath);
	if (!image.isNull())
	{
		gridX = image.width();
		gridY = image.height();;

		hasImage = true;
		hasImageChanged = false;
		updatePatternSize();
		return true;
	}
	return false;
}

bool Renderer::smartResize(int x, int y)
{
	QImage imageSource;
	imageSource = image;
	if (!imageSource.isNull() && hasPattern)
	{
		int pixelXCount = x/pattern.getReadX();
		int pixelYCount = y/pattern.getReadY();
		if (pixelXCount%pattern.getReadX()==0)
			pixelXCount--;
		if (pixelYCount%pattern.getReadY()==0)
			pixelYCount--;

		pixelXCount = pattern.getX()*pixelXCount+pattern.getLargestTileOffsetX();
		pixelYCount = pattern.getY()*pixelYCount+pattern.getLargestTileOffsetY();

		image = QImage(x, y, QImage::Format_RGB32);

		for (int i=0; i<x; i++)
		{
			for (int j=0; j<y; j++)
			{
				int tileX = i%pattern.getReadX();
				int tileY = j%pattern.getReadY();
				float displaceX = pattern.getX()*(i/pattern.getReadX())+pattern.getTileW(tileX, tileY)/2.0+pattern.getTileX(tileX,tileY);
				float displaceY = pattern.getY()*(j/pattern.getReadY())+pattern.getTileH(tileX, tileY)/2.0+pattern.getTileY(tileX,tileY);
				int ii = int(imageSource.width()/float(pixelXCount)*displaceX);
				int jj = int(imageSource.height()/float(pixelYCount)*displaceY);

				if (ii > imageSource.width()-1)
					ii = imageSource.width()-1;
				if (jj > imageSource.height()-1)
					jj = imageSource.height()-1;
				image.setPixel(i, j, imageSource.pixel(ii, jj));
			}
		}

		// Set the remainder of the values
		gridX = image.width();
		gridY = image.height();

		hasImage = true;
		hasImageChanged = true;
		updatePatternSize();
		return true;
	}
	return false;
}

QSize Renderer::smartResizeTip()
{
	if (hasPattern && hasImage)
	{
		return QSize(image.width()*pattern.getReadX()*20/pattern.getX(),image.height()*pattern.getReadY()*20/pattern.getY());
	}
	if (hasImage)
		return QSize(image.size());
	return QSize(1,1);
}

void Renderer::resizeImage(int x, int y)
{
	if (!image.isNull())
	{
		image = image.scaled(x,y);

		gridX = image.width();
		gridY = image.height();

		updatePatternSize();
		hasImageChanged = true;
	}
}

void Renderer::changePalette(QString colorFile)
{
	if (!image.isNull())
	{
		QVector<QRgb> newColorTable;
		QImage paletteImage;
		paletteImage.load(colorFile);
		if (!paletteImage.isNull())
		{
			for (int i=0; i<paletteImage.width(); i++)
			{
				newColorTable.push_back(paletteImage.pixel(i,0));
			}
			image = image.convertToFormat(QImage::Format_Indexed8, newColorTable, Qt::ColorOnly);
			image = image.convertToFormat(QImage::Format_RGB32, newColorTable, Qt::ColorOnly);
			update();
			hasImageChanged = true;
		}
	}
}

void Renderer::setBackgroundColor(QColor color)
{
	background = color;
	paintedOutline = false;
}

void Renderer::setOutlineColor(QColor color)
{
	outline = color;
	paintedOutline = false;
}

void Renderer::setBrushColor(QColor color)
{
	brush = color;
}

void Renderer::rotateTranspose()
{
	rotate(QTransform(0,-1,-1,0,1,1));
}

void Renderer::rotateClockwise()
{
	rotate(QTransform(0,1,-1,0,1,1));
}

void Renderer::rotateCounterClockwise()
{
	rotate(QTransform(0,-1,1,0,1,1));
}

void Renderer::rotate180()
{
	rotate(QTransform(-1,0,0,-1,1,1));
}

void Renderer::rotateFlipX()
{
	rotate(QTransform(-1,0,0,1,1,1));
}

void Renderer::rotateFlipY()
{
	rotate(QTransform(1,0,0,-1,1,1));
}

void Renderer::zoomIn()
{
	zoom*=1.1;
	updatePatternSize();
}

void Renderer::zoomOut()
{
	zoom*=0.9;
	updatePatternSize();
}

void Renderer::zoomNormal()
{
	zoom=1.0;
	updatePatternSize();
}

bool Renderer::setPattern(QDir dir)
{
	//std::cout << "Loaded Pattern: " << dir.dirName().toStdString() << "\n";
	if (pattern.loadPattern(dir))
	{
		zoom = 1;
		hasPattern = true;
		updatePatternSize();
		return true;
	}
	else
		hasPattern = false;
	updatePatternSize();
	return false;
}

QSize Renderer::getMinSize()
{
	updatePatternSize();
	return QSize(sizeX,sizeY);
}

QSize Renderer::getImageSize()
{
	if (!image.isNull())
		return image.size();
	return QSize(1,1);
}

bool Renderer::saveImage(QString saveFileName)
{
	if (hasImage)
	{
		bool wasSaved = image.save(saveFileName);
		if (wasSaved)
			hasImageChanged = false;
		return wasSaved;
	}
	return false;
}

bool Renderer::imageChanged()
{
	if (hasImage && hasPattern)
		return hasImageChanged;
	return false;
}

bool Renderer::hasPatternSelected()
{
	return hasPattern;
}

void Renderer::countColors(QVector<QRgb> *colors, QVector<int> *counts)
{
	if (hasImage)
	{
		colors->clear();
		counts->clear();
		QImage newImage = image.convertToFormat(QImage::Format_Indexed8, Qt::ColorOnly);

		for (int i=0; i<image.width(); i++)
		{
			for (int j=0; j<image.height(); j++)
			{
				int location = colors->indexOf(image.pixel(i,j));
				if (location >= 0)
				{
					counts->replace(location,counts->value(location)+1);
				}
				else
				{
					colors->push_back(image.pixel(i,j));
					counts->push_back(1);
				}
			}
		}
	}
}

void Renderer::paintEvent(QPaintEvent *e)
{
	QPainter painter(this);

	if (hasPattern && hasImage)
	{
		int x=0;
		int y=0;
		int gridCountX = int(gridX/pattern.getReadX());
		int gridXStart = int(e->region().boundingRect().left()/zoom/pattern.getX())-1;
		int gridXEnd = int(e->region().boundingRect().right()/zoom/pattern.getX())+2;
		int gridCountY = int(gridY/pattern.getReadY());
		int gridYStart = int(e->region().boundingRect().top()/zoom/pattern.getY())-1;
		int gridYEnd = int(e->region().boundingRect().bottom()/zoom/pattern.getY())+2;

		if (gridXStart<0)
			gridXStart=0;
		if (gridYStart<0)
			gridYStart=0;
		if (gridXEnd>gridCountX)
			gridXEnd=gridCountX;
		if (gridYEnd>gridCountY)
			gridYEnd=gridCountY;

		painter.scale(zoom,zoom);

		// Paint the outline and background
		painter.setBackgroundMode(Qt::OpaqueMode);
		painter.setBackground(QBrush(background));
		painter.setPen(outline);
		painter.drawTiledPixmap(0,0,sizeX/zoom,sizeY/zoom,QBitmap(pattern.getBackground()));
		painter.setBackgroundMode(Qt::TransparentMode);

		// Paint the imageGrid
		for (int i=gridXStart; i<=gridXEnd; i++)
		{
			x=int(pattern.getX())*i;
			for (int j=gridYStart; j<=gridYEnd; j++)
			{
				y=int(pattern.getY())*j;

				// Paint tiles
				painter.save();
				painter.translate(x,y);
				for (int tileX=0; tileX < pattern.getReadX(); tileX++)
				{
					for (int tileY=0; tileY < pattern.getReadY(); tileY++)
					{
						int pixelX = i*(pattern.getReadX())+pattern.getTileReadX(tileX, tileY);
						int pixelY = j*(pattern.getReadY())+pattern.getTileReadY(tileX, tileY);
						if (pixelX < gridX && pixelY < gridY)
						{
							painter.setPen(image.pixel(pixelX, pixelY));
							painter.drawPixmap(pattern.getTileX(tileX, tileY),pattern.getTileY(tileX, tileY), QBitmap(pattern.getTile(tileX, tileY)));
						}
					}
				}
				painter.restore();
			}
		}
	}
	painter.end();
}

void Renderer::mousePressEvent(QMouseEvent *e)
{
	if (hasImage && hasPattern)
	{
		// Starting positions to test
		int eX = int(e->x()/zoom);
		int eY = int(e->y()/zoom);
		int startX = int(e->x()/zoom/pattern.getX());
		int startY = int(e->y()/zoom/pattern.getY());

		// Search 3x3 patterned area
		for (int i=-1; i<2; i++)
		{
			for (int j=-1; j<2; j++)
			{
				int curX = i+startX;
				int curY = j+startY;

				if (curX >= 0 && curX < gridX && curY >= 0 && curY < gridY)
				{
					// Search all subtiles
					for (int tileX=0; tileX<pattern.getReadX(); tileX++)
					{
						for (int tileY=0; tileY<pattern.getReadY(); tileY++)
						{
							QBitmap tile = pattern.getTile(tileX,tileY);
							int xTest = eX-(curX*pattern.getX()+pattern.getTileX(tileX,tileY));
							int yTest = eY-(curY*pattern.getY()+pattern.getTileY(tileX,tileY));
							if (tile.rect().contains(xTest,yTest))
							{
								// Check if clicked pixel is within tile mask
								if (QColor(tile.toImage().pixel(xTest,yTest)).black()>0)
								{
									int pixelX = curX*pattern.getReadX()+pattern.getTileReadX(tileX,tileY);
									int pixelY = curY*pattern.getReadY()+pattern.getTileReadY(tileX,tileY);
									// Make sure clicked image pixel is inside the image
									if (pixelX < gridX && pixelY < gridY)
									{
										image.setPixel(pixelX,pixelY,brush.rgb());
										update();
										hasImageChanged = true;
									}
								}
							}
						}
					}
				}
			}
		}
	}
}

void Renderer::updatePatternSize()
{
	if (hasImage && hasPattern)
	{
		float gridXCount = gridX/pattern.getReadX();
		float gridYCount = gridY/pattern.getReadY();
		if (gridX%pattern.getReadX()==0)
			gridXCount--;
		if (gridY%pattern.getReadY()==0)
			gridYCount--;

		sizeX = int((pattern.getX()*gridXCount+pattern.getLargestTileOffsetX())*zoom);
		sizeY = int((pattern.getY()*gridYCount+pattern.getLargestTileOffsetY())*zoom);

		paintedOutline = false;
		update();
	}
	else
	{
		sizeX = 1;
		sizeY = 1;
	}
}

void Renderer::rotate(QTransform matrix)
{
	if (hasImage)
	{
		QImage newImage = image.transformed(matrix);
		image.swap(newImage);

		gridX = image.width();
		gridY = image.height();

		updatePatternSize();
		hasImageChanged = true;
	}
}

<|endoftext|>


<commit_before>#include "Settings.h"
#include <QDir>
#include <QStandardPaths>
#include "SimpleCrypt.h"
#include "Log.h"
#include "ToolBase.h"
#include "Exceptions.h"
#include "Helper.h"

bool Settings::settingsApplicationUserExists()
{
	QStringList default_paths = QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation);
	if(default_paths.isEmpty()) return false;

	QString filename = default_paths[0] + QDir::separator() + QCoreApplication::applicationName() + "_local.ini";
	if (!QFile::exists(filename)) return false;

	return true;
}

QSettings& Settings::settingsApplicationUser()
{
	static QSettings* settings = 0;
	if(settings==0)
	{
		QStringList default_paths = QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation);
		if(default_paths.isEmpty()) THROW(Exception, "No local application data path was found!");
		QString path = default_paths[0];
		if (!QDir().mkpath(path)) THROW(Exception, "Could not create application data path '" + path + "'!");

		//set log file
		QString filename = path + QDir::separator() + QCoreApplication::applicationName() + "_local.ini";
		settings = new QSettings(filename, QSettings::IniFormat);
	}
	return *settings;
}

const QSettings& Settings::settingsApplication()
{
	static QSettings* settings = 0;
	if(settings==0)
	{
		QString filename = QCoreApplication::applicationDirPath() + QDir::separator() + QCoreApplication::applicationName() + ".ini";
		settings = new QSettings(filename, QSettings::IniFormat);
	}
	return *settings;
}

const QSettings& Settings::settingsGeneral()
{
	static QSettings* settings = 0;
	if(settings==0)
	{
		QString filename = QCoreApplication::applicationDirPath() + QDir::separator() + "settings.ini";
		settings = new QSettings(filename, QSettings::IniFormat);
	}
	return *settings;
}

int Settings::integer(QString key)
{
	return valueWithFallback(key).toInt();
}

void Settings::setInteger(QString key, int value)
{
	settingsApplicationUser().setValue(key, value);
}

QString Settings::string(QString key, bool optional)
{
	if (optional && !contains(key)) return "";

	QString value = valueWithFallback(key).toString();

	//decrypt if encrypted
	QString crypt_prefix = "encrypted:";
	if (value.startsWith(crypt_prefix))
	{
		//remove prefix
		value = value.mid(crypt_prefix.count()).trimmed();

		//decrypt
		qulonglong crypt_key = ToolBase::encryptionKey("setting entry '" + key + "'");
		value = SimpleCrypt(crypt_key).decryptToString(value);
	}

	return value;
}

void Settings::setString(QString key, QString value)
{
	settingsApplicationUser().setValue(key, value);
}

QStringList Settings::stringList(QString key, bool optional)
{
	if (optional && !contains(key)) return QStringList();

	return valueWithFallback(key).toStringList();
}

void Settings::setStringList(QString key, QStringList value)
{
	settingsApplicationUser().setValue(key, value);
}

bool Settings::boolean(QString key, bool optional)
{
	if (optional && !contains(key)) return false;

	return valueWithFallback(key).toBool();
}

void Settings::setBoolean(QString key, bool value)
{
	settingsApplicationUser().setValue(key, value);
}

QMap<QString, QVariant> Settings::map(QString key, bool optional)
{
	if (optional && !contains(key)) QMap<QString, QVariant>();

	return valueWithFallback(key).toMap();
}

void Settings::setMap(QString key, QMap<QString, QVariant> value)
{
	settingsApplicationUser().setValue(key, value);
}

QString Settings::path(QString key, bool optional)
{
	if (optional && !contains(key)) return "";

	QString path = string(key).trimmed();

	//convert separators
	path = Helper::canonicalPath(path);

	//add separator at the end if missing from path
	if (QFile::exists(path) && QFileInfo(path).isDir() && !path.endsWith(QDir::separator()))
	{
		path += QDir::separator();
	}

	return path;
}

void Settings::setPath(QString key, QString path)
{
	QFileInfo info(path);
	if (info.isFile())
	{
		path = info.absolutePath();
	}

	if (QDir(path).exists())
	{
		setString(key, Helper::canonicalPath(path));
	}
}

void Settings::clear()
{
	settingsApplicationUser().clear();
}

void Settings::remove(QString key)
{
	settingsApplicationUser().remove(key);
}

QStringList Settings::allKeys()
{
	QStringList output;

	if (settingsApplicationUserExists())
	{
		output << settingsApplicationUser().allKeys();
	}
	output << settingsApplication().allKeys();
	output << settingsGeneral().allKeys();

	std::sort(output.begin(), output.end());
	output.removeDuplicates();

	return output;
}

bool Settings::contains(QString key)
{
	//check if key exists
	bool key_exists = (settingsApplicationUserExists() && settingsApplicationUser().contains(key)) || settingsApplication().contains(key) || settingsGeneral().contains(key);
	if (!key_exists) return false;

	//if the key exists, check that the value is not empty
	return valueWithFallback(key).toString().trimmed()!="";
}

QVariant Settings::valueWithFallback(QString key)
{
	if (settingsApplicationUserExists() && settingsApplicationUser().contains(key))
	{
		return settingsApplicationUser().value(key);
	}

	if (settingsApplication().contains(key))
	{
		return settingsApplication().value(key);
	}

	if (settingsGeneral().contains(key))
	{
		return settingsGeneral().value(key);
	}

	THROW(ProgrammingException, "Requested key '" + key + "' not found in settings!");
}
<commit_msg>Fixed two bugs in Settings class: - QSettings sometimes cached changes in RAM: fixed by forced sync after writing - contains method did not work correctly for string list and map<commit_after>#include "Settings.h"
#include <QDir>
#include <QStandardPaths>
#include "SimpleCrypt.h"
#include "Log.h"
#include "ToolBase.h"
#include "Exceptions.h"
#include "Helper.h"

bool Settings::settingsApplicationUserExists()
{
	QStringList default_paths = QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation);
	if(default_paths.isEmpty()) return false;

	QString filename = default_paths[0] + QDir::separator() + QCoreApplication::applicationName() + "_local.ini";
	if (!QFile::exists(filename)) return false;

	return true;
}

QSettings& Settings::settingsApplicationUser()
{
	static QSharedPointer<QSettings> settings;
	if(settings.isNull())
	{
		QStringList default_paths = QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation);
		if(default_paths.isEmpty()) THROW(Exception, "No local application data path was found!");
		QString path = default_paths[0];
		if (!QDir().mkpath(path)) THROW(Exception, "Could not create application data path '" + path + "'!");

		//set log file
		QString filename = path + QDir::separator() + QCoreApplication::applicationName() + "_local.ini";
		settings.reset(new QSettings(filename, QSettings::IniFormat));
		if (!settings->isWritable()) THROW(Exception, "Settings file '" + filename + "' is not writable!");
	}
	return *(settings.data());
}

const QSettings& Settings::settingsApplication()
{
	static QSettings* settings = nullptr;
	if(settings==nullptr)
	{
		QString filename = QCoreApplication::applicationDirPath() + QDir::separator() + QCoreApplication::applicationName() + ".ini";
		settings = new QSettings(filename, QSettings::IniFormat);
	}
	return *settings;
}

const QSettings& Settings::settingsGeneral()
{
	static QSettings* settings = nullptr;
	if(settings==nullptr)
	{
		QString filename = QCoreApplication::applicationDirPath() + QDir::separator() + "settings.ini";
		settings = new QSettings(filename, QSettings::IniFormat);
	}
	return *settings;
}

int Settings::integer(QString key)
{
	return valueWithFallback(key).toInt();
}

void Settings::setInteger(QString key, int value)
{
	QSettings& settings = settingsApplicationUser();
	settings.setValue(key, value);
	settings.sync(); //sync, so that the file is created, which is checked by settingsApplicationUserExists
}

QString Settings::string(QString key, bool optional)
{
	if (optional && !contains(key)) return "";

	QString value = valueWithFallback(key).toString();

	//decrypt if encrypted
	QString crypt_prefix = "encrypted:";
	if (value.startsWith(crypt_prefix))
	{
		//remove prefix
		value = value.mid(crypt_prefix.count()).trimmed();

		//decrypt
		qulonglong crypt_key = ToolBase::encryptionKey("setting entry '" + key + "'");
		value = SimpleCrypt(crypt_key).decryptToString(value);
	}

	return value;
}

void Settings::setString(QString key, QString value)
{
	QSettings& settings = settingsApplicationUser();
	settings.setValue(key, value);
	settings.sync(); //sync, so that the file is created, which is checked by settingsApplicationUserExists
}

QStringList Settings::stringList(QString key, bool optional)
{
	if (optional && !contains(key)) return QStringList();

	return valueWithFallback(key).toStringList();
}

void Settings::setStringList(QString key, QStringList value)
{
	QSettings& settings = settingsApplicationUser();
	settings.setValue(key, value);
	settings.sync(); //sync, so that the file is created, which is checked by settingsApplicationUserExists
}

bool Settings::boolean(QString key, bool optional)
{
	if (optional && !contains(key)) return false;

	return valueWithFallback(key).toBool();
}

void Settings::setBoolean(QString key, bool value)
{
	QSettings& settings = settingsApplicationUser();
	settings.setValue(key, value);
	settings.sync(); //sync, so that the file is created, which is checked by settingsApplicationUserExists
}

QMap<QString, QVariant> Settings::map(QString key, bool optional)
{
	if (optional && !contains(key)) QMap<QString, QVariant>();

	return valueWithFallback(key).toMap();
}

void Settings::setMap(QString key, QMap<QString, QVariant> value)
{
	QSettings& settings = settingsApplicationUser();
	settings.setValue(key, value);
	settings.sync(); //sync, so that the file is created, which is checked by settingsApplicationUserExists
}

QString Settings::path(QString key, bool optional)
{
	if (optional && !contains(key)) return "";

	QString path = string(key).trimmed();

	//convert separators
	path = Helper::canonicalPath(path);

	//add separator at the end if missing from path
	if (QFile::exists(path) && QFileInfo(path).isDir() && !path.endsWith(QDir::separator()))
	{
		path += QDir::separator();
	}

	return path;
}

void Settings::setPath(QString key, QString path)
{
	QFileInfo info(path);
	if (info.isFile())
	{
		path = info.absolutePath();
	}

	if (QDir(path).exists())
	{
		setString(key, Helper::canonicalPath(path));
	}
}

void Settings::clear()
{
	settingsApplicationUser().clear();
}

void Settings::remove(QString key)
{
	settingsApplicationUser().remove(key);
}

QStringList Settings::allKeys()
{
	QStringList output;

	if (settingsApplicationUserExists())
	{
		output << settingsApplicationUser().allKeys();
	}
	output << settingsApplication().allKeys();
	output << settingsGeneral().allKeys();

	std::sort(output.begin(), output.end());
	output.removeDuplicates();

	return output;
}

bool Settings::contains(QString key)
{
	//check if key exists
	bool key_exists = (settingsApplicationUserExists() && settingsApplicationUser().contains(key)) || settingsApplication().contains(key) || settingsGeneral().contains(key);
	if (!key_exists) return false;

	//if the key exists, check that the value is not empty
	QVariant var = valueWithFallback(key);
	if (var.type()==QVariant::StringList) return var.toStringList().join("").trimmed()!=""; //special handling for QStringList
	if (var.type()==QVariant::Map) return var.toMap().keys().join("").trimmed()!=""; //special handling for QMap
	return var.toString().trimmed()!="";
}

QVariant Settings::valueWithFallback(QString key)
{
	if (settingsApplicationUserExists() && settingsApplicationUser().contains(key))
	{
		return settingsApplicationUser().value(key);
	}

	if (settingsApplication().contains(key))
	{
		return settingsApplication().value(key);
	}

	if (settingsGeneral().contains(key))
	{
		return settingsGeneral().value(key);
	}

	THROW(ProgrammingException, "Requested key '" + key + "' not found in settings!");
}
<|endoftext|>


<commit_before>//
// SonarSRF
// Arduino Library for controlling SRF sonar sensors
// http://www.arduino.cc/playground/Main/SonarSrf08
//
// MIT License
// Copyright(c) 2009 Zach Foresta
// Copyright(c) 2012 Philipp A. Mohrenweiser
// Copyright(c) 2012-2016 Leo Colombaro
//

#include "SonarSRF.h"

/// <summary>
/// Initiates the connection to the sensor and start I2C bus
/// </summary>
/// <param name="address">I2C Address</param>
/// <param name="gainRegister">SRF Location 1</param>
/// <param name="rangeLocation">SRF Location 2</param>
void SonarSRF::SonarSRF(int address, int gainRegister, int rangeLocation)
{
    _address = address;
    _gainRegister = gainRegister;
    _rangeLocation = rangeLocation;
    Wire.begin();
}

/// <summary>
/// Sets Units for display / storage
/// </summary>
/// <remarks>
/// * 'i' for inches
/// * 'c' for centimeters
/// * 'm' for microseconds
/// </remarks>
/// <param name="unit">Unit used</param>
void SonarSRF::startRanging(char unit)
{
    switch (unit)
    {
    case 'i':
        sendCommand(INCHES);
        break;
    case 'c':
        sendCommand(CENTIMETERS);
        break;
    case 'm':
        sendCommand(MICROSECONDS);
        break;
    default:
        Serial.println("Invalid units entered... using micro-seconds");
        sendCommand(MICROSECONDS);
    }
}

/// <summary>
/// Communicates with Sonar to send commands
/// </summary>
/// <param name="command">SRF Command</param>
/// <param name="addressRegister">SRF Location 0</param>
/// <seealso cref="connect"/>
void SonarSRF::sendCommand(int command, int addressRegister)
{
    // start I2C transmission
    Wire.beginTransmission(_address);
    // send command
    Wire.write(addressRegister);
    if (command != NULL)
    {
        Wire.write(command);
        if (_gainRegister && _rangeLocation)
        {
            Wire.write(_gainRegister); // SRF Location 1
            Wire.write(_rangeLocation); // SRF Location 2
        }
    }
    // end I2C transmission
    Wire.endTransmission();
}

/// <summary>
/// Read data from register return result
/// </summary>
/// <param name="unit">Unit used</param>
/// <param name="andStart"></param>
/// <returns>The range number (two bytes)</returns>
/// <seealso cref="startRanging"/>
int SonarSRF::getRange(char unit, bool andStart)
{
    int result = 0; // the result is two bytes long
    if (andStart)
    {
        startRanging(unit);
        waitForCompletion();
    }
    sendCommand(NULL, RESULT_REGISTER);
    Wire.requestFrom(_address, 2);
    // wait for two bytes to return
    while (Wire.available() < 2); // wait for result
    // read the two bytes, and combine them into one int
    byte highByte = Wire.read(); // Stores high byte from ranging
    byte lowByte = Wire.read(); // Stored low byte from ranging
    result = (highByte << 8) + lowByte;
    return result;
}

/// <summary>
/// Wait for completion
/// </summary>
void SonarSRF::waitForCompletion()
{
    while (getVersion() == -1)
    {
        delay(1);
    }
}

/// <summary>
/// Get software revision
/// </summary>
/// <returns>The software revision (one byte)</returns>
int SonarSRF::getVersion()
{
    sendCommand();
    Wire.requestFrom(_address, 1); // Request 1 byte
    while (Wire.available() < 0); // While byte available
    int software = Wire.read(); // Get byte
    return software;
}

/// <summary>
/// Set a new address
/// </summary>
/// <remarks>
/// The address given in Arduino 7bit has to be converted back into SRF 8bit
/// newAddress << 1 can be set to any of E0, E2, E4, E6, E8, EA, EC, EE, F0, F2,
/// F4, F6, F8, FA, FC, FE.
/// </remarks>
/// <param name="newAddress">The new address</param>
void SonarSRF::setAddress(int newAddress)
{
    sendCommand(0xA0);
    sendCommand(0xAA);
    sendCommand(0xA5);
    sendCommand(newAddress << 1);
}
<commit_msg>Remove useless code<commit_after>//
// SonarSRF
// Arduino Library for controlling SRF sonar sensors
// http://www.arduino.cc/playground/Main/SonarSrf08
//
// MIT License
// Copyright(c) 2009 Zach Foresta
// Copyright(c) 2012 Philipp A. Mohrenweiser
// Copyright(c) 2012-2016 Leo Colombaro
//

#include "SonarSRF.h"

/// <summary>
/// Initiates the connection to the sensor and start I2C bus
/// </summary>
/// <param name="address">I2C Address</param>
/// <param name="gainRegister">SRF Location 1</param>
/// <param name="rangeLocation">SRF Location 2</param>
void SonarSRF::SonarSRF(int address, int gainRegister, int rangeLocation)
{
    _address = address;
    _gainRegister = gainRegister;
    _rangeLocation = rangeLocation;
    Wire.begin();
}

/// <summary>
/// Sets Units for display / storage
/// </summary>
/// <remarks>
/// * 'i' for inches
/// * 'c' for centimeters
/// * 'm' for microseconds
/// </remarks>
/// <param name="unit">Unit used</param>
void SonarSRF::startRanging(char unit)
{
    switch (unit)
    {
    case 'i':
        sendCommand(INCHES);
        break;
    case 'c':
        sendCommand(CENTIMETERS);
        break;
    case 'm':
        sendCommand(MICROSECONDS);
        break;
    default:
        Serial.println("Invalid units entered... using micro-seconds");
        sendCommand(MICROSECONDS);
    }
}

/// <summary>
/// Communicates with Sonar to send commands
/// </summary>
/// <param name="command">SRF Command</param>
/// <param name="addressRegister">SRF Location 0</param>
/// <seealso cref="connect"/>
void SonarSRF::sendCommand(int command, int addressRegister)
{
    // start I2C transmission
    Wire.beginTransmission(_address);
    // send command
    Wire.write(addressRegister);
    if (command != NULL)
    {
        Wire.write(command);
        if (_gainRegister && _rangeLocation)
        {
            Wire.write(_gainRegister); // SRF Location 1
            Wire.write(_rangeLocation); // SRF Location 2
        }
    }
    // end I2C transmission
    Wire.endTransmission();
}

/// <summary>
/// Read data from register return result
/// </summary>
/// <param name="unit">Unit used</param>
/// <param name="andStart"></param>
/// <returns>The range number (two bytes)</returns>
/// <seealso cref="startRanging"/>
int SonarSRF::getRange(char unit, bool andStart)
{
    if (andStart)
    {
        startRanging(unit);
        waitForCompletion();
    }
    sendCommand(NULL, RESULT_REGISTER);
    Wire.requestFrom(_address, 2);
    // wait for two bytes to return
    while (Wire.available() < 2); // wait for result
    // read the two bytes, and combine them into one int
    byte highByte = Wire.read(); // Stores high byte from ranging
    byte lowByte = Wire.read(); // Stored low byte from ranging
    return (int)((highByte << 8) + lowByte);
}

/// <summary>
/// Wait for completion
/// </summary>
void SonarSRF::waitForCompletion()
{
    while (getVersion() == -1)
    {
        delay(1);
    }
}

/// <summary>
/// Get software revision
/// </summary>
/// <returns>The software revision (one byte)</returns>
int SonarSRF::getVersion()
{
    sendCommand();
    Wire.requestFrom(_address, 1); // Request 1 byte
    while (Wire.available() < 0); // While byte available
    return (int)(Wire.read());
}

/// <summary>
/// Set a new address
/// </summary>
/// <remarks>
/// The address given in Arduino 7bit has to be converted back into SRF 8bit
/// newAddress << 1 can be set to any of E0, E2, E4, E6, E8, EA, EC, EE, F0, F2,
/// F4, F6, F8, FA, FC, FE.
/// </remarks>
/// <param name="newAddress">The new address</param>
void SonarSRF::setAddress(int newAddress)
{
    sendCommand(0xA0);
    sendCommand(0xAA);
    sendCommand(0xA5);
    sendCommand(newAddress << 1);
}
<|endoftext|>


<commit_before>#include <iostream>

#include "StringSet.hh"

using namespace std;

StringSet::StringSet(const std::map<std::string, flt_type> &vocab, bool log_domain) {
    max_factor_length = 0;
    for (auto it = vocab.cbegin(); it !=vocab.cend(); ++it)
        add(it->first, it->second);
    this->optimize_arcs(&root_node, log_domain);
}

StringSet::~StringSet() {
    clear(&root_node);
}

StringSet::Arc*
StringSet::find_arc(char letter,
                    const StringSet::Node *node) const
{
    Arc *arc = node->first_arc;
    while (arc != NULL) {
        if (arc->letter == letter) break;
        arc = arc->sibling_arc;
    }
    return arc;
}

bool
StringSet::includes(const string &factor) const
{
    const StringSet::Node *node = &root_node;
    StringSet::Arc *arc = NULL;
    for (unsigned int i=0; i<factor.length(); i++) {
        arc = find_arc(factor[i], node);
        if (arc == NULL) return false;
        node = arc->target_node;
    }
    if (arc->factor.length() == 0) return false;
    return true;
}

flt_type
StringSet::get_score(const string &factor) const
{
    const StringSet::Node *node = &root_node;
    StringSet::Arc *arc = NULL;
    for (unsigned int i=0; i<factor.length(); i++) {
        arc = find_arc(factor[i], node);
        if (arc == NULL) throw string("could not find factor");
        node = arc->target_node;
    }
    if (arc->factor.length() == 0) throw string("could not find factor");
    return arc->cost;
}

void
StringSet::add(const string &factor, flt_type cost)
{
    // Create arcs
    Node *node = &root_node;
    int i=0;
    for (; i < (int)factor.length()-1; i++)
        node = insert(factor[i], "" , 0.0, node);
    insert(factor[i], factor, cost, node);
}

flt_type
StringSet::remove(const string &factor)
{
    StringSet::Node *node = &root_node;
    StringSet::Arc *arc = NULL;

    for (unsigned int i=0; i<factor.length(); i++) {
        arc = find_arc(factor[i], node);
        if (arc == NULL) throw string("could not remove factor");
        node = arc->target_node;
    }
    arc->factor.clear();
    flt_type cost = arc->cost;
    arc->cost = 0.0;
    return cost;
}

StringSet::Node*
StringSet::insert(char letter,
                  const string &factor,
                  flt_type cost,
                  StringSet::Node *node)
{
    // Find a possible existing arc with the letter
    Arc *arc = node->first_arc;
    while (arc != NULL) {
        if (arc->letter == letter) break;
        arc = arc->sibling_arc;
    }

    // No existing arc: create a new arc
    if (arc == NULL) {
        Node *new_node = new Node(NULL);
        node->first_arc = new Arc(letter, factor, new_node, node->first_arc, cost);
        arc = node->first_arc;
    }

    // Update the existing arc if factor was set
    else if (factor.length() > 0) {
        if (arc->factor.length() == 0) arc->factor = factor;
        arc->cost = cost;
    }

    // Maintain the length of the longest factor
    if ((int)factor.length() > max_factor_length)
        max_factor_length = factor.length();

    return arc->target_node;
}

flt_type
StringSet::optimize_arcs(Node *node, bool log_domain)
{
    flt_type total = log_domain ? SMALL_LP : 0.0;
    StringSet::Arc *arc = node->first_arc;
    multimap<flt_type, Arc*> letters;

    while (arc != NULL) {
        flt_type cumsum = optimize_arcs(arc->target_node, log_domain);
        if (log_domain) {
            if (arc->factor.length() > 0)
                cumsum = add_log_domain_probs(cumsum, arc->cost);
            total = add_log_domain_probs(cumsum, total);
        } else {
            if (arc->factor.length() > 0)
                cumsum += arc->cost;
            total += cumsum;
        }
        letters.insert( pair<flt_type, Arc*>(cumsum, arc) );
        arc = arc->sibling_arc;
    }

    Arc* prev_arc = NULL;
    Arc* curr_arc = NULL;
    for (auto it = letters.begin(); it != letters.end(); ++it) {
        curr_arc = it->second;
        curr_arc->sibling_arc = prev_arc;
        prev_arc = curr_arc;
    }
    node->first_arc = curr_arc;

    return total;
}

void
StringSet::assign_scores(const std::map<std::string, flt_type> &vocab)
{
    for (auto it = vocab.begin(); it != vocab.end(); ++it) {
        string factor(it->first);
        Node *node = &root_node;
        int i=0;
        for (; i < (int)factor.length()-1; i++)
            node = insert(factor[i], "" , 0.0, node);
        insert(factor[i], factor, it->second, node);
    }
}

void
StringSet::clear(Node *node)
{
    StringSet::Arc *curr_arc = node->first_arc;
    StringSet::Arc *temp_arc = NULL;

    while (curr_arc != NULL) {
        clear(curr_arc->target_node);
        temp_arc = curr_arc;
        curr_arc = curr_arc->sibling_arc;
        delete temp_arc->target_node;
        delete temp_arc;
    }
}

bool
StringSet::prune(Node *node)
{
    StringSet::Arc *curr_arc = node->first_arc;
    StringSet::Arc *temp_arc = NULL;

    std::vector<StringSet::Arc*> arcs;
    while (curr_arc != NULL) {
        bool unused = prune(curr_arc->target_node);
        temp_arc = curr_arc;
        curr_arc = curr_arc->sibling_arc;
        if (unused && temp_arc->factor.length() == 0) {
            delete temp_arc->target_node;
            delete temp_arc;
        } else {
            arcs.push_back(temp_arc);
        }
    }

    node->first_arc = NULL;
    for (int i=0; i<(int)arcs.size()-1; i++)
        arcs[i]->sibling_arc = arcs[i+1];
    if (arcs.size() > 0) {
        arcs[arcs.size()-1]->sibling_arc = NULL;
        node->first_arc = arcs[0];
    }

    if (arcs.size() > 0) return false;
    else return true;
}
<commit_msg>Minor cleanup.<commit_after>#include <iostream>

#include "StringSet.hh"

using namespace std;

StringSet::StringSet(const std::map<std::string, flt_type> &vocab, bool log_domain) {
    max_factor_length = 0;
    for (auto it = vocab.cbegin(); it !=vocab.cend(); ++it)
        add(it->first, it->second);
    this->optimize_arcs(&root_node, log_domain);
}

StringSet::~StringSet() {
    clear(&root_node);
}

StringSet::Arc*
StringSet::find_arc(char letter,
                    const StringSet::Node *node) const
{
    Arc *arc = node->first_arc;
    while (arc != NULL) {
        if (arc->letter == letter) break;
        arc = arc->sibling_arc;
    }
    return arc;
}

bool
StringSet::includes(const string &factor) const
{
    const StringSet::Node *node = &root_node;
    StringSet::Arc *arc = NULL;
    for (unsigned int i=0; i<factor.length(); i++) {
        arc = find_arc(factor[i], node);
        if (arc == NULL) return false;
        node = arc->target_node;
    }
    if (arc->factor.length() == 0) return false;
    return true;
}

flt_type
StringSet::get_score(const string &factor) const
{
    const StringSet::Node *node = &root_node;
    StringSet::Arc *arc = NULL;
    for (unsigned int i=0; i<factor.length(); i++) {
        arc = find_arc(factor[i], node);
        if (arc == NULL) throw string("could not find factor");
        node = arc->target_node;
    }
    if (arc->factor.length() == 0) throw string("could not find factor");
    return arc->cost;
}

void
StringSet::add(const string &factor, flt_type cost)
{
    // Create arcs
    Node *node = &root_node;
    int i=0;
    for (; i < (int)factor.length()-1; i++)
        node = insert(factor[i], "" , 0.0, node);
    insert(factor[i], factor, cost, node);
}

flt_type
StringSet::remove(const string &factor)
{
    StringSet::Node *node = &root_node;
    StringSet::Arc *arc = NULL;

    for (unsigned int i=0; i<factor.length(); i++) {
        arc = find_arc(factor[i], node);
        if (arc == NULL) throw string("could not remove factor");
        node = arc->target_node;
    }
    arc->factor.clear();
    flt_type cost = arc->cost;
    arc->cost = 0.0;
    return cost;
}

StringSet::Node*
StringSet::insert(char letter,
                  const string &factor,
                  flt_type cost,
                  StringSet::Node *node)
{
    // Find a possible existing arc with the letter
    Arc *arc = node->first_arc;
    while (arc != NULL) {
        if (arc->letter == letter) break;
        arc = arc->sibling_arc;
    }

    // No existing arc: create a new arc
    if (arc == NULL) {
        Node *new_node = new Node(NULL);
        node->first_arc = new Arc(letter, factor, new_node, node->first_arc, cost);
        arc = node->first_arc;
    }

    // Update the existing arc if factor was set
    else if (factor.length() > 0) {
        if (arc->factor.length() == 0) arc->factor = factor;
        arc->cost = cost;
    }

    // Maintain the length of the longest factor
    if ((int)factor.length() > max_factor_length)
        max_factor_length = factor.length();

    return arc->target_node;
}

flt_type
StringSet::optimize_arcs(Node *node, bool log_domain)
{
    flt_type total = log_domain ? SMALL_LP : 0.0;
    StringSet::Arc *arc = node->first_arc;
    multimap<flt_type, Arc*> letters;

    while (arc != NULL) {
        flt_type cumsum = optimize_arcs(arc->target_node, log_domain);
        if (log_domain) {
            if (arc->factor.length() > 0)
                cumsum = add_log_domain_probs(cumsum, arc->cost);
            total = add_log_domain_probs(cumsum, total);
        } else {
            if (arc->factor.length() > 0)
                cumsum += arc->cost;
            total += cumsum;
        }
        letters.insert( pair<flt_type, Arc*>(cumsum, arc) );
        arc = arc->sibling_arc;
    }

    Arc* prev_arc = NULL;
    Arc* curr_arc = NULL;
    for (auto it = letters.begin(); it != letters.end(); ++it) {
        curr_arc = it->second;
        curr_arc->sibling_arc = prev_arc;
        prev_arc = curr_arc;
    }
    node->first_arc = curr_arc;

    return total;
}

void
StringSet::assign_scores(const std::map<std::string, flt_type> &vocab)
{
    for (auto it = vocab.begin(); it != vocab.end(); ++it) {
        string factor(it->first);
        Node *node = &root_node;
        int i=0;
        for (; i < (int)factor.length()-1; i++)
            node = insert(factor[i], "" , 0.0, node);
        insert(factor[i], factor, it->second, node);
    }
}

void
StringSet::clear(Node *node)
{
    StringSet::Arc *curr_arc = node->first_arc;
    StringSet::Arc *temp_arc = NULL;

    while (curr_arc != NULL) {
        clear(curr_arc->target_node);
        temp_arc = curr_arc;
        curr_arc = curr_arc->sibling_arc;
        delete temp_arc->target_node;
        delete temp_arc;
    }
}

bool
StringSet::prune(Node *node)
{
    StringSet::Arc *curr_arc = node->first_arc;
    StringSet::Arc *temp_arc = NULL;

    std::vector<StringSet::Arc*> arcs;
    while (curr_arc != NULL) {
        bool unused = prune(curr_arc->target_node);
        temp_arc = curr_arc;
        curr_arc = curr_arc->sibling_arc;
        if (unused && temp_arc->factor.length() == 0) {
            delete temp_arc->target_node;
            delete temp_arc;
        }
        else arcs.push_back(temp_arc);
    }

    node->first_arc = NULL;
    if (arcs.size() > 0) {
        for (int i=0; i<(int)arcs.size()-1; i++)
            arcs[i]->sibling_arc = arcs[i+1];
        arcs[arcs.size()-1]->sibling_arc = NULL;
        node->first_arc = arcs[0];
        return false;
    }
    else return true;
}
<|endoftext|>


<commit_before>#ifndef TESTS
#error "You shouldn't compile UnitTests.cc without test mode on."
#endif

#include "UnitTests.h"

#include "Bank.h"

#include "Printer.h"
#include "debug.h"

#include "Config.h"
#include "Main.h"

using namespace std;

static void VectorsEqual(vector<PrintState> &lhs, vector<PrintState> &rhs) {
    int ix = 0;
    while (ix < (int)min(lhs.size(), rhs.size())) {
        if (!lhs[ix].equals(rhs[ix])) {
            printf("Values not equal at %d:\n", ix);
            printf("Should be:\t\t"); lhs[ix].print();
            printf("But was:\t\t"); rhs[ix].print();
        }
        ix++;
    }
    if (ix < (int)lhs.size()) {
        printf("Missing values:\n");
    }
    while (ix < (int)lhs.size()) {
        printf("\t"); lhs[ix++].print();
    }

    if (ix < (int)rhs.size()) {
        printf("Extra values:\n");
    }
    while (ix < (int)rhs.size()) {
        printf("\t"); rhs[ix++].print();
    }
}

_Task BankWithdraw {
public:
    Bank &bank;
    int id;
    int count;
    BankWithdraw(Bank & bank, int id, int count) : bank(bank), id(id), count(count) { }
    void main() {
        bank.withdraw(id, count);
    }
};

static void TestBank(uBaseTask &task) {
    testPrinter.states.clear();
    Bank bank(1);
    {
        BankWithdraw task(bank, 0, 2);
        task.yield(10);
        bank.deposit(0, 1);
        bank.deposit(0, 1);
    }

    vector<PrintState> TestBankResults {
        PrintState(PrinterKind::BankDeposit, 0, ' ', 1),
        PrintState(PrinterKind::BankDeposit, 0, ' ', 1),
        PrintState(PrinterKind::BankWithdraw, 0, ' ', 2)
    };
    VectorsEqual(TestBankResults, testPrinter.states);
}

void RunAllTests(uBaseTask &task) {
    TestBank(task);
}

Config genRandConfig() {
    Config config;
    config.sodaCost = rand() % 10 + 1;
    config.numStudents = rand() % 10 + 1;
    config.maxPurchases = rand() % 10 + 1;
    config.numVendingMachines = rand() % 10 + 1;
    config.maxStockPerFlavour = rand() % 10 + 1;
    config.maxShippedPerFlavour = rand() % 10 + 1;
    config.timeBetweenShipments = rand() % 10 + 1;
    config.parentalDelay = rand() % 10 + 1;
    config.numCouriers = rand() % 10 + 1;
    return config;
}

void uMain::main() {
    Config config = genRandConfig();

    Main(config);
    //RunAllTests(*this);
}
<commit_msg>Printed the config file.<commit_after>#ifndef TESTS
#error "You shouldn't compile UnitTests.cc without test mode on."
#endif

#include "UnitTests.h"

#include "Bank.h"

#include "Printer.h"
#include "debug.h"

#include "Config.h"
#include "Main.h"

using namespace std;

static void VectorsEqual(vector<PrintState> &lhs, vector<PrintState> &rhs) {
    int ix = 0;
    while (ix < (int)min(lhs.size(), rhs.size())) {
        if (!lhs[ix].equals(rhs[ix])) {
            printf("Values not equal at %d:\n", ix);
            printf("Should be:\t\t"); lhs[ix].print();
            printf("But was:\t\t"); rhs[ix].print();
        }
        ix++;
    }
    if (ix < (int)lhs.size()) {
        printf("Missing values:\n");
    }
    while (ix < (int)lhs.size()) {
        printf("\t"); lhs[ix++].print();
    }

    if (ix < (int)rhs.size()) {
        printf("Extra values:\n");
    }
    while (ix < (int)rhs.size()) {
        printf("\t"); rhs[ix++].print();
    }
}

_Task BankWithdraw {
public:
    Bank &bank;
    int id;
    int count;
    BankWithdraw(Bank & bank, int id, int count) : bank(bank), id(id), count(count) { }
    void main() {
        bank.withdraw(id, count);
    }
};

static void TestBank(uBaseTask &task) {
    testPrinter.states.clear();
    Bank bank(1);
    {
        BankWithdraw task(bank, 0, 2);
        task.yield(10);
        bank.deposit(0, 1);
        bank.deposit(0, 1);
    }

    vector<PrintState> TestBankResults {
        PrintState(PrinterKind::BankDeposit, 0, ' ', 1),
        PrintState(PrinterKind::BankDeposit, 0, ' ', 1),
        PrintState(PrinterKind::BankWithdraw, 0, ' ', 2)
    };
    VectorsEqual(TestBankResults, testPrinter.states);
}

void RunAllTests(uBaseTask &task) {
    TestBank(task);
}

Config genRandConfig() {
    Config config;
    config.sodaCost = rand() % 10 + 1;
    config.numStudents = rand() % 10 + 1;
    config.maxPurchases = rand() % 10 + 1;
    config.numVendingMachines = rand() % 10 + 1;
    config.maxStockPerFlavour = rand() % 10 + 1;
    config.maxShippedPerFlavour = rand() % 10 + 1;
    config.timeBetweenShipments = rand() % 10 + 1;
    config.parentalDelay = rand() % 10 + 1;
    config.numCouriers = rand() % 10 + 1;
    return config;
}

void uMain::main() {
    Config config = genRandConfig();

    printf(
        "sodaCost %d, "
        "numStudents %d, "
        "maxPurchases %d, "
        "numVendingMachines %d, "
        "maxStockPerFlavour %d, "
        "maxShippedPerFlavour %d, "
        "timeBetweenShipments %d, "
        "parentalDelay %d, "
        "numCouriers %d\n",
        config.sodaCost,
        config.numStudents,
        config.maxPurchases,
        config.numVendingMachines,
        config.maxStockPerFlavour,
        config.maxShippedPerFlavour,
        config.timeBetweenShipments,
        config.parentalDelay,
        config.numCouriers
    );

    Main(config);
    //RunAllTests(*this);
}
<|endoftext|>


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

/** \file Channel.cc
 * \brief
 *
 */

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <syslog.h>
#include <glob.h>

#include <tcl.h>
#include "TCL_Fixup.h"
#include <valgrind/memcheck.h>

#include "util.h"
#include "Channel.h"
#include "Service.h"

namespace { int debug = 0; }

/**
 * dst is the destination service id
 * src is the source service id
 */
struct channel_message {
    long dst;
    long src;
    long error;
    char body[1012];
};
#define MESSAGE_OK        0
#define MESSAGE_ERROR     1
#define MESSAGE_EXCEPTION 2

/**
 * Look through list of processes to see if the named service is
 * alive.  We check by looking a process that has its executable
 * as /usr/sbin/[service_name].
 *
 * Note: readlink does not NULL terminate the strings it reads, so
 *   we must do it explicitly.
 */
static int
is_alive( char *service_name ) {
    int result = 0;
    glob_t processes;
    size_t i;
    char exe[256], path[80];

    sprintf( path, "/usr/sbin/%s", service_name );

    memset( &processes, 0, sizeof(processes) );
    glob( "/proc/*/exe", GLOB_NOSORT, NULL, &processes );

    for ( i = 0 ; i < processes.gl_pathc ; i++ ) {
        int count = readlink( processes.gl_pathv[i], exe, sizeof(exe) );
        if ( count == -1 ) continue;
        exe[count] = '\0';
        if ( strcmp(exe, path) == 0 ) {
            result = 1;
            break;
        }
    }

    globfree( &processes );
    return result;
}

/**
 */
key_t service_key( const char *service_name ) {
    key_t key = *( (key_t*)service_name );
    if ( key == -1 ) {
        syslog( LOG_ERR, "could not generate a key for '%s'", service_name );
        exit( 1 );
    }
    // send this to stdout if the tcl interpreter is interactive
    // syslog( LOG_NOTICE, "channel key for '%s' is 0x%08x", service_name, key );
    return key;
}

/**
 * will need a path name to point the mq at
 *
 * Channel needs to be a thread that reads the Q and
 * calls the interpreter when it gets the message
 *
 * The channel cannot accept messages until the interpreter is
 * fully initialized.  Also, the channel should be the primary
 * (only?) evaluator in the interpreter.
 *
 * Should make the Interpreter be a base class and have a
 * TclInterpreter and a RubyInterpreter?  The Interpreter
 * should provide an evalute method ...
 *
 *
 * There will be a race here ... where the client of a service
 * will not be able to start until the server.  However, if they
 * talk to each other then they are both clients and servers
 * so neither could start.  So, the client needs to be able to
 * create the server's directory also.
 */
Channel::Channel( Service *service )
: service(service) {
    key_t key = service_key( service->name() );
    syslog( LOG_NOTICE, "msgQ id = 0x%08x", key );

    // Eventually change this so only root can send...
    q = msgget( key, IPC_CREAT | 0777 );
    if ( q < 0 ) {
        syslog( LOG_ERR, "could not create a msgQ for '%s'", service->name() );
        exit( 1 );
    }
}

/**
 * \todo should use IPC_NOWAIT -- and try again if EAGAIN
 * \todo fix message length calculation
 */
void
Channel::send( long dst, int result, char *message ) {
    int flags = 0; // IPC_NOWAIT | MSG_NOERROR
    struct channel_message m;
    m.dst = dst;
    m.src = 1;
    m.error = result;
    int bytes = strlcpy( m.body, message, sizeof(m.body) );
    if ( bytes > sizeof(m.body) ) {
        syslog( LOG_WARNING, "message body truncated" );
        bytes = sizeof(m.body) - 1;
    }
    if ( msgsnd(q, &m, bytes + sizeof(char) + sizeof(long) + sizeof(long), flags) < 0 ) {
        syslog( LOG_ERR, "failed to msgsnd" );
    }
}

/**
 * block ... read from Q and process msg
 * \todo add retry logic when we get a msgrcv err on Channel
 */
long
Channel::receive( char *buffer, int length ) {
    int flags = 0; // IPC_NOWAIT | MSG_NOERROR
    struct channel_message request;
    int bytes = msgrcv( q, &request, sizeof(request), 1, flags );
    if ( bytes < 0 ) {
        // how to handle error
        syslog( LOG_ERR, "Error receiving Channel request" );
    }
    if ( debug > 0 ) syslog( LOG_NOTICE, "request '%s'", request.body );
    strlcpy( buffer, request.body, length );
    return request.src;
}

/**
 */
ChannelClient::ChannelClient( char *service_name ) {
    strlcpy( service, service_name, sizeof(service) );
    key_t key = service_key( service_name );
    // Eventually change this so only root can send...
    q = msgget( key, IPC_CREAT | 0777 );
    if ( q < 0 ) {
        syslog( LOG_ERR, "could not create a msgQ for '%s'", service_name );
        exit( 1 );
    }
}

/**
 * \todo should use IPC_NOWAIT -- and try again if EAGAIN
 * \todo fix message length calculation
 */
void
ChannelClient::send( char *message ) {
    int flags = 0; // IPC_NOWAIT | MSG_NOERROR
    struct channel_message m;
    m.dst = 1;
    m.src = getpid();
    m.error = 0;
    int bytes = strlcpy( m.body, message, sizeof(m.body) );
    if ( bytes > sizeof(m.body) ) {
        syslog( LOG_WARNING, "message body truncated" );
        bytes = sizeof(m.body) - 1;
    }
    if ( msgsnd(q, &m, bytes + sizeof(char) + sizeof(long) + sizeof(long), flags) < 0 ) {
        syslog( LOG_ERR, "failed to msgsnd" );
    }
}

/**
 * block ... read from Q and process msg
 */
int
ChannelClient::receive( char *buffer, int length ) {
    int flags = 0; // IPC_NOWAIT | MSG_NOERROR
    struct channel_message request;

    int bytes = msgrcv( q, &request, sizeof(request), getpid(), flags );
    if ( bytes < 0 ) {
        // how to handle error -- try again
    }
    strlcpy( buffer, request.body, length );
    return request.error;
}

/**
 */
int
ChannelClient::receive( char *buffer, int length, time_t time_limit ) {
    struct channel_message request;
    time_t elapsed = 0;
    struct timespec delay = { 1, 0 };
    pid_t pid = getpid();

    do {
        int bytes = msgrcv( q, &request, sizeof(request), pid, IPC_NOWAIT );

        if ( bytes > 0 ) {
            strlcpy( buffer, request.body, length );
            return request.error;
        }

        /**
         * We only want this error correction when we are not running under
         * valgrind, since valgrind changes the name of the program that is
         * running and all messaging would fail since we can not detect process
         * liveness after the program name change.
         */
        if ( RUNNING_ON_VALGRIND == 0 ) {
            if ( is_alive(service) == false ) return MESSAGE_EXCEPTION;
        }
        nanosleep( &delay, NULL );
    } while ( ++elapsed < time_limit );

    syslog( LOG_ERR, "ERROR channel recv timed out" );
    return MESSAGE_EXCEPTION;
}

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

/** \file Channel.cc
 * \brief
 *
 */

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <syslog.h>
#include <glob.h>

#include "util.h"
#include "Channel.h"
#include "Service.h"

namespace { int debug = 0; }

/**
 * dst is the destination service id
 * src is the source service id
 */
struct channel_message {
    long dst;
    long src;
    long error;
    char body[1012];
};
#define MESSAGE_OK        0
#define MESSAGE_ERROR     1
#define MESSAGE_EXCEPTION 2

/**
 * Look through list of processes to see if the named service is
 * alive.  We check by looking a process that has its executable
 * as /usr/sbin/[service_name].
 *
 * Note: readlink does not NULL terminate the strings it reads, so
 *   we must do it explicitly.
 */
static int
is_alive( char *service_name ) {
    int result = 0;
    glob_t processes;
    size_t i;
    char exe[256], path[80];

    sprintf( path, "/usr/sbin/%s", service_name );

    memset( &processes, 0, sizeof(processes) );
    glob( "/proc/*/exe", GLOB_NOSORT, NULL, &processes );

    for ( i = 0 ; i < processes.gl_pathc ; i++ ) {
        int count = readlink( processes.gl_pathv[i], exe, sizeof(exe) );
        if ( count == -1 ) continue;
        exe[count] = '\0';
        if ( strcmp(exe, path) == 0 ) {
            result = 1;
            break;
        }
    }

    globfree( &processes );
    return result;
}

/**
 */
key_t service_key( const char *service_name ) {
    key_t key = *( (key_t*)service_name );
    if ( key == -1 ) {
        syslog( LOG_ERR, "could not generate a key for '%s'", service_name );
        exit( 1 );
    }
    // send this to stdout if the tcl interpreter is interactive
    // syslog( LOG_NOTICE, "channel key for '%s' is 0x%08x", service_name, key );
    return key;
}

/**
 * will need a path name to point the mq at
 *
 * Channel needs to be a thread that reads the Q and
 * calls the interpreter when it gets the message
 *
 * The channel cannot accept messages until the interpreter is
 * fully initialized.  Also, the channel should be the primary
 * (only?) evaluator in the interpreter.
 *
 * Should make the Interpreter be a base class and have a
 * TclInterpreter and a RubyInterpreter?  The Interpreter
 * should provide an evalute method ...
 *
 *
 * There will be a race here ... where the client of a service
 * will not be able to start until the server.  However, if they
 * talk to each other then they are both clients and servers
 * so neither could start.  So, the client needs to be able to
 * create the server's directory also.
 */
Channel::Channel( Service *service )
: service(service) {
    key_t key = service_key( service->name() );
    syslog( LOG_NOTICE, "msgQ id = 0x%08x", key );

    // Eventually change this so only root can send...
    q = msgget( key, IPC_CREAT | 0777 );
    if ( q < 0 ) {
        syslog( LOG_ERR, "could not create a msgQ for '%s'", service->name() );
        exit( 1 );
    }
}

/**
 * \todo should use IPC_NOWAIT -- and try again if EAGAIN
 * \todo fix message length calculation
 */
void
Channel::send( long dst, int result, char *message ) {
    int flags = 0; // IPC_NOWAIT | MSG_NOERROR
    struct channel_message m;
    m.dst = dst;
    m.src = 1;
    m.error = result;
    int bytes = strlcpy( m.body, message, sizeof(m.body) );
    if ( bytes > sizeof(m.body) ) {
        syslog( LOG_WARNING, "message body truncated" );
        bytes = sizeof(m.body) - 1;
    }
    if ( msgsnd(q, &m, bytes + sizeof(char) + sizeof(long) + sizeof(long), flags) < 0 ) {
        syslog( LOG_ERR, "failed to msgsnd" );
    }
}

/**
 * block ... read from Q and process msg
 * \todo add retry logic when we get a msgrcv err on Channel
 */
long
Channel::receive( char *buffer, int length ) {
    int flags = 0; // IPC_NOWAIT | MSG_NOERROR
    struct channel_message request;
    int bytes = msgrcv( q, &request, sizeof(request), 1, flags );
    if ( bytes < 0 ) {
        // how to handle error
        syslog( LOG_ERR, "Error receiving Channel request" );
    }
    if ( debug > 0 ) syslog( LOG_NOTICE, "request '%s'", request.body );
    strlcpy( buffer, request.body, length );
    return request.src;
}

/**
 */
ChannelClient::ChannelClient( char *service_name ) {
    strlcpy( service, service_name, sizeof(service) );
    key_t key = service_key( service_name );
    // Eventually change this so only root can send...
    q = msgget( key, IPC_CREAT | 0777 );
    if ( q < 0 ) {
        syslog( LOG_ERR, "could not create a msgQ for '%s'", service_name );
        exit( 1 );
    }
}

/**
 * \todo should use IPC_NOWAIT -- and try again if EAGAIN
 * \todo fix message length calculation
 */
void
ChannelClient::send( char *message ) {
    int flags = 0; // IPC_NOWAIT | MSG_NOERROR
    struct channel_message m;
    m.dst = 1;
    m.src = getpid();
    m.error = 0;
    int bytes = strlcpy( m.body, message, sizeof(m.body) );
    if ( bytes > sizeof(m.body) ) {
        syslog( LOG_WARNING, "message body truncated" );
        bytes = sizeof(m.body) - 1;
    }
    if ( msgsnd(q, &m, bytes + sizeof(char) + sizeof(long) + sizeof(long), flags) < 0 ) {
        syslog( LOG_ERR, "failed to msgsnd" );
    }
}

/**
 * block ... read from Q and process msg
 */
int
ChannelClient::receive( char *buffer, int length ) {
    int flags = 0; // IPC_NOWAIT | MSG_NOERROR
    struct channel_message request;

    int bytes = msgrcv( q, &request, sizeof(request), getpid(), flags );
    if ( bytes < 0 ) {
        // how to handle error -- try again
    }
    strlcpy( buffer, request.body, length );
    return request.error;
}

/**
 */
int
ChannelClient::receive( char *buffer, int length, time_t time_limit ) {
    struct channel_message request;
    time_t elapsed = 0;
    struct timespec delay = { 1, 0 };
    pid_t pid = getpid();

    do {
        int bytes = msgrcv( q, &request, sizeof(request), pid, IPC_NOWAIT );

        if ( bytes > 0 ) {
            strlcpy( buffer, request.body, length );
            return request.error;
        }

#if 0 // where is valgrind on OSX
        /**
         * We only want this error correction when we are not running under
         * valgrind, since valgrind changes the name of the program that is
         * running and all messaging would fail since we can not detect process
         * liveness after the program name change.
         */
        if ( RUNNING_ON_VALGRIND == 0 ) {
            if ( is_alive(service) == false ) return MESSAGE_EXCEPTION;
        }
#endif
        nanosleep( &delay, NULL );
    } while ( ++elapsed < time_limit );

    syslog( LOG_ERR, "ERROR channel recv timed out" );
    return MESSAGE_EXCEPTION;
}

/* vim: set autoindent expandtab sw=4 : */
<|endoftext|>