<commit_before>/**
 * @file llchicletbar.cpp
 * @brief LLChicletBar class implementation
 *
 * $LicenseInfo:firstyear=2011&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2011, Linden Research, Inc.
 *
 * 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;
 * version 2.1 of the License only.
 *
 * 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
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h" // must be first include

#include "llchicletbar.h"

// library includes
#include "llfloaterreg.h"
#include "lllayoutstack.h"

// newview includes
#include "llchiclet.h"
#include "llimfloater.h" // for LLIMFloater
#include "llpaneltopinfobar.h"
#include "llsyswellwindow.h"

namespace
{
	const std::string& PANEL_CHICLET_NAME	= "chiclet_list_panel";

	S32 get_panel_min_width(LLLayoutStack* stack, LLView* panel)
	{
		S32 minimal_width = 0;
		llassert(stack);
		if ( stack && panel && panel->getVisible() )
		{
			stack->getPanelMinSize(panel->getName(), &minimal_width);
		}
		return minimal_width;
	}

	S32 get_panel_max_width(LLLayoutStack* stack, LLPanel* panel)
	{
		S32 max_width = 0;
		llassert(stack);
		if ( stack && panel && panel->getVisible() )
		{
			stack->getPanelMaxSize(panel->getName(), &max_width);
		}
		return max_width;
	}

	S32 get_curr_width(LLUICtrl* ctrl)
	{
		S32 cur_width = 0;
		if ( ctrl && ctrl->getVisible() )
		{
			cur_width = ctrl->getRect().getWidth();
		}
		return cur_width;
	}
}

LLChicletBar::LLChicletBar(const LLSD&)
:	mChicletPanel(NULL),
	mToolbarStack(NULL)
{
	// Firstly add our self to IMSession observers, so we catch session events
	// before chiclets do that.
	LLIMMgr::getInstance()->addSessionObserver(this);

	buildFromFile("panel_chiclet_bar.xml");
}

LLChicletBar::~LLChicletBar()
{
	if (!LLSingleton<LLIMMgr>::destroyed())
	{
		LLIMMgr::getInstance()->removeSessionObserver(this);
	}
}

LLIMChiclet* LLChicletBar::createIMChiclet(const LLUUID& session_id)
{
	LLIMChiclet::EType im_chiclet_type = LLIMChiclet::getIMSessionType(session_id);

	switch (im_chiclet_type)
	{
	case LLIMChiclet::TYPE_IM:
		return getChicletPanel()->createChiclet<LLIMP2PChiclet>(session_id);
	case LLIMChiclet::TYPE_GROUP:
		return getChicletPanel()->createChiclet<LLIMGroupChiclet>(session_id);
	case LLIMChiclet::TYPE_AD_HOC:
		return getChicletPanel()->createChiclet<LLAdHocChiclet>(session_id);
	case LLIMChiclet::TYPE_UNKNOWN:
		break;
	}

	return NULL;
}

//virtual
void LLChicletBar::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id)
{
	if (!getChicletPanel()) return;

	LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id);
	if (!session) return;

	// no need to spawn chiclets for participants in P2P calls called through Avaline
	if (session->isP2P() && session->isOtherParticipantAvaline()) return;

	if (getChicletPanel()->findChiclet<LLChiclet>(session_id)) return;

	LLIMChiclet* chiclet = createIMChiclet(session_id);
	if(chiclet)
	{
		chiclet->setIMSessionName(name);
		chiclet->setOtherParticipantId(other_participant_id);

		LLIMFloater::onIMChicletCreated(session_id);

	}
	else
	{
		llwarns << "Could not create chiclet" << llendl;
	}
}

//virtual
void LLChicletBar::sessionRemoved(const LLUUID& session_id)
{
	if(getChicletPanel())
	{
		// IM floater should be closed when session removed and associated chiclet closed
		LLIMFloater* iMfloater = LLFloaterReg::findTypedInstance<LLIMFloater>("impanel", session_id);
		if (iMfloater != NULL)
		{
			iMfloater->closeFloater();
		}

		getChicletPanel()->removeChiclet(session_id);
	}
}

void LLChicletBar::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id)
{
	//this is only needed in case of outgoing ad-hoc/group chat sessions
	LLChicletPanel* chiclet_panel = getChicletPanel();
	if (chiclet_panel)
	{
		//it should be ad-hoc im chiclet or group im chiclet
		LLChiclet* chiclet = chiclet_panel->findChiclet<LLChiclet>(old_session_id);
		if (chiclet) chiclet->setSessionId(new_session_id);
	}
}

S32 LLChicletBar::getTotalUnreadIMCount()
{
	return getChicletPanel()->getTotalUnreadIMCount();
}

BOOL LLChicletBar::postBuild()
{
	mToolbarStack = getChild<LLLayoutStack>("toolbar_stack");
	mChicletPanel = getChild<LLChicletPanel>("chiclet_list");

	showWellButton("im_well", !LLIMWellWindow::getInstance()->isWindowEmpty());
	showWellButton("notification_well", !LLNotificationWellWindow::getInstance()->isWindowEmpty());

	LLPanelTopInfoBar::instance().setResizeCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));
	LLPanelTopInfoBar::instance().setVisibleCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));

	return TRUE;
}

void LLChicletBar::showWellButton(const std::string& well_name, bool visible)
{
	LLView * panel = findChild<LLView>(well_name + "_panel");
	if (!panel)	return;

	panel->setVisible(visible);
}

void LLChicletBar::log(LLView* panel, const std::string& descr)
{
	if (NULL == panel) return;
	LLView* layout = panel->getParent();
	LL_DEBUGS("Chiclet Bar Rects") << descr << ": "
		<< "panel: " << panel->getName()
		<< ", rect: " << panel->getRect()
		<< " layout: " << layout->getName()
		<< ", rect: " << layout->getRect()
		<< LL_ENDL;
}

void LLChicletBar::reshape(S32 width, S32 height, BOOL called_from_parent)
{
	static S32 debug_calling_number = 0;
	lldebugs << "**************************************** " << ++debug_calling_number << llendl;

	S32 current_width = getRect().getWidth();
	S32 delta_width = width - current_width;
	lldebugs << "Reshaping: "
		<< ", width: " << width
		<< ", cur width: " << current_width
		<< ", delta_width: " << delta_width
		<< ", called_from_parent: " << called_from_parent
		<< llendl;

	if (mChicletPanel)			log(mChicletPanel, "before");

	// Difference between chiclet bar width required to fit its children and the actual width. (see EXT-991)
	// Positive value means that chiclet bar is not wide enough.
	// Negative value means that there is free space.
	static S32 extra_shrink_width = 0;
	bool should_be_reshaped = true;

	if (mChicletPanel && mToolbarStack)
	{
		// Firstly, update layout stack to ensure we deal with correct panel sizes.
		{
			BOOL saved_anim = mToolbarStack->getAnimate();
			// Set chiclet panel to be autoresized by default.
			mToolbarStack->updatePanelAutoResize(PANEL_CHICLET_NAME, TRUE);
			// Disable animation to prevent layout updating in several frames.
			mToolbarStack->setAnimate(FALSE);
			// Force the updating of layout to reset panels collapse factor.
			mToolbarStack->updateLayout();
			// Restore animate state.
			mToolbarStack->setAnimate(saved_anim);
		}

		// chiclet bar is narrowed
		if (delta_width < 0)
		{
			if (extra_shrink_width > 0) // not enough space
			{
				extra_shrink_width += llabs(delta_width);
				should_be_reshaped = false;
			}
			else
			{
				extra_shrink_width = processWidthDecreased(delta_width);

				// increase new width to extra_shrink_width value to not reshape less than chiclet bar minimum
				width += extra_shrink_width;
			}
		}
		// chiclet bar is widened
		else
		{
			if (extra_shrink_width > delta_width)
			{
				// Still not enough space.
				// Only subtract the delta from the required delta and don't reshape.
				extra_shrink_width -= delta_width;
				should_be_reshaped = false;
			}
			else if (extra_shrink_width > 0)
			{
				// If we have some extra shrink width let's reduce delta_width & width
				delta_width -= extra_shrink_width;
				width -= extra_shrink_width;
				extra_shrink_width = 0;
			}
		}
	}

	if (should_be_reshaped)
	{
		lldebugs << "Reshape all children with width: " << width << llendl;
		LLPanel::reshape(width, height, called_from_parent);
	}

	if (mChicletPanel)			log(mChicletPanel, "after");
}

S32 LLChicletBar::processWidthDecreased(S32 delta_width)
{
	bool still_should_be_processed = true;

	const S32 chiclet_panel_shrink_headroom = getChicletPanelShrinkHeadroom();

	// Decreasing width of chiclet panel.
	if (chiclet_panel_shrink_headroom > 0)
	{
		// we have some space to decrease chiclet panel
		S32 shrink_by = llmin(-delta_width, chiclet_panel_shrink_headroom);

		lldebugs << "delta_width: " << delta_width
			<< ", panel_delta_min: " << chiclet_panel_shrink_headroom
			<< ", shrink_by: " << shrink_by
			<< llendl;

		// is chiclet panel wide enough to process resizing?
		delta_width += chiclet_panel_shrink_headroom;

		still_should_be_processed = delta_width < 0;

		lldebugs << "Shrinking chiclet panel by " << shrink_by << " px" << llendl;
		mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - shrink_by, mChicletPanel->getParent()->getRect().getHeight());
		log(mChicletPanel, "after processing panel decreasing via chiclet panel");

		lldebugs << "RS_CHICLET_PANEL"
			<< ", delta_width: " << delta_width
			<< llendl;
	}

	S32 extra_shrink_width = 0;

	if (still_should_be_processed)
	{
		extra_shrink_width = -delta_width;
		llwarns << "There is no enough width to reshape all children: "
			<< extra_shrink_width << llendl;
	}

	return extra_shrink_width;
}

S32 LLChicletBar::getChicletPanelShrinkHeadroom() const
{
	static const S32 min_width = mChicletPanel->getMinWidth();
	const S32 cur_width = mChicletPanel->getParent()->getRect().getWidth();

	S32 shrink_headroom = cur_width - min_width;
	llassert(shrink_headroom >= 0); // the panel cannot get narrower than the minimum
	return shrink_headroom;
}

void LLChicletBar::fitWithTopInfoBar()
{
	LLPanelTopInfoBar& top_info_bar = LLPanelTopInfoBar::instance();

	LLRect rect = getRect();
	S32 width = rect.getWidth();

	if (top_info_bar.getVisible())
	{
		S32 delta = top_info_bar.calcScreenRect().mRight - calcScreenRect().mLeft;
		rect.setLeftTopAndSize(rect.mLeft + delta, rect.mTop, rect.getWidth(), rect.getHeight());
		width = rect.getWidth() - delta;
	}
	else
	{
		LLView* parent = getParent();
		if (parent)
		{
			LLRect parent_rect = parent->getRect();
			rect.setLeftTopAndSize(0, rect.mTop, rect.getWidth(), rect.getHeight());
			width = parent_rect.getWidth();
		}
	}

	setRect(rect);
	LLPanel::reshape(width, rect.getHeight(), false);
}
<commit_msg>EXP-1463 ADDITIONAL FIX (IM chiclets overlay Mini-Location bar)<commit_after>/**
 * @file llchicletbar.cpp
 * @brief LLChicletBar class implementation
 *
 * $LicenseInfo:firstyear=2011&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2011, Linden Research, Inc.
 *
 * 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;
 * version 2.1 of the License only.
 *
 * 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
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h" // must be first include

#include "llchicletbar.h"

// library includes
#include "llfloaterreg.h"
#include "lllayoutstack.h"

// newview includes
#include "llchiclet.h"
#include "llimfloater.h" // for LLIMFloater
#include "llpaneltopinfobar.h"
#include "llsyswellwindow.h"

namespace
{
	const std::string& PANEL_CHICLET_NAME	= "chiclet_list_panel";

	S32 get_panel_min_width(LLLayoutStack* stack, LLView* panel)
	{
		S32 minimal_width = 0;
		llassert(stack);
		if ( stack && panel && panel->getVisible() )
		{
			stack->getPanelMinSize(panel->getName(), &minimal_width);
		}
		return minimal_width;
	}

	S32 get_panel_max_width(LLLayoutStack* stack, LLPanel* panel)
	{
		S32 max_width = 0;
		llassert(stack);
		if ( stack && panel && panel->getVisible() )
		{
			stack->getPanelMaxSize(panel->getName(), &max_width);
		}
		return max_width;
	}

	S32 get_curr_width(LLUICtrl* ctrl)
	{
		S32 cur_width = 0;
		if ( ctrl && ctrl->getVisible() )
		{
			cur_width = ctrl->getRect().getWidth();
		}
		return cur_width;
	}
}

LLChicletBar::LLChicletBar(const LLSD&)
:	mChicletPanel(NULL),
	mToolbarStack(NULL)
{
	// Firstly add our self to IMSession observers, so we catch session events
	// before chiclets do that.
	LLIMMgr::getInstance()->addSessionObserver(this);

	buildFromFile("panel_chiclet_bar.xml");
}

LLChicletBar::~LLChicletBar()
{
	if (!LLSingleton<LLIMMgr>::destroyed())
	{
		LLIMMgr::getInstance()->removeSessionObserver(this);
	}
}

LLIMChiclet* LLChicletBar::createIMChiclet(const LLUUID& session_id)
{
	LLIMChiclet::EType im_chiclet_type = LLIMChiclet::getIMSessionType(session_id);

	switch (im_chiclet_type)
	{
	case LLIMChiclet::TYPE_IM:
		return getChicletPanel()->createChiclet<LLIMP2PChiclet>(session_id);
	case LLIMChiclet::TYPE_GROUP:
		return getChicletPanel()->createChiclet<LLIMGroupChiclet>(session_id);
	case LLIMChiclet::TYPE_AD_HOC:
		return getChicletPanel()->createChiclet<LLAdHocChiclet>(session_id);
	case LLIMChiclet::TYPE_UNKNOWN:
		break;
	}

	return NULL;
}

//virtual
void LLChicletBar::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id)
{
	if (!getChicletPanel()) return;

	LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id);
	if (!session) return;

	// no need to spawn chiclets for participants in P2P calls called through Avaline
	if (session->isP2P() && session->isOtherParticipantAvaline()) return;

	if (getChicletPanel()->findChiclet<LLChiclet>(session_id)) return;

	LLIMChiclet* chiclet = createIMChiclet(session_id);
	if(chiclet)
	{
		chiclet->setIMSessionName(name);
		chiclet->setOtherParticipantId(other_participant_id);

		LLIMFloater::onIMChicletCreated(session_id);

	}
	else
	{
		llwarns << "Could not create chiclet" << llendl;
	}
}

//virtual
void LLChicletBar::sessionRemoved(const LLUUID& session_id)
{
	if(getChicletPanel())
	{
		// IM floater should be closed when session removed and associated chiclet closed
		LLIMFloater* iMfloater = LLFloaterReg::findTypedInstance<LLIMFloater>("impanel", session_id);
		if (iMfloater != NULL)
		{
			iMfloater->closeFloater();
		}

		getChicletPanel()->removeChiclet(session_id);
	}
}

void LLChicletBar::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id)
{
	//this is only needed in case of outgoing ad-hoc/group chat sessions
	LLChicletPanel* chiclet_panel = getChicletPanel();
	if (chiclet_panel)
	{
		//it should be ad-hoc im chiclet or group im chiclet
		LLChiclet* chiclet = chiclet_panel->findChiclet<LLChiclet>(old_session_id);
		if (chiclet) chiclet->setSessionId(new_session_id);
	}
}

S32 LLChicletBar::getTotalUnreadIMCount()
{
	return getChicletPanel()->getTotalUnreadIMCount();
}

BOOL LLChicletBar::postBuild()
{
	mToolbarStack = getChild<LLLayoutStack>("toolbar_stack");
	mChicletPanel = getChild<LLChicletPanel>("chiclet_list");

	showWellButton("im_well", !LLIMWellWindow::getInstance()->isWindowEmpty());
	showWellButton("notification_well", !LLNotificationWellWindow::getInstance()->isWindowEmpty());

	LLPanelTopInfoBar::instance().setResizeCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));
	LLPanelTopInfoBar::instance().setVisibleCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));

	return TRUE;
}

void LLChicletBar::showWellButton(const std::string& well_name, bool visible)
{
	LLView * panel = findChild<LLView>(well_name + "_panel");
	if (!panel)	return;

	panel->setVisible(visible);
}

void LLChicletBar::log(LLView* panel, const std::string& descr)
{
	if (NULL == panel) return;
	LLView* layout = panel->getParent();
	LL_DEBUGS("Chiclet Bar Rects") << descr << ": "
		<< "panel: " << panel->getName()
		<< ", rect: " << panel->getRect()
		<< " layout: " << layout->getName()
		<< ", rect: " << layout->getRect()
		<< LL_ENDL;
}

void LLChicletBar::reshape(S32 width, S32 height, BOOL called_from_parent)
{
	static S32 debug_calling_number = 0;
	lldebugs << "**************************************** " << ++debug_calling_number << llendl;

	S32 current_width = getRect().getWidth();
	S32 delta_width = width - current_width;
	lldebugs << "Reshaping: "
		<< ", width: " << width
		<< ", cur width: " << current_width
		<< ", delta_width: " << delta_width
		<< ", called_from_parent: " << called_from_parent
		<< llendl;

	if (mChicletPanel)			log(mChicletPanel, "before");

	// Difference between chiclet bar width required to fit its children and the actual width. (see EXT-991)
	// Positive value means that chiclet bar is not wide enough.
	// Negative value means that there is free space.
	static S32 extra_shrink_width = 0;
	bool should_be_reshaped = true;

	if (mChicletPanel && mToolbarStack)
	{
		// Firstly, update layout stack to ensure we deal with correct panel sizes.
		{
			BOOL saved_anim = mToolbarStack->getAnimate();
			// Set chiclet panel to be autoresized by default.
			mToolbarStack->updatePanelAutoResize(PANEL_CHICLET_NAME, TRUE);
			// Disable animation to prevent layout updating in several frames.
			mToolbarStack->setAnimate(FALSE);
			// Force the updating of layout to reset panels collapse factor.
			mToolbarStack->updateLayout();
			// Restore animate state.
			mToolbarStack->setAnimate(saved_anim);
		}

		// chiclet bar is narrowed
		if (delta_width < 0)
		{
			if (extra_shrink_width > 0) // not enough space
			{
				extra_shrink_width += llabs(delta_width);
				should_be_reshaped = false;
			}
			else
			{
				extra_shrink_width = processWidthDecreased(delta_width);

				// increase new width to extra_shrink_width value to not reshape less than chiclet bar minimum
				width += extra_shrink_width;
			}
		}
		// chiclet bar is widened
		else
		{
			if (extra_shrink_width > delta_width)
			{
				// Still not enough space.
				// Only subtract the delta from the required delta and don't reshape.
				extra_shrink_width -= delta_width;
				should_be_reshaped = false;
			}
			else if (extra_shrink_width > 0)
			{
				// If we have some extra shrink width let's reduce delta_width & width
				delta_width -= extra_shrink_width;
				width -= extra_shrink_width;
				extra_shrink_width = 0;
			}
		}
	}

	if (should_be_reshaped)
	{
		lldebugs << "Reshape all children with width: " << width << llendl;
		LLPanel::reshape(width, height, called_from_parent);
	}

	if (mChicletPanel)			log(mChicletPanel, "after");
}

S32 LLChicletBar::processWidthDecreased(S32 delta_width)
{
	bool still_should_be_processed = true;

	const S32 chiclet_panel_shrink_headroom = getChicletPanelShrinkHeadroom();

	// Decreasing width of chiclet panel.
	if (chiclet_panel_shrink_headroom > 0)
	{
		// we have some space to decrease chiclet panel
		S32 shrink_by = llmin(-delta_width, chiclet_panel_shrink_headroom);

		lldebugs << "delta_width: " << delta_width
			<< ", panel_delta_min: " << chiclet_panel_shrink_headroom
			<< ", shrink_by: " << shrink_by
			<< llendl;

		// is chiclet panel wide enough to process resizing?
		delta_width += chiclet_panel_shrink_headroom;

		still_should_be_processed = delta_width < 0;

		lldebugs << "Shrinking chiclet panel by " << shrink_by << " px" << llendl;
		mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - shrink_by, mChicletPanel->getParent()->getRect().getHeight());
		log(mChicletPanel, "after processing panel decreasing via chiclet panel");

		lldebugs << "RS_CHICLET_PANEL"
			<< ", delta_width: " << delta_width
			<< llendl;
	}

	S32 extra_shrink_width = 0;

	if (still_should_be_processed)
	{
		extra_shrink_width = -delta_width;
		llwarns << "There is no enough width to reshape all children: "
			<< extra_shrink_width << llendl;
	}

	return extra_shrink_width;
}

S32 LLChicletBar::getChicletPanelShrinkHeadroom() const
{
	static const S32 min_width = mChicletPanel->getMinWidth();
	const S32 cur_width = mChicletPanel->getParent()->getRect().getWidth();

	S32 shrink_headroom = cur_width - min_width;
	llassert(shrink_headroom >= 0); // the panel cannot get narrower than the minimum
	return shrink_headroom;
}

void LLChicletBar::fitWithTopInfoBar()
{
	LLPanelTopInfoBar& top_info_bar = LLPanelTopInfoBar::instance();

	LLRect rect = getRect();
	S32 width = rect.getWidth();

	if (top_info_bar.getVisible())
	{
		S32 delta = top_info_bar.calcScreenRect().mRight - calcScreenRect().mLeft;
		if (delta < 0 && rect.mLeft < llabs(delta))
			delta = -rect.mLeft;
		rect.setLeftTopAndSize(rect.mLeft + delta, rect.mTop, rect.getWidth(), rect.getHeight());
		width = rect.getWidth() - delta;
	}
	else
	{
		LLView* parent = getParent();
		if (parent)
		{
			LLRect parent_rect = parent->getRect();
			rect.setLeftTopAndSize(0, rect.mTop, rect.getWidth(), rect.getHeight());
			width = parent_rect.getWidth();
		}
	}

	setRect(rect);
	LLPanel::reshape(width, rect.getHeight(), false);
}
<|endoftext|>


<commit_before>/**
 * @file llfloatertos.cpp
 * @brief Terms of Service Agreement dialog
 *
 * $LicenseInfo:firstyear=2003&license=viewergpl$
 *
 * Copyright (c) 2003-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llfloatertos.h"

// viewer includes
#include "llviewerstats.h"
#include "llviewerwindow.h"

// linden library includes
#include "llbutton.h"
#include "llhttpclient.h"
#include "llhttpstatuscodes.h"	// for HTTP_FOUND
#include "llradiogroup.h"
#include "lltextbox.h"
#include "llui.h"
#include "lluictrlfactory.h"
#include "llvfile.h"
#include "message.h"

LLFloaterTOS::LLFloaterTOS(const LLSD& data)
:	LLModalDialog( data["message"].asString() ),
	mMessage(data["message"].asString()),
	mWebBrowserWindowId( 0 ),
	mLoadCompleteCount( 0 ),
	mReplyPumpName(data["reply_pump"].asString())
{
}

// helper class that trys to download a URL from a web site and calls a method
// on parent class indicating if the web server is working or not
class LLIamHere : public LLHTTPClient::Responder
{
	private:
		LLIamHere( LLFloaterTOS* parent ) :
		   mParent( parent )
		{}

		LLFloaterTOS* mParent;

	public:

		static boost::intrusive_ptr< LLIamHere > build( LLFloaterTOS* parent )
		{
			return boost::intrusive_ptr< LLIamHere >( new LLIamHere( parent ) );
		};

		virtual void  setParent( LLFloaterTOS* parentIn )
		{
			mParent = parentIn;
		};

		virtual void result( const LLSD& content )
		{
			if ( mParent )
				mParent->setSiteIsAlive( true );
		};

		virtual void error( U32 status, const std::string& reason )
		{
			if ( mParent )
			{
				// *HACK: For purposes of this alive check, 302 Found
				// (aka Moved Temporarily) is considered alive.  The web site
				// redirects this link to a "cache busting" temporary URL. JC
				bool alive = (status == HTTP_FOUND);
				mParent->setSiteIsAlive( alive );
			}
		};
};

// this is global and not a class member to keep crud out of the header file
namespace {
	boost::intrusive_ptr< LLIamHere > gResponsePtr = 0;
};

BOOL LLFloaterTOS::postBuild()
{
	childSetAction("Continue", onContinue, this);
	childSetAction("Cancel", onCancel, this);
	childSetCommitCallback("agree_chk", updateAgree, this);

	if (hasChild("tos_text"))
	{
		// this displays the critical message
		LLUICtrl *tos_text = getChild<LLUICtrl>("tos_text");
		tos_text->setEnabled( FALSE );
		tos_text->setFocus(TRUE);
		tos_text->setValue(LLSD(mMessage));

		return TRUE;
	}

	// disable Agree to TOS radio button until the page has fully loaded
	LLCheckBoxCtrl* tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk");
	tos_agreement->setEnabled( false );

	// hide the SL text widget if we're displaying TOS with using a browser widget.
	LLUICtrl *editor = getChild<LLUICtrl>("tos_text");
	editor->setVisible( FALSE );

	LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("tos_html");
	if ( web_browser )
	{
		web_browser->addObserver(this);
		gResponsePtr = LLIamHere::build( this );
		LLHTTPClient::get( getString( "real_url" ), gResponsePtr );
	}

	return TRUE;
}

void LLFloaterTOS::setSiteIsAlive( bool alive )
{
	// only do this for TOS pages
	if (hasChild("tos_html"))
	{
		LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("tos_html");
		// if the contents of the site was retrieved
		if ( alive )
		{
			// navigate to the "real" page
			web_browser->navigateTo( getString( "real_url" ) );
		}
		else
		{
			// normally this is set when navigation to TOS page navigation completes (so you can't accept before TOS loads)
			// but if the page is unavailable, we need to do this now
			LLCheckBoxCtrl* tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk");
			tos_agreement->setEnabled( true );
		}
	}
}

LLFloaterTOS::~LLFloaterTOS()
{

	// tell the responder we're not here anymore
	if ( gResponsePtr )
		gResponsePtr->setParent( 0 );
}

// virtual
void LLFloaterTOS::draw()
{
	// draw children
	LLModalDialog::draw();
}

// static
void LLFloaterTOS::updateAgree(LLUICtrl*, void* userdata )
{
	LLFloaterTOS* self = (LLFloaterTOS*) userdata;
	bool agree = self->childGetValue("agree_chk").asBoolean();
	self->childSetEnabled("Continue", agree);
}

// static
void LLFloaterTOS::onContinue( void* userdata )
{
	LLFloaterTOS* self = (LLFloaterTOS*) userdata;
	llinfos << "User agrees with TOS." << llendl;

	if(self->mReplyPumpName != "")
	{
		LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD(true));
	}

	self->closeFloater(); // destroys this object
}

// static
void LLFloaterTOS::onCancel( void* userdata )
{
	LLFloaterTOS* self = (LLFloaterTOS*) userdata;
	llinfos << "User disagrees with TOS." << llendl;

	if(self->mReplyPumpName != "")
	{
		LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD(false));
	}

	self->mLoadCompleteCount = 0;  // reset counter for next time we come to TOS
	self->closeFloater(); // destroys this object
}

//virtual
void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event)
{
	if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
	{
		// skip past the loading screen navigate complete
		if ( ++mLoadCompleteCount == 2 )
		{
			llinfos << "NAVIGATE COMPLETE" << llendl;
			// enable Agree to TOS radio button now that page has loaded
			LLCheckBoxCtrl * tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk");
			tos_agreement->setEnabled( true );
		}
	}
}

<commit_msg>QAR-1619: Reconcile LLFloaterTOS::onCancel() with viewer-2 version. The viewer-2 onCancel() pops up a "MustAgreeToLogIn" notification. Make ours do the same.<commit_after>/**
 * @file llfloatertos.cpp
 * @brief Terms of Service Agreement dialog
 *
 * $LicenseInfo:firstyear=2003&license=viewergpl$
 *
 * Copyright (c) 2003-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llfloatertos.h"

// viewer includes
#include "llviewerstats.h"
#include "llviewerwindow.h"

// linden library includes
#include "llbutton.h"
#include "llhttpclient.h"
#include "llhttpstatuscodes.h"	// for HTTP_FOUND
#include "llradiogroup.h"
#include "lltextbox.h"
#include "llui.h"
#include "lluictrlfactory.h"
#include "llvfile.h"
#include "message.h"
#include "llstartup.h"              // login_alert_done

LLFloaterTOS::LLFloaterTOS(const LLSD& data)
:	LLModalDialog( data["message"].asString() ),
	mMessage(data["message"].asString()),
	mWebBrowserWindowId( 0 ),
	mLoadCompleteCount( 0 ),
	mReplyPumpName(data["reply_pump"].asString())
{
}

// helper class that trys to download a URL from a web site and calls a method
// on parent class indicating if the web server is working or not
class LLIamHere : public LLHTTPClient::Responder
{
	private:
		LLIamHere( LLFloaterTOS* parent ) :
		   mParent( parent )
		{}

		LLFloaterTOS* mParent;

	public:

		static boost::intrusive_ptr< LLIamHere > build( LLFloaterTOS* parent )
		{
			return boost::intrusive_ptr< LLIamHere >( new LLIamHere( parent ) );
		};

		virtual void  setParent( LLFloaterTOS* parentIn )
		{
			mParent = parentIn;
		};

		virtual void result( const LLSD& content )
		{
			if ( mParent )
				mParent->setSiteIsAlive( true );
		};

		virtual void error( U32 status, const std::string& reason )
		{
			if ( mParent )
			{
				// *HACK: For purposes of this alive check, 302 Found
				// (aka Moved Temporarily) is considered alive.  The web site
				// redirects this link to a "cache busting" temporary URL. JC
				bool alive = (status == HTTP_FOUND);
				mParent->setSiteIsAlive( alive );
			}
		};
};

// this is global and not a class member to keep crud out of the header file
namespace {
	boost::intrusive_ptr< LLIamHere > gResponsePtr = 0;
};

BOOL LLFloaterTOS::postBuild()
{
	childSetAction("Continue", onContinue, this);
	childSetAction("Cancel", onCancel, this);
	childSetCommitCallback("agree_chk", updateAgree, this);

	if (hasChild("tos_text"))
	{
		// this displays the critical message
		LLUICtrl *tos_text = getChild<LLUICtrl>("tos_text");
		tos_text->setEnabled( FALSE );
		tos_text->setFocus(TRUE);
		tos_text->setValue(LLSD(mMessage));

		return TRUE;
	}

	// disable Agree to TOS radio button until the page has fully loaded
	LLCheckBoxCtrl* tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk");
	tos_agreement->setEnabled( false );

	// hide the SL text widget if we're displaying TOS with using a browser widget.
	LLUICtrl *editor = getChild<LLUICtrl>("tos_text");
	editor->setVisible( FALSE );

	LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("tos_html");
	if ( web_browser )
	{
		web_browser->addObserver(this);
		gResponsePtr = LLIamHere::build( this );
		LLHTTPClient::get( getString( "real_url" ), gResponsePtr );
	}

	return TRUE;
}

void LLFloaterTOS::setSiteIsAlive( bool alive )
{
	// only do this for TOS pages
	if (hasChild("tos_html"))
	{
		LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("tos_html");
		// if the contents of the site was retrieved
		if ( alive )
		{
			// navigate to the "real" page
			web_browser->navigateTo( getString( "real_url" ) );
		}
		else
		{
			// normally this is set when navigation to TOS page navigation completes (so you can't accept before TOS loads)
			// but if the page is unavailable, we need to do this now
			LLCheckBoxCtrl* tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk");
			tos_agreement->setEnabled( true );
		}
	}
}

LLFloaterTOS::~LLFloaterTOS()
{

	// tell the responder we're not here anymore
	if ( gResponsePtr )
		gResponsePtr->setParent( 0 );
}

// virtual
void LLFloaterTOS::draw()
{
	// draw children
	LLModalDialog::draw();
}

// static
void LLFloaterTOS::updateAgree(LLUICtrl*, void* userdata )
{
	LLFloaterTOS* self = (LLFloaterTOS*) userdata;
	bool agree = self->childGetValue("agree_chk").asBoolean();
	self->childSetEnabled("Continue", agree);
}

// static
void LLFloaterTOS::onContinue( void* userdata )
{
	LLFloaterTOS* self = (LLFloaterTOS*) userdata;
	llinfos << "User agrees with TOS." << llendl;

	if(self->mReplyPumpName != "")
	{
		LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD(true));
	}

	self->closeFloater(); // destroys this object
}

// static
void LLFloaterTOS::onCancel( void* userdata )
{
	LLFloaterTOS* self = (LLFloaterTOS*) userdata;
	llinfos << "User disagrees with TOS." << llendl;
	LLNotifications::instance().add("MustAgreeToLogIn", LLSD(), LLSD(), login_alert_done);

	if(self->mReplyPumpName != "")
	{
		LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD(false));
	}

	self->mLoadCompleteCount = 0;  // reset counter for next time we come to TOS
	self->closeFloater(); // destroys this object
}

//virtual
void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event)
{
	if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
	{
		// skip past the loading screen navigate complete
		if ( ++mLoadCompleteCount == 2 )
		{
			llinfos << "NAVIGATE COMPLETE" << llendl;
			// enable Agree to TOS radio button now that page has loaded
			LLCheckBoxCtrl * tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk");
			tos_agreement->setEnabled( true );
		}
	}
}

<|endoftext|>


<commit_before>

/**

  Read one value from a modbus device

  @param[out]  value		the value read, cast to an integer
  @param[in]   device_var	the modbus device address
  @param[in]   address		the offset of the value to be read in the device
  @param[in]   retry_times	the number of times to retry on read failure before giving up

  @return  0 if there were no errors

  This does NOT lock the register_critical_section

  */
int modbus_read_one_value(
				int& value,
				unsigned char device_var,
				unsigned short address,
				int retry_times )
{

	BOOL EnableRefreshTreeView_original_value = g_bEnableRefreshTreeView;

	/** This will prevent a refresh of the tree view while we are doing the read
	 It seems to be a sort of home made mutex.
	 There are all sorts of probems with this, including the fact that the tree refresh
	 is abandoned, not just delayed.
	 But it is used in over 40 places in the rest of the code, so leave it alone
	 */
	g_bEnableRefreshTreeView = false;

	// clear the value read from the device
	value = 0;

	// clear the error return flag
	int error_ret = 0;

	// clear the value/error flag from the modbus DLL
	int j = 0;

	// loop over number of retries requested
	for(int i=0;i<retry_times;i++)
	{
		// ensure no other threads attempt to access modbus communications
		CSingleLock singleLock(&register_critical_section);
		singleLock.Lock();

		// call the modbus DLL method
		j=Read_One(device_var,address);

		// free the modbus communications for other threads
		singleLock.Unlock();

		// increment the number of transmissions we have done
		g_llTxCount++;

		// check for no connection error
		if( j == -1 ) {

			error_ret = j;

			// give up
			break;
		}

		// check for other errors
		if ( j == -2 || j == -3 ) {

			error_ret = j;

			// try again, if more retries available
			continue;
		}

		// increment the number or replies we have received
		g_llRxCount++;

		// set value that we received
		value = (int) j;

		// we have a good value, so no need to try again
		break;

	}

	// Special handling for a particular address  101
	// ( This probably should not be done here!
	// Presumably it is done because the old version
	// returned a negative value as an error flag
	// and it was neccessary to elude that check )
	if( address == 101 ) {
		if( value > 32767) {
			// assume this is a temperature below zero
			value = 0 - 65535 + value;
		}
	}

	// check for running in the main GUI thread
	if( AfxGetMainWnd()->GetActiveWindow() != NULL ) {

		// construct status message string
		CString str;
		str.Format(_T("Addr:%d [Tx=%d Rx=%d Err=%d]"),
			device_var, g_llTxCount, g_llRxCount, g_llTxCount-g_llRxCount);

		//Display it
		((CMFCStatusBar *) AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR))->SetPaneText(0,str.GetString());

	}

	/**  Restore original value of tree refresh flag

	Note that we do an OR here, so if the flag has been set true somewhere else
	then we will not set it false if it was false when we started.

	*/
	g_bEnableRefreshTreeView |= EnableRefreshTreeView_original_value;

	return error_ret;

}

/**

  Read multiple values from a modbus device

  @param[out]  put_data_into_here	the values read
  @param[in]   device_var			the modbus device address
  @param[in]   start_address		the offset of thefirt value to be read in the device
  @param[in]   length				number of values to be read
  @param[in]   retry_times			the number of times to retry on read failure before giving up

  @return  negative if there were errors, otherwise length of data read

  This does NOT lock the register_critical_section

  */
int modbus_read_multi_value(
		unsigned short *put_data_into_here,
		unsigned char device_var,
		unsigned short start_address,
		int length,
		int retry_times )
{
	BOOL EnableRefreshTreeView_original_value = g_bEnableRefreshTreeView;

	/** This will prevent a refresh of the tree view while we are doing the read
	 It seems to be a sort of home made mutex.
	 There are all sorts of probems with this, including the fact that the tree refresh
	 is abandoned, not just delayed.
	 But it is used in over 40 places in the rest of the code, so leave it alone
	 */
	g_bEnableRefreshTreeView = false;

	int error=0;
	for(int i=0;i<retry_times;i++)
	{

		// call the modbus DLL method
		error=read_multi(device_var,put_data_into_here,start_address,length);

		// increment the number of transmissions we have done
		g_llTxCount++;

		// accept any return other than -2
		if( error !=-2 )
		{
			// increment the number or replies we have received
			g_llRxCount++;
			break;
		}
	}

	// check for running in the main GUI thread
	if( AfxGetMainWnd()->GetActiveWindow() != NULL ) {

		// construct status message string
		CString str;
		str.Format(_T("Addr:%d [Tx=%d Rx=%d Err=%d]"),
			device_var, g_llTxCount, g_llRxCount, g_llTxCount-g_llRxCount);

		//Display it
		((CMFCStatusBar *) AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR))->SetPaneText(0,str.GetString());

	}

	/**  Restore original value of tree refresh flag

	Note that we do an OR here, so if the flag has been set true somewhere else
	then we will not set it false if it was false when we started.

	*/
	g_bEnableRefreshTreeView |= EnableRefreshTreeView_original_value;

	return error;
}
<commit_msg>Fix documentation mistake<commit_after>

/**

  Read one value from a modbus device

  @param[out]  value		the value read, cast to an integer
  @param[in]   device_var	the modbus device address
  @param[in]   address		the offset of the value to be read in the device
  @param[in]   retry_times	the number of times to retry on read failure before giving up

  @return  0 if there were no errors

  This DOES lock the register_critical_section

  */
int modbus_read_one_value(
				int& value,
				unsigned char device_var,
				unsigned short address,
				int retry_times )
{

	BOOL EnableRefreshTreeView_original_value = g_bEnableRefreshTreeView;

	/** This will prevent a refresh of the tree view while we are doing the read
	 It seems to be a sort of home made mutex.
	 There are all sorts of probems with this, including the fact that the tree refresh
	 is abandoned, not just delayed.
	 But it is used in over 40 places in the rest of the code, so leave it alone
	 */
	g_bEnableRefreshTreeView = false;

	// clear the value read from the device
	value = 0;

	// clear the error return flag
	int error_ret = 0;

	// clear the value/error flag from the modbus DLL
	int j = 0;

	// loop over number of retries requested
	for(int i=0;i<retry_times;i++)
	{
		// ensure no other threads attempt to access modbus communications
		CSingleLock singleLock(&register_critical_section);
		singleLock.Lock();

		// call the modbus DLL method
		j=Read_One(device_var,address);

		// free the modbus communications for other threads
		singleLock.Unlock();

		// increment the number of transmissions we have done
		g_llTxCount++;

		// check for no connection error
		if( j == -1 ) {

			error_ret = j;

			// give up
			break;
		}

		// check for other errors
		if ( j == -2 || j == -3 ) {

			error_ret = j;

			// try again, if more retries available
			continue;
		}

		// increment the number or replies we have received
		g_llRxCount++;

		// set value that we received
		value = (int) j;

		// we have a good value, so no need to try again
		break;

	}

	// Special handling for a particular address  101
	// ( This probably should not be done here!
	// Presumably it is done because the old version
	// returned a negative value as an error flag
	// and it was neccessary to elude that check )
	if( address == 101 ) {
		if( value > 32767) {
			// assume this is a temperature below zero
			value = 0 - 65535 + value;
		}
	}

	// check for running in the main GUI thread
	if( AfxGetMainWnd()->GetActiveWindow() != NULL ) {

		// construct status message string
		CString str;
		str.Format(_T("Addr:%d [Tx=%d Rx=%d Err=%d]"),
			device_var, g_llTxCount, g_llRxCount, g_llTxCount-g_llRxCount);

		//Display it
		((CMFCStatusBar *) AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR))->SetPaneText(0,str.GetString());

	}

	/**  Restore original value of tree refresh flag

	Note that we do an OR here, so if the flag has been set true somewhere else
	then we will not set it false if it was false when we started.

	*/
	g_bEnableRefreshTreeView |= EnableRefreshTreeView_original_value;

	return error_ret;

}

/**

  Read multiple values from a modbus device

  @param[out]  put_data_into_here	the values read
  @param[in]   device_var			the modbus device address
  @param[in]   start_address		the offset of thefirt value to be read in the device
  @param[in]   length				number of values to be read
  @param[in]   retry_times			the number of times to retry on read failure before giving up

  @return  negative if there were errors, otherwise length of data read

  This does NOT lock the register_critical_section

  */
int modbus_read_multi_value(
		unsigned short *put_data_into_here,
		unsigned char device_var,
		unsigned short start_address,
		int length,
		int retry_times )
{
	BOOL EnableRefreshTreeView_original_value = g_bEnableRefreshTreeView;

	/** This will prevent a refresh of the tree view while we are doing the read
	 It seems to be a sort of home made mutex.
	 There are all sorts of probems with this, including the fact that the tree refresh
	 is abandoned, not just delayed.
	 But it is used in over 40 places in the rest of the code, so leave it alone
	 */
	g_bEnableRefreshTreeView = false;

	int error=0;
	for(int i=0;i<retry_times;i++)
	{

		// call the modbus DLL method
		error=read_multi(device_var,put_data_into_here,start_address,length);

		// increment the number of transmissions we have done
		g_llTxCount++;

		// accept any return other than -2
		if( error !=-2 )
		{
			// increment the number or replies we have received
			g_llRxCount++;
			break;
		}
	}

	// check for running in the main GUI thread
	if( AfxGetMainWnd()->GetActiveWindow() != NULL ) {

		// construct status message string
		CString str;
		str.Format(_T("Addr:%d [Tx=%d Rx=%d Err=%d]"),
			device_var, g_llTxCount, g_llRxCount, g_llTxCount-g_llRxCount);

		//Display it
		((CMFCStatusBar *) AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR))->SetPaneText(0,str.GetString());

	}

	/**  Restore original value of tree refresh flag

	Note that we do an OR here, so if the flag has been set true somewhere else
	then we will not set it false if it was false when we started.

	*/
	g_bEnableRefreshTreeView |= EnableRefreshTreeView_original_value;

	return error;
}
<|endoftext|>


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

#if !DEVICE_RTC
    #error [NOT_SUPPORTED] RTC API not supported for this target
#endif

#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "rtc_test.h"

#include "mbed.h"
#include "rtc_api.h"

using namespace utest::v1;

static const uint32_t WAIT_TIME = 4;
static const uint32_t WAIT_TOLERANCE = 1;

#define US_PER_SEC 1000000
#define ACCURACY_FACTOR 10

static const uint32_t DELAY_4S = 4;
static const uint32_t DELAY_10S = 10;
static const uint32_t RTC_TOLERANCE = 1;
static const uint32_t TOLERANCE_ACCURACY_US = (DELAY_10S * US_PER_SEC / ACCURACY_FACTOR);

#if DEVICE_LOWPOWERTIMER
volatile bool expired;

void callback(void)
{
    expired = true;
}

/* Auxiliary function to test if RTC continue counting in
 * sleep and deep-sleep modes. */
void rtc_sleep_test_support (bool deepsleep_mode)
{
    LowPowerTimeout timeout;
    const uint32_t start = 100;
    expired = false;

    /*
     * Since deepsleep() may shut down the UART peripheral, we wait for 10ms
     * to allow for hardware serial buffers to completely flush.
     * This should be replaced with a better function that checks if the
     * hardware buffers are empty. However, such an API does not exist now,
     * so we'll use the wait_ms() function for now.
     */
    wait_ms(10);

    rtc_init();

    if(deepsleep_mode == false) {
        sleep_manager_lock_deep_sleep();
    }

    rtc_write(start);

    timeout.attach(callback, DELAY_4S);

    TEST_ASSERT(sleep_manager_can_deep_sleep() == deepsleep_mode);

    while(!expired) sleep();

    const uint32_t stop = rtc_read();

    TEST_ASSERT_UINT32_WITHIN(RTC_TOLERANCE, DELAY_4S, stop - start);

    timeout.detach();

    if(deepsleep_mode == false) {
        sleep_manager_unlock_deep_sleep();
    }

    rtc_free();
}
#endif

/* Test that ::rtc_init can be called multiple times. */
void rtc_init_test()
{
    for (int i = 0; i < 10; i++) {
        rtc_init();
    }

    rtc_free();
}

#if DEVICE_LOWPOWERTIMER
/** Test that the RTC keeps counting in the various sleep modes. */

void rtc_sleep_test()
{
    /* Test sleep mode. */
    rtc_sleep_test_support(false);

    /* Test deep-sleep mode. */
    rtc_sleep_test_support(true);
}
#endif

/* Test that the RTC keeps counting even after ::rtc_free has been called. */
void rtc_persist_test()
{
    const uint32_t start = 100;
    rtc_init();
    rtc_write(start);
    rtc_free();

    wait(WAIT_TIME);

    rtc_init();
    const uint32_t stop = rtc_read();
    const int enabled = rtc_isenabled();
    rtc_free();

    TEST_ASSERT_TRUE(enabled);
    TEST_ASSERT_UINT32_WITHIN(WAIT_TOLERANCE, WAIT_TIME, stop - start);
}

/* Test time does not glitch backwards due to an incorrectly implemented ripple counter driver. */
void rtc_glitch_test()
{
    const uint32_t start = 0xffffe;
    rtc_init();

    rtc_write(start);
    uint32_t last = start;
    while (last < start + 4) {
        const uint32_t cur = rtc_read();
        TEST_ASSERT(cur >= last);
        last = cur;
    }

    rtc_free();
}

/* Test that the RTC correctly handles different time values. */
void rtc_range_test()
{
    static const uint32_t starts[] = {
            0x00000000,
            0xEFFFFFFF,
            0x00001000,
            0x00010000,
    };

    rtc_init();
    for (uint32_t i = 0; i < sizeof(starts) / sizeof(starts[0]); i++) {
        const uint32_t start = starts[i];
        rtc_write(start);
        wait(WAIT_TIME);
        const uint32_t stop = rtc_read();
        TEST_ASSERT_UINT32_WITHIN(WAIT_TOLERANCE, WAIT_TIME, stop - start);
    }
    rtc_free();
}

/* Test that the RTC accuracy is at least 10%. */
void rtc_accuracy_test()
{
    Timer timer1;

    const uint32_t start = 100;
    rtc_init();
    rtc_write(start);

    timer1.start();
    while(rtc_read() < (start + DELAY_10S)) {
        /* Just wait. */
    }
    timer1.stop();

    /* RTC accuracy is at least 10%. */
    TEST_ASSERT_INT32_WITHIN(TOLERANCE_ACCURACY_US, DELAY_10S * US_PER_SEC, timer1.read_us());
}

/* Test that ::rtc_write/::rtc_read functions provides availability to set/get RTC time. */
void rtc_write_read_test()
{
    static const uint32_t rtc_init_val = 100;

    rtc_init();

    for (int i = 0; i < 3; i++) {
        const uint32_t init_val = (rtc_init_val + i * rtc_init_val);

        core_util_critical_section_enter();

        rtc_write(init_val);
        const uint32_t read_val = rtc_read();

        core_util_critical_section_exit();

        /* No tolerance is provided since we should have 1 second to
         * execute this case after the RTC time is set.
         */
        TEST_ASSERT_EQUAL_UINT32(init_val, read_val);
    }

    rtc_free();
}

/* Test that ::is_enabled function returns 1 if the RTC is counting and the time has been set, 0 otherwise. */
void rtc_enabled_test()
{
    rtc_init();
    TEST_ASSERT_EQUAL_INT(0, rtc_isenabled());
    rtc_write(0);
    TEST_ASSERT_EQUAL_INT(1, rtc_isenabled());
    rtc_free();
}

Case cases[] = {
    Case("RTC - init", rtc_init_test),
#if DEVICE_LOWPOWERTIMER
    Case("RTC - sleep", rtc_sleep_test),
#endif
    Case("RTC - persist", rtc_persist_test),
    Case("RTC - glitch", rtc_glitch_test),
    Case("RTC - range", rtc_range_test),
    Case("RTC - accuracy", rtc_accuracy_test),
    Case("RTC - write/read", rtc_write_read_test),
    Case("RTC - enabled", rtc_enabled_test),
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
    GREENTEA_SETUP(30, "default_auto");
    return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main()
{
    Harness::run(specification);
}
<commit_msg>HAL rtc test: check only if rtc_isenabled() returns 1 in case when init is done.<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2017 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#if !DEVICE_RTC
    #error [NOT_SUPPORTED] RTC API not supported for this target
#endif

#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "rtc_test.h"

#include "mbed.h"
#include "rtc_api.h"

using namespace utest::v1;

static const uint32_t WAIT_TIME = 4;
static const uint32_t WAIT_TOLERANCE = 1;

#define US_PER_SEC 1000000
#define ACCURACY_FACTOR 10

static const uint32_t DELAY_4S = 4;
static const uint32_t DELAY_10S = 10;
static const uint32_t RTC_TOLERANCE = 1;
static const uint32_t TOLERANCE_ACCURACY_US = (DELAY_10S * US_PER_SEC / ACCURACY_FACTOR);

#if DEVICE_LOWPOWERTIMER
volatile bool expired;

void callback(void)
{
    expired = true;
}

/* Auxiliary function to test if RTC continue counting in
 * sleep and deep-sleep modes. */
void rtc_sleep_test_support (bool deepsleep_mode)
{
    LowPowerTimeout timeout;
    const uint32_t start = 100;
    expired = false;

    /*
     * Since deepsleep() may shut down the UART peripheral, we wait for 10ms
     * to allow for hardware serial buffers to completely flush.
     * This should be replaced with a better function that checks if the
     * hardware buffers are empty. However, such an API does not exist now,
     * so we'll use the wait_ms() function for now.
     */
    wait_ms(10);

    rtc_init();

    if(deepsleep_mode == false) {
        sleep_manager_lock_deep_sleep();
    }

    rtc_write(start);

    timeout.attach(callback, DELAY_4S);

    TEST_ASSERT(sleep_manager_can_deep_sleep() == deepsleep_mode);

    while(!expired) sleep();

    const uint32_t stop = rtc_read();

    TEST_ASSERT_UINT32_WITHIN(RTC_TOLERANCE, DELAY_4S, stop - start);

    timeout.detach();

    if(deepsleep_mode == false) {
        sleep_manager_unlock_deep_sleep();
    }

    rtc_free();
}
#endif

/* Test that ::rtc_init can be called multiple times. */
void rtc_init_test()
{
    for (int i = 0; i < 10; i++) {
        rtc_init();
    }

    rtc_free();
}

#if DEVICE_LOWPOWERTIMER
/** Test that the RTC keeps counting in the various sleep modes. */

void rtc_sleep_test()
{
    /* Test sleep mode. */
    rtc_sleep_test_support(false);

    /* Test deep-sleep mode. */
    rtc_sleep_test_support(true);
}
#endif

/* Test that the RTC keeps counting even after ::rtc_free has been called. */
void rtc_persist_test()
{
    const uint32_t start = 100;
    rtc_init();
    rtc_write(start);
    rtc_free();

    wait(WAIT_TIME);

    rtc_init();
    const uint32_t stop = rtc_read();
    const int enabled = rtc_isenabled();
    rtc_free();

    TEST_ASSERT_TRUE(enabled);
    TEST_ASSERT_UINT32_WITHIN(WAIT_TOLERANCE, WAIT_TIME, stop - start);
}

/* Test time does not glitch backwards due to an incorrectly implemented ripple counter driver. */
void rtc_glitch_test()
{
    const uint32_t start = 0xffffe;
    rtc_init();

    rtc_write(start);
    uint32_t last = start;
    while (last < start + 4) {
        const uint32_t cur = rtc_read();
        TEST_ASSERT(cur >= last);
        last = cur;
    }

    rtc_free();
}

/* Test that the RTC correctly handles different time values. */
void rtc_range_test()
{
    static const uint32_t starts[] = {
            0x00000000,
            0xEFFFFFFF,
            0x00001000,
            0x00010000,
    };

    rtc_init();
    for (uint32_t i = 0; i < sizeof(starts) / sizeof(starts[0]); i++) {
        const uint32_t start = starts[i];
        rtc_write(start);
        wait(WAIT_TIME);
        const uint32_t stop = rtc_read();
        TEST_ASSERT_UINT32_WITHIN(WAIT_TOLERANCE, WAIT_TIME, stop - start);
    }
    rtc_free();
}

/* Test that the RTC accuracy is at least 10%. */
void rtc_accuracy_test()
{
    Timer timer1;

    const uint32_t start = 100;
    rtc_init();
    rtc_write(start);

    timer1.start();
    while(rtc_read() < (start + DELAY_10S)) {
        /* Just wait. */
    }
    timer1.stop();

    /* RTC accuracy is at least 10%. */
    TEST_ASSERT_INT32_WITHIN(TOLERANCE_ACCURACY_US, DELAY_10S * US_PER_SEC, timer1.read_us());
}

/* Test that ::rtc_write/::rtc_read functions provides availability to set/get RTC time. */
void rtc_write_read_test()
{
    static const uint32_t rtc_init_val = 100;

    rtc_init();

    for (int i = 0; i < 3; i++) {
        const uint32_t init_val = (rtc_init_val + i * rtc_init_val);

        core_util_critical_section_enter();

        rtc_write(init_val);
        const uint32_t read_val = rtc_read();

        core_util_critical_section_exit();

        /* No tolerance is provided since we should have 1 second to
         * execute this case after the RTC time is set.
         */
        TEST_ASSERT_EQUAL_UINT32(init_val, read_val);
    }

    rtc_free();
}

/* Test that ::is_enabled function returns 1 if the RTC is counting and the time has been set. */
void rtc_enabled_test()
{
    /* Since some platforms use RTC for low power timer RTC may be already enabled.
     * Because of that we will only verify if rtc_isenabled() returns 1 in case when init is done
     * and RTC time is set.
     */

    rtc_init();
    rtc_write(0);
    TEST_ASSERT_EQUAL_INT(1, rtc_isenabled());
    rtc_free();
}

Case cases[] = {
    Case("RTC - init", rtc_init_test),
#if DEVICE_LOWPOWERTIMER
    Case("RTC - sleep", rtc_sleep_test),
#endif
    Case("RTC - persist", rtc_persist_test),
    Case("RTC - glitch", rtc_glitch_test),
    Case("RTC - range", rtc_range_test),
    Case("RTC - accuracy", rtc_accuracy_test),
    Case("RTC - write/read", rtc_write_read_test),
    Case("RTC - enabled", rtc_enabled_test),
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
    GREENTEA_SETUP(30, "default_auto");
    return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main()
{
    Harness::run(specification);
}
<|endoftext|>


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

#include "classad/common.h"
#include "classad/source.h"
#include "classad/matchClassad.h"

using namespace std;

static char const *ATTR_UNOPTIMIZED_REQUIREMENTS = "UnoptimizedRequirements";

BEGIN_NAMESPACE( classad )

MatchClassAd::
MatchClassAd()
{
	lCtx = rCtx = NULL;
	lad = rad = NULL;
	ladParent = radParent = NULL;
	InitMatchClassAd( NULL, NULL );
}

MatchClassAd::
MatchClassAd( ClassAd *adl, ClassAd *adr ) : ClassAd()
{
	lad = rad = lCtx = rCtx = NULL;
	ladParent = radParent = NULL;
	InitMatchClassAd( adl, adr );
}

MatchClassAd::
~MatchClassAd()
{
}

MatchClassAd* MatchClassAd::
MakeMatchClassAd( ClassAd *adl, ClassAd *adr )
{
	return( new MatchClassAd( adl, adr ) );
}

bool MatchClassAd::
InitMatchClassAd( ClassAd *adl, ClassAd *adr )
{
	ClassAdParser parser;

		// clear out old info
	Clear( );
	lad = rad = NULL;
	lCtx = rCtx = NULL;

		// convenience expressions
	ClassAd *upd;
	if( !( upd = parser.ParseClassAd(
			"[symmetricMatch = RIGHT.requirements && LEFT.requirements ;"
			"leftMatchesRight = RIGHT.requirements ;"
			"rightMatchesLeft = LEFT.requirements ;"
			"leftRankValue = LEFT.rank ;"
			"rightRankValue = RIGHT.rank]" ) ) ) {
		Clear( );
		lCtx = NULL;
		rCtx = NULL;
		return( false );
	}
	Update( *upd );
	delete upd;

		// In the following, global-scope references to LEFT and RIGHT
		// are used to make things slightly more efficient.  That means
		// that this match ad should not be nested inside other ads.
		// Also for effiency, the left and right ads are actually
		// inserted as .LEFT and .RIGHT (ie at the top level) but
		// their parent scope is set to the lCtx and rCtx ads as
		// though they were inserted as lCtx.ad and rCtx.ad.  This way,
		// the most direct way to reference the ads is through the
		// top-level global names .LEFT and .RIGHT.

		// the left context
	if( !( lCtx = parser.ParseClassAd(
			"[other=.RIGHT;target=.RIGHT;my=.LEFT;ad=.LEFT]" ) ) ) {
		Clear( );
		lCtx = NULL;
		rCtx = NULL;
		return( false );
	}

		// the right context
	if( !( rCtx = parser.ParseClassAd(
			"[other=.LEFT;target=.LEFT;my=.RIGHT;ad=.RIGHT]" ) ) ) {
		delete lCtx;
		lCtx = rCtx = NULL;
		return( false );
	}

		// insert the left and right contexts
	Insert( "lCtx", lCtx );
	Insert( "rCtx", rCtx );

	if( !adl ) {
		adl = new ClassAd();
	}
	if( !adr ) {
		adr = new ClassAd();
	}
	ReplaceLeftAd( adl );
	ReplaceRightAd( adr );

	return( true );
}

bool MatchClassAd::
ReplaceLeftAd( ClassAd *ad )
{
	lad = ad;
	ladParent = lad ? lad->GetParentScope( ) : (ClassAd*)NULL;
	if( ad ) {
		if( !Insert( "LEFT", ad ) ) {
			return false;
		}
			// For the ability to efficiently reference the ad via
			// .LEFT, it is inserted in the top match ad, but we want
			// its parent scope to be the context ad.
		lad->SetParentScope( lCtx );
	}
	return true;
}

bool MatchClassAd::
ReplaceRightAd( ClassAd *ad )
{
	rad = ad;
	radParent = rad ? rad->GetParentScope( ) : (ClassAd*)NULL;
	if( ad ) {
		if( !Insert( "RIGHT", ad ) ) {
			return false;
		}
			// For the ability to efficiently reference the ad via
			// .RIGHT, it is inserted in the top match ad, but we want
			// its parent scope to be the context ad.
		rad->SetParentScope( rCtx );
	}
	return true;
}

ClassAd *MatchClassAd::
GetLeftAd()
{
	return( lad );
}

ClassAd *MatchClassAd::
GetRightAd()
{
	return( rad );
}

ClassAd *MatchClassAd::
GetLeftContext( )
{
	return( lCtx );
}

ClassAd *MatchClassAd::
GetRightContext( )
{
	return( rCtx );
}

ClassAd *MatchClassAd::
RemoveLeftAd( )
{
	ClassAd *ad = lad;
	Remove( "LEFT" );
	if( lad ) {
		lad->SetParentScope( ladParent );
	}
	ladParent = NULL;
	lad = NULL;
	return( ad );
}

ClassAd *MatchClassAd::
RemoveRightAd( )
{
	ClassAd	*ad = rad;
	Remove( "RIGHT" );
	if( rad ) {
		rad->SetParentScope( radParent );
	}
	radParent = NULL;
	rad = NULL;
	return( ad );
}

bool MatchClassAd::
OptimizeRightAdForMatchmaking( ClassAd *ad, std::string *error_msg )
{
	return OptimizeAdForMatchmaking( ad, true, error_msg );
}

bool MatchClassAd::
OptimizeLeftAdForMatchmaking( ClassAd *ad, std::string *error_msg )
{
	return OptimizeAdForMatchmaking( ad, false, error_msg );
}

bool MatchClassAd::
OptimizeAdForMatchmaking( ClassAd *ad, bool is_right, std::string *error_msg )
{
	if( ad->Lookup("my") ||
		ad->Lookup("target") ||
		ad->Lookup("other") ||
		ad->Lookup(ATTR_UNOPTIMIZED_REQUIREMENTS) )
	{
		if( error_msg ) {
			*error_msg = "Optimization of matchmaking requirements failed, because ad already contains one of my, target, other, or UnoptimizedRequirements.";
		}
		return false;
	}

	ExprTree *requirements = ad->Lookup(ATTR_REQUIREMENTS);
	if( !requirements ) {
		if( error_msg ) {
			*error_msg = "No requirements found in ad to be optimized.";
		}
		return false;
	}

		// insert "my" into this ad so that references that use it
		// can be flattened
	Value me;
	me.SetClassAdValue( ad );
	ad->Insert("my",Literal::MakeLiteral(me));

		// insert "target" and "other" into this ad so references can be
		// _partially_ flattened to the more efficient .RIGHT or .LEFT
	char const *other = is_right ? "LEFT" : "RIGT";
	ExprTree *target =
		AttributeReference::MakeAttributeReference(NULL,other,true);
	ad->Insert("target",target);
	ad->Insert("other",target);

	ExprTree *flat_requirements = NULL;
	Value flat_val;

	if( ad->FlattenAndInline(requirements,flat_val,flat_requirements) ) {
		if( !flat_requirements ) {
				// flattened to a value
			flat_requirements = classad::Literal::MakeLiteral(flat_val);
		}
		if( flat_requirements ) {
				// save original requirements
			ExprTree *orig_requirements = ad->Remove(ATTR_REQUIREMENTS);
			if( orig_requirements ) {
				if( !ad->Insert(ATTR_UNOPTIMIZED_REQUIREMENTS,orig_requirements) )
				{
						// Now we have no requirements.  Very bad!
					if( error_msg ) {
						*error_msg = "Failed to rename original requirements.";
					}
					delete orig_requirements;
					return false;
				}
			}

				// insert new flattened requirements
			if( !ad->Insert(ATTR_REQUIREMENTS,flat_requirements) ) {
				if( error_msg ) {
					*error_msg = "Failed to insert optimized requirements.";
				}
				delete flat_requirements;
				return false;
			}
		}
	}

		// After flatenning, no references should remain to MY or TARGET.
		// Even if there are, those can be resolved by the context ads, so
		// we don't need to leave these attributes in the ad.
	ad->Delete("my");
	ad->Remove("other"); // this is a pointer to same object as target
	ad->Delete("target");

	return true;
}

bool MatchClassAd::
UnoptimizeAdForMatchmaking( ClassAd *ad )
{
	ExprTree *orig_requirements = ad->Remove(ATTR_UNOPTIMIZED_REQUIREMENTS);
	if( orig_requirements ) {
		if( !ad->Insert(ATTR_REQUIREMENTS,orig_requirements) ) {
			return false;
		}
	}
	return true;
}

END_NAMESPACE // classad
<commit_msg>Fix bad namespace usage in MatchClassAd.<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "classad/common.h"
#include "classad/source.h"
#include "classad/matchClassad.h"

using namespace std;

static char const *ATTR_UNOPTIMIZED_REQUIREMENTS = "UnoptimizedRequirements";

BEGIN_NAMESPACE( classad )

MatchClassAd::
MatchClassAd()
{
	lCtx = rCtx = NULL;
	lad = rad = NULL;
	ladParent = radParent = NULL;
	InitMatchClassAd( NULL, NULL );
}

MatchClassAd::
MatchClassAd( ClassAd *adl, ClassAd *adr ) : ClassAd()
{
	lad = rad = lCtx = rCtx = NULL;
	ladParent = radParent = NULL;
	InitMatchClassAd( adl, adr );
}

MatchClassAd::
~MatchClassAd()
{
}

MatchClassAd* MatchClassAd::
MakeMatchClassAd( ClassAd *adl, ClassAd *adr )
{
	return( new MatchClassAd( adl, adr ) );
}

bool MatchClassAd::
InitMatchClassAd( ClassAd *adl, ClassAd *adr )
{
	ClassAdParser parser;

		// clear out old info
	Clear( );
	lad = rad = NULL;
	lCtx = rCtx = NULL;

		// convenience expressions
	ClassAd *upd;
	if( !( upd = parser.ParseClassAd(
			"[symmetricMatch = RIGHT.requirements && LEFT.requirements ;"
			"leftMatchesRight = RIGHT.requirements ;"
			"rightMatchesLeft = LEFT.requirements ;"
			"leftRankValue = LEFT.rank ;"
			"rightRankValue = RIGHT.rank]" ) ) ) {
		Clear( );
		lCtx = NULL;
		rCtx = NULL;
		return( false );
	}
	Update( *upd );
	delete upd;

		// In the following, global-scope references to LEFT and RIGHT
		// are used to make things slightly more efficient.  That means
		// that this match ad should not be nested inside other ads.
		// Also for effiency, the left and right ads are actually
		// inserted as .LEFT and .RIGHT (ie at the top level) but
		// their parent scope is set to the lCtx and rCtx ads as
		// though they were inserted as lCtx.ad and rCtx.ad.  This way,
		// the most direct way to reference the ads is through the
		// top-level global names .LEFT and .RIGHT.

		// the left context
	if( !( lCtx = parser.ParseClassAd(
			"[other=.RIGHT;target=.RIGHT;my=.LEFT;ad=.LEFT]" ) ) ) {
		Clear( );
		lCtx = NULL;
		rCtx = NULL;
		return( false );
	}

		// the right context
	if( !( rCtx = parser.ParseClassAd(
			"[other=.LEFT;target=.LEFT;my=.RIGHT;ad=.RIGHT]" ) ) ) {
		delete lCtx;
		lCtx = rCtx = NULL;
		return( false );
	}

		// insert the left and right contexts
	Insert( "lCtx", lCtx );
	Insert( "rCtx", rCtx );

	if( !adl ) {
		adl = new ClassAd();
	}
	if( !adr ) {
		adr = new ClassAd();
	}
	ReplaceLeftAd( adl );
	ReplaceRightAd( adr );

	return( true );
}

bool MatchClassAd::
ReplaceLeftAd( ClassAd *ad )
{
	lad = ad;
	ladParent = lad ? lad->GetParentScope( ) : (ClassAd*)NULL;
	if( ad ) {
		if( !Insert( "LEFT", ad ) ) {
			return false;
		}
			// For the ability to efficiently reference the ad via
			// .LEFT, it is inserted in the top match ad, but we want
			// its parent scope to be the context ad.
		lad->SetParentScope( lCtx );
	}
	return true;
}

bool MatchClassAd::
ReplaceRightAd( ClassAd *ad )
{
	rad = ad;
	radParent = rad ? rad->GetParentScope( ) : (ClassAd*)NULL;
	if( ad ) {
		if( !Insert( "RIGHT", ad ) ) {
			return false;
		}
			// For the ability to efficiently reference the ad via
			// .RIGHT, it is inserted in the top match ad, but we want
			// its parent scope to be the context ad.
		rad->SetParentScope( rCtx );
	}
	return true;
}

ClassAd *MatchClassAd::
GetLeftAd()
{
	return( lad );
}

ClassAd *MatchClassAd::
GetRightAd()
{
	return( rad );
}

ClassAd *MatchClassAd::
GetLeftContext( )
{
	return( lCtx );
}

ClassAd *MatchClassAd::
GetRightContext( )
{
	return( rCtx );
}

ClassAd *MatchClassAd::
RemoveLeftAd( )
{
	ClassAd *ad = lad;
	Remove( "LEFT" );
	if( lad ) {
		lad->SetParentScope( ladParent );
	}
	ladParent = NULL;
	lad = NULL;
	return( ad );
}

ClassAd *MatchClassAd::
RemoveRightAd( )
{
	ClassAd	*ad = rad;
	Remove( "RIGHT" );
	if( rad ) {
		rad->SetParentScope( radParent );
	}
	radParent = NULL;
	rad = NULL;
	return( ad );
}

bool MatchClassAd::
OptimizeRightAdForMatchmaking( ClassAd *ad, std::string *error_msg )
{
	return OptimizeAdForMatchmaking( ad, true, error_msg );
}

bool MatchClassAd::
OptimizeLeftAdForMatchmaking( ClassAd *ad, std::string *error_msg )
{
	return OptimizeAdForMatchmaking( ad, false, error_msg );
}

bool MatchClassAd::
OptimizeAdForMatchmaking( ClassAd *ad, bool is_right, std::string *error_msg )
{
	if( ad->Lookup("my") ||
		ad->Lookup("target") ||
		ad->Lookup("other") ||
		ad->Lookup(ATTR_UNOPTIMIZED_REQUIREMENTS) )
	{
		if( error_msg ) {
			*error_msg = "Optimization of matchmaking requirements failed, because ad already contains one of my, target, other, or UnoptimizedRequirements.";
		}
		return false;
	}

	ExprTree *requirements = ad->Lookup(ATTR_REQUIREMENTS);
	if( !requirements ) {
		if( error_msg ) {
			*error_msg = "No requirements found in ad to be optimized.";
		}
		return false;
	}

		// insert "my" into this ad so that references that use it
		// can be flattened
	Value me;
	me.SetClassAdValue( ad );
	ad->Insert("my",Literal::MakeLiteral(me));

		// insert "target" and "other" into this ad so references can be
		// _partially_ flattened to the more efficient .RIGHT or .LEFT
	char const *other = is_right ? "LEFT" : "RIGT";
	ExprTree *target =
		AttributeReference::MakeAttributeReference(NULL,other,true);
	ad->Insert("target",target);
	ad->Insert("other",target);

	ExprTree *flat_requirements = NULL;
	Value flat_val;

	if( ad->FlattenAndInline(requirements,flat_val,flat_requirements) ) {
		if( !flat_requirements ) {
				// flattened to a value
			flat_requirements = Literal::MakeLiteral(flat_val);
		}
		if( flat_requirements ) {
				// save original requirements
			ExprTree *orig_requirements = ad->Remove(ATTR_REQUIREMENTS);
			if( orig_requirements ) {
				if( !ad->Insert(ATTR_UNOPTIMIZED_REQUIREMENTS,orig_requirements) )
				{
						// Now we have no requirements.  Very bad!
					if( error_msg ) {
						*error_msg = "Failed to rename original requirements.";
					}
					delete orig_requirements;
					return false;
				}
			}

				// insert new flattened requirements
			if( !ad->Insert(ATTR_REQUIREMENTS,flat_requirements) ) {
				if( error_msg ) {
					*error_msg = "Failed to insert optimized requirements.";
				}
				delete flat_requirements;
				return false;
			}
		}
	}

		// After flatenning, no references should remain to MY or TARGET.
		// Even if there are, those can be resolved by the context ads, so
		// we don't need to leave these attributes in the ad.
	ad->Delete("my");
	ad->Remove("other"); // this is a pointer to same object as target
	ad->Delete("target");

	return true;
}

bool MatchClassAd::
UnoptimizeAdForMatchmaking( ClassAd *ad )
{
	ExprTree *orig_requirements = ad->Remove(ATTR_UNOPTIMIZED_REQUIREMENTS);
	if( orig_requirements ) {
		if( !ad->Insert(ATTR_REQUIREMENTS,orig_requirements) ) {
			return false;
		}
	}
	return true;
}

END_NAMESPACE // classad
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "CppUTest/TestHarness_c.h"

#include "CppUTest/TestHarness.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/PlatformSpecificFunctions.h"

TEST_GROUP(TestHarness_c)
{
	TestTestingFixture* fixture;
	TEST_SETUP()
	{
		fixture = new TestTestingFixture();
	}
	TEST_TEARDOWN()
	{
		delete fixture;
	}
};

static void _failIntMethod()
{
	CHECK_EQUAL_C_INT(1, 2);
}

TEST(TestHarness_c, checkInt)
{
	CHECK_EQUAL_C_INT(2, 2);
	fixture->setTestFunction(_failIntMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <1>\n	but was  <2>");
	fixture->assertPrintContains("arness_c");
}

static void _failRealMethod()
{
	CHECK_EQUAL_C_REAL(1.0, 2.0, 0.5);
}

TEST(TestHarness_c, checkReal)
{
	CHECK_EQUAL_C_REAL(1.0, 1.1, 0.5);
	fixture->setTestFunction(_failRealMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <1>\n	but was  <2>");
	fixture->assertPrintContains("arness_c");
}

static void _failCharMethod()
{
	CHECK_EQUAL_C_CHAR('a', 'c');
}

TEST(TestHarness_c, checkChar)
{
	CHECK_EQUAL_C_CHAR('a', 'a');
	fixture->setTestFunction(_failCharMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <a>\n	but was  <c>");
	fixture->assertPrintContains("arness_c");
}

static void _failStringMethod()
{
	CHECK_EQUAL_C_STRING("Hello", "Hello World");
}

TEST(TestHarness_c, checkString)
{
	CHECK_EQUAL_C_STRING("Hello", "Hello");
	fixture->setTestFunction(_failStringMethod);
	fixture->runAllTests();

	StringEqualFailure failure(UtestShell::getCurrent(), "file", 1, "Hello", "Hello World");
	fixture->assertPrintContains(failure.getMessage());
	fixture->assertPrintContains("arness_c");
}

static void _failTextMethod()
{
	FAIL_TEXT_C("Booo");
}

TEST(TestHarness_c, checkFailText)
{
	fixture->setTestFunction(_failTextMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("Booo");
	fixture->assertPrintContains("arness_c");
}

static void _failMethod()
{
	FAIL_C();
}

TEST(TestHarness_c, checkFail)
{
	fixture->setTestFunction(_failMethod);
	fixture->runAllTests();
	LONGS_EQUAL(1, fixture->getFailureCount());
	fixture->assertPrintContains("arness_c");
}

static void _CheckMethod()
{
	CHECK_C(false);
}

TEST(TestHarness_c, checkCheck)
{
	CHECK_C(true);
	fixture->setTestFunction(_CheckMethod);
	fixture->runAllTests();
	LONGS_EQUAL(1, fixture->getFailureCount());
}

#if CPPUTEST_USE_MEM_LEAK_DETECTION

TEST(TestHarness_c, cpputest_malloc_out_of_memory)
{
	cpputest_malloc_set_out_of_memory();
	CHECK(0 == cpputest_malloc(100));

	cpputest_malloc_set_not_out_of_memory();
	void * mem = cpputest_malloc(100);
	CHECK(0 != mem);
	cpputest_free(mem);
}

TEST(TestHarness_c, cpputest_malloc_out_of_memory_after_n_mallocs)
{
	cpputest_malloc_set_out_of_memory_countdown(3);
	void * m1 = cpputest_malloc(10);
	void * m2 = cpputest_malloc(11);
	void * m3 = cpputest_malloc(12);
	CHECK(m1);
	CHECK(m2);
	POINTERS_EQUAL(0, m3);
	cpputest_malloc_set_not_out_of_memory();
	cpputest_free(m1);
	cpputest_free(m2);
}

TEST(TestHarness_c, cpputest_malloc_out_of_memory_after_0_mallocs)
{
	cpputest_malloc_set_out_of_memory_countdown(0);
	void * m1 = cpputest_malloc(10);
	CHECK(m1 == 0);
	cpputest_malloc_set_not_out_of_memory();
}

TEST(TestHarness_c, count_mallocs)
{
	cpputest_malloc_count_reset();
	void * m1 = cpputest_malloc(10);
	void * m2 = cpputest_malloc(11);
	void * m3 = cpputest_malloc(12);
	cpputest_free(m1);
	cpputest_free(m2);
	cpputest_free(m3);
	LONGS_EQUAL(3, cpputest_malloc_get_count());
}

TEST(TestHarness_c, cpputest_calloc)
{
	void * mem = cpputest_calloc(10, 10);
	CHECK(0 != mem);
	cpputest_free(mem);
}

TEST(TestHarness_c, cpputest_realloc_larger)
{
	const char* number_string = "123456789";

	char* mem1 = (char*) cpputest_malloc(10);

	PlatformSpecificStrCpy(mem1, number_string);
	CHECK(mem1 != 0);

	char* mem2 = (char*) cpputest_realloc(mem1, 1000);

	CHECK(mem2 != 0);
	STRCMP_EQUAL(number_string, mem2);

	cpputest_free(mem2);
}

#include "CppUTest/MemoryLeakDetector.h"

TEST(TestHarness_c, macros)
{
	MemoryLeakDetector* memLeakDetector = MemoryLeakWarningPlugin::getGlobalDetector();
	int memLeaks = memLeakDetector->totalMemoryLeaks(mem_leak_period_checking);
	void* mem1 = malloc(10);
	void* mem2 = calloc(10, 20);
	void* mem3 = realloc(mem2, 100);
#if CPPUTEST_USE_MALLOC_MACROS
	LONGS_EQUAL(memLeaks + 2, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
#endif
	free(mem1);
	free(mem3);
#if CPPUTEST_USE_MALLOC_MACROS
	LONGS_EQUAL(memLeaks, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
#endif

}

TEST(TestHarness_c, callocInitializedToZero)
{
	char* mem = (char*) calloc(20, sizeof(char));
	for (int i = 0; i < 20; i++)
		CHECK(mem[i] == 0);
	free(mem);
}
#endif

<commit_msg>Eliminate "unused Variable" warning when CPPUTEST_USE_MALLOC_MACROS is not defined.<commit_after>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "CppUTest/TestHarness_c.h"

#include "CppUTest/TestHarness.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/PlatformSpecificFunctions.h"

TEST_GROUP(TestHarness_c)
{
	TestTestingFixture* fixture;
	TEST_SETUP()
	{
		fixture = new TestTestingFixture();
	}
	TEST_TEARDOWN()
	{
		delete fixture;
	}
};

static void _failIntMethod()
{
	CHECK_EQUAL_C_INT(1, 2);
}

TEST(TestHarness_c, checkInt)
{
	CHECK_EQUAL_C_INT(2, 2);
	fixture->setTestFunction(_failIntMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <1>\n	but was  <2>");
	fixture->assertPrintContains("arness_c");
}

static void _failRealMethod()
{
	CHECK_EQUAL_C_REAL(1.0, 2.0, 0.5);
}

TEST(TestHarness_c, checkReal)
{
	CHECK_EQUAL_C_REAL(1.0, 1.1, 0.5);
	fixture->setTestFunction(_failRealMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <1>\n	but was  <2>");
	fixture->assertPrintContains("arness_c");
}

static void _failCharMethod()
{
	CHECK_EQUAL_C_CHAR('a', 'c');
}

TEST(TestHarness_c, checkChar)
{
	CHECK_EQUAL_C_CHAR('a', 'a');
	fixture->setTestFunction(_failCharMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("expected <a>\n	but was  <c>");
	fixture->assertPrintContains("arness_c");
}

static void _failStringMethod()
{
	CHECK_EQUAL_C_STRING("Hello", "Hello World");
}

TEST(TestHarness_c, checkString)
{
	CHECK_EQUAL_C_STRING("Hello", "Hello");
	fixture->setTestFunction(_failStringMethod);
	fixture->runAllTests();

	StringEqualFailure failure(UtestShell::getCurrent(), "file", 1, "Hello", "Hello World");
	fixture->assertPrintContains(failure.getMessage());
	fixture->assertPrintContains("arness_c");
}

static void _failTextMethod()
{
	FAIL_TEXT_C("Booo");
}

TEST(TestHarness_c, checkFailText)
{
	fixture->setTestFunction(_failTextMethod);
	fixture->runAllTests();
	fixture->assertPrintContains("Booo");
	fixture->assertPrintContains("arness_c");
}

static void _failMethod()
{
	FAIL_C();
}

TEST(TestHarness_c, checkFail)
{
	fixture->setTestFunction(_failMethod);
	fixture->runAllTests();
	LONGS_EQUAL(1, fixture->getFailureCount());
	fixture->assertPrintContains("arness_c");
}

static void _CheckMethod()
{
	CHECK_C(false);
}

TEST(TestHarness_c, checkCheck)
{
	CHECK_C(true);
	fixture->setTestFunction(_CheckMethod);
	fixture->runAllTests();
	LONGS_EQUAL(1, fixture->getFailureCount());
}

#if CPPUTEST_USE_MEM_LEAK_DETECTION

TEST(TestHarness_c, cpputest_malloc_out_of_memory)
{
	cpputest_malloc_set_out_of_memory();
	CHECK(0 == cpputest_malloc(100));

	cpputest_malloc_set_not_out_of_memory();
	void * mem = cpputest_malloc(100);
	CHECK(0 != mem);
	cpputest_free(mem);
}

TEST(TestHarness_c, cpputest_malloc_out_of_memory_after_n_mallocs)
{
	cpputest_malloc_set_out_of_memory_countdown(3);
	void * m1 = cpputest_malloc(10);
	void * m2 = cpputest_malloc(11);
	void * m3 = cpputest_malloc(12);
	CHECK(m1);
	CHECK(m2);
	POINTERS_EQUAL(0, m3);
	cpputest_malloc_set_not_out_of_memory();
	cpputest_free(m1);
	cpputest_free(m2);
}

TEST(TestHarness_c, cpputest_malloc_out_of_memory_after_0_mallocs)
{
	cpputest_malloc_set_out_of_memory_countdown(0);
	void * m1 = cpputest_malloc(10);
	CHECK(m1 == 0);
	cpputest_malloc_set_not_out_of_memory();
}

TEST(TestHarness_c, count_mallocs)
{
	cpputest_malloc_count_reset();
	void * m1 = cpputest_malloc(10);
	void * m2 = cpputest_malloc(11);
	void * m3 = cpputest_malloc(12);
	cpputest_free(m1);
	cpputest_free(m2);
	cpputest_free(m3);
	LONGS_EQUAL(3, cpputest_malloc_get_count());
}

TEST(TestHarness_c, cpputest_calloc)
{
	void * mem = cpputest_calloc(10, 10);
	CHECK(0 != mem);
	cpputest_free(mem);
}

TEST(TestHarness_c, cpputest_realloc_larger)
{
	const char* number_string = "123456789";

	char* mem1 = (char*) cpputest_malloc(10);

	PlatformSpecificStrCpy(mem1, number_string);
	CHECK(mem1 != 0);

	char* mem2 = (char*) cpputest_realloc(mem1, 1000);

	CHECK(mem2 != 0);
	STRCMP_EQUAL(number_string, mem2);

	cpputest_free(mem2);
}

#include "CppUTest/MemoryLeakDetector.h"

TEST(TestHarness_c, macros)
{
#if CPPUTEST_USE_MALLOC_MACROS
	MemoryLeakDetector* memLeakDetector = MemoryLeakWarningPlugin::getGlobalDetector();
	int memLeaks = memLeakDetector->totalMemoryLeaks(mem_leak_period_checking);
#endif
	void* mem1 = malloc(10);
	void* mem2 = calloc(10, 20);
	void* mem3 = realloc(mem2, 100);
#if CPPUTEST_USE_MALLOC_MACROS
	LONGS_EQUAL(memLeaks + 2, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
#endif
	free(mem1);
	free(mem3);
#if CPPUTEST_USE_MALLOC_MACROS
	LONGS_EQUAL(memLeaks, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
#endif

}

TEST(TestHarness_c, callocInitializedToZero)
{
	char* mem = (char*) calloc(20, sizeof(char));
	for (int i = 0; i < 20; i++)
		CHECK(mem[i] == 0);
	free(mem);
}
#endif

<|endoftext|>