<commit_before>/**
 * @file llnearbychatcontrol.cpp
 * @brief Nearby chat input control implementation
 *
 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 * Copyright (C) 2012, Zi Ree @ Second Life
 *
 * 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"

#include "llnearbychatcontrol.h"
#include "llnearbychathub.h"
#include "llfloaternearbychat.h"
// #include "llviewercontrol.h"
// #include "llviewerwindow.h"
// #include "llrootview.h"
//#include "llchatitemscontainerctrl.h"
// #include "lliconctrl.h"
#include "llspinctrl.h"
// #include "llfloatersidepanelcontainer.h"
// #include "llfocusmgr.h"
// #include "lllogchat.h"
// #include "llresizebar.h"
// #include "llresizehandle.h"
#include "llmenugl.h"
#include "llviewermenu.h"//for gMenuHolder

// #include "llnearbychathandler.h"
// #include "llnearbychatbar.h"	// <FS:Zi> Remove floating chat bar
// #include "llchannelmanager.h"

#include "llagent.h" 			// gAgent
// #include "llchathistory.h"
// #include "llstylemap.h"

// #include "llavatarnamecache.h"

// #include "lldraghandle.h"

// #include "llnearbychatbar.h"	// <FS:Zi> Remove floating chat bar
// #include "llfloaterreg.h"
// #include "lltrans.h"

// IM
// #include "llbutton.h"
// #include "lllayoutstack.h"

// #include "llimfloatercontainer.h"
// #include "llimfloater.h"
#include "lllineeditor.h"

//AO - includes for textentry
#include "rlvhandler.h"
#include "llcommandhandler.h"
#include "llkeyboard.h"
#include "llgesturemgr.h"
#include "llmultigesture.h"

// #include "llconsole.h"
// #include "fscontactsfloater.h"

// <FS:Zi> Moved nearby chat functionality here for now
// #include "chatbar_as_cmdline.h"
// #include "llanimationstates.h"	// ANIM_AGENT_WHISPER, ANIM_AGENT_TALK, ANIM_AGENT_SHOUT
// #include "llviewerstats.h"
// </FS:Zi>

static LLDefaultChildRegistry::Register<LLNearbyChatControl> r("nearby_chat_control");

struct LLChatTypeTrigger {
	std::string name;
	EChatType type;
};

static LLChatTypeTrigger sChatTypeTriggers[] = {
	{ "/whisper"	, CHAT_TYPE_WHISPER},
	{ "/shout"	, CHAT_TYPE_SHOUT}
};

LLNearbyChatControl::LLNearbyChatControl(const LLNearbyChatControl::Params& p) :
	LLLineEditor(p)
{
	setKeystrokeCallback(onKeystroke,this);
	LLNearbyChat::instance().registerChatBar(this);

	setEnableLineHistory(TRUE);
	setIgnoreArrowKeys( FALSE );
	setCommitOnFocusLost( FALSE );
	setRevertOnEsc( FALSE );
	setIgnoreTab( TRUE );
	setReplaceNewlinesWithSpaces( FALSE );
	setPassDelete( TRUE );
}

LLNearbyChatControl::~LLNearbyChatControl()
{
}

void LLNearbyChatControl::onKeystroke(LLLineEditor* caller,void* userdata)
{
	LLWString raw_text = caller->getWText();

	// Can't trim the end, because that will cause autocompletion
	// to eat trailing spaces that might be part of a gesture.
	LLWStringUtil::trimHead(raw_text);
	S32 length = raw_text.length();

	// Get the currently selected channel from the channel spinner in the nearby chat bar, if present and used.
	// NOTE: Parts of the gAgent.startTyping() code are duplicated in 3 places:
	// - llnearbychatbar.cpp
	// - llchatbar.cpp
	// - llnearbychat.cpp
	// So be sure to look in all three places if changes are needed. This needs to be addressed at some point.
	// -Zi
	S32 channel=0;
	if (gSavedSettings.getBOOL("FSNearbyChatbar") &&
		gSavedSettings.getBOOL("FSShowChatChannel"))
	{
		channel = (S32)(LLFloaterNearbyChat::getInstance()->getChild<LLSpinCtrl>("ChatChannel")->get());
	}
	// -Zi

	//	if( (length > 0) && (raw_text[0] != '/') )  // forward slash is used for escape (eg. emote) sequences
	// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0d
	if ( (length > 0) && (raw_text[0] != '/') && (!gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT)) )
		// [/RLVa:KB]
	{
		// only start typing animation if we are chatting without / on channel 0 -Zi
		if(channel==0)
			gAgent.startTyping();
	}
	else
	{
		gAgent.stopTyping();
	}

	KEY key = gKeyboard->currentKey();

	// Ignore "special" keys, like backspace, arrows, etc.
	if (length > 1
		&& raw_text[0] == '/'
		&& key < KEY_SPECIAL)
	{
		// we're starting a gesture, attempt to autocomplete

		std::string utf8_trigger = wstring_to_utf8str(raw_text);
		std::string utf8_out_str(utf8_trigger);

		if (LLGestureMgr::instance().matchPrefix(utf8_trigger, &utf8_out_str))
		{
			std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size());
			caller->setText(utf8_trigger + rest_of_match); // keep original capitalization for user-entered part
			S32 outlength = caller->getLength(); // in characters

			// Select to end of line, starting from the character
			// after the last one the user typed.
			caller->setSelection(length, outlength);
		}
		else if (matchChatTypeTrigger(utf8_trigger, &utf8_out_str))
		{
			std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size());
			caller->setText(utf8_trigger + rest_of_match + " "); // keep original capitalization for user-entered part
			caller->setCursorToEnd();
		}
	}
}

BOOL LLNearbyChatControl::matchChatTypeTrigger(const std::string& in_str, std::string* out_str)
{
	U32 in_len = in_str.length();
	S32 cnt = sizeof(sChatTypeTriggers) / sizeof(*sChatTypeTriggers);

	for (S32 n = 0; n < cnt; n++)
	{
		if (in_len > sChatTypeTriggers[n].name.length())
			continue;

		std::string trigger_trunc = sChatTypeTriggers[n].name;
		LLStringUtil::truncate(trigger_trunc, in_len);

		if (!LLStringUtil::compareInsensitive(in_str, trigger_trunc))
		{
			*out_str = sChatTypeTriggers[n].name;
			return TRUE;
		}
	}

	return FALSE;
}

// send our focus status to the LLNearbyChat hub
void LLNearbyChatControl::onFocusReceived()
{
	LLNearbyChat::instance().setFocusedInputEditor(this,TRUE);
	LLLineEditor::onFocusReceived();
}

void LLNearbyChatControl::onFocusLost()
{
	LLNearbyChat::instance().setFocusedInputEditor(this,FALSE);
	LLLineEditor::onFocusLost();
}

void LLNearbyChatControl::setFocus(BOOL focus)
{
	LLNearbyChat::instance().setFocusedInputEditor(this,focus);
	LLLineEditor::setFocus(focus);
}

void LLNearbyChatControl::autohide()
{
	if(getName()=="default_chat_bar")
	{
		if(gSavedSettings.getBOOL("CloseChatOnReturn"))
		{
			setFocus(FALSE);
		}

		if(gSavedSettings.getBOOL("AutohideChatBar"))
		{
			LLNearbyChat::instance().showDefaultChatBar(FALSE);
		}
	}
}

// handle ESC key here
BOOL LLNearbyChatControl::handleKeyHere(KEY key, MASK mask )
{
	BOOL handled = FALSE;
	EChatType type = CHAT_TYPE_NORMAL;

	// autohide the chat bar if escape key was pressed and we're the default chat bar
	if(key==KEY_ESCAPE && mask==MASK_NONE)
	{
		autohide();
		gAgent.stopTyping();
	}
	else if( KEY_RETURN == key )
	{
		llinfos << "Handling return key, mask=" << mask << llendl;
		if (mask == MASK_CONTROL)
		{
			// shout
			type = CHAT_TYPE_SHOUT;
			handled = TRUE;
		}
		else if (mask == MASK_SHIFT)
		{
			// whisper
			type = CHAT_TYPE_WHISPER;
			handled = TRUE;
		}
		else if (mask == MASK_ALT)
		{
			// OOC
			type = CHAT_TYPE_OOC;
			handled = TRUE;
		}
		else if (mask == MASK_NONE)
		{
			// say
			type = CHAT_TYPE_NORMAL;
			handled = TRUE;
		}
	}

	if (handled == TRUE)
	{
		LLNearbyChat::instance().sendChat(getConvertedText(),type);
		setText(LLStringExplicit(""));
		autohide();
		return TRUE;
	}

	// let ESC key go through to the rest of the UI code
	return LLLineEditor::handleKeyHere(key,mask);
}
<commit_msg>Fixed line editor history or nearby chat, broken by my previous commit.<commit_after>/**
 * @file llnearbychatcontrol.cpp
 * @brief Nearby chat input control implementation
 *
 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 * Copyright (C) 2012, Zi Ree @ Second Life
 *
 * 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"

#include "llnearbychatcontrol.h"
#include "llnearbychathub.h"
#include "llfloaternearbychat.h"
// #include "llviewercontrol.h"
// #include "llviewerwindow.h"
// #include "llrootview.h"
//#include "llchatitemscontainerctrl.h"
// #include "lliconctrl.h"
#include "llspinctrl.h"
// #include "llfloatersidepanelcontainer.h"
// #include "llfocusmgr.h"
// #include "lllogchat.h"
// #include "llresizebar.h"
// #include "llresizehandle.h"
#include "llmenugl.h"
#include "llviewermenu.h"//for gMenuHolder

// #include "llnearbychathandler.h"
// #include "llnearbychatbar.h"	// <FS:Zi> Remove floating chat bar
// #include "llchannelmanager.h"

#include "llagent.h" 			// gAgent
// #include "llchathistory.h"
// #include "llstylemap.h"

// #include "llavatarnamecache.h"

// #include "lldraghandle.h"

// #include "llnearbychatbar.h"	// <FS:Zi> Remove floating chat bar
// #include "llfloaterreg.h"
// #include "lltrans.h"

// IM
// #include "llbutton.h"
// #include "lllayoutstack.h"

// #include "llimfloatercontainer.h"
// #include "llimfloater.h"
#include "lllineeditor.h"

//AO - includes for textentry
#include "rlvhandler.h"
#include "llcommandhandler.h"
#include "llkeyboard.h"
#include "llgesturemgr.h"
#include "llmultigesture.h"

// #include "llconsole.h"
// #include "fscontactsfloater.h"

// <FS:Zi> Moved nearby chat functionality here for now
// #include "chatbar_as_cmdline.h"
// #include "llanimationstates.h"	// ANIM_AGENT_WHISPER, ANIM_AGENT_TALK, ANIM_AGENT_SHOUT
// #include "llviewerstats.h"
// </FS:Zi>

static LLDefaultChildRegistry::Register<LLNearbyChatControl> r("nearby_chat_control");

struct LLChatTypeTrigger {
	std::string name;
	EChatType type;
};

static LLChatTypeTrigger sChatTypeTriggers[] = {
	{ "/whisper"	, CHAT_TYPE_WHISPER},
	{ "/shout"	, CHAT_TYPE_SHOUT}
};

LLNearbyChatControl::LLNearbyChatControl(const LLNearbyChatControl::Params& p) :
	LLLineEditor(p)
{
	setKeystrokeCallback(onKeystroke,this);
	LLNearbyChat::instance().registerChatBar(this);

	setEnableLineHistory(TRUE);
	setIgnoreArrowKeys( FALSE );
	setCommitOnFocusLost( FALSE );
	setRevertOnEsc( FALSE );
	setIgnoreTab( TRUE );
	setReplaceNewlinesWithSpaces( FALSE );
	setPassDelete( TRUE );
}

LLNearbyChatControl::~LLNearbyChatControl()
{
}

void LLNearbyChatControl::onKeystroke(LLLineEditor* caller,void* userdata)
{
	LLWString raw_text = caller->getWText();

	// Can't trim the end, because that will cause autocompletion
	// to eat trailing spaces that might be part of a gesture.
	LLWStringUtil::trimHead(raw_text);
	S32 length = raw_text.length();

	// Get the currently selected channel from the channel spinner in the nearby chat bar, if present and used.
	// NOTE: Parts of the gAgent.startTyping() code are duplicated in 3 places:
	// - llnearbychatbar.cpp
	// - llchatbar.cpp
	// - llnearbychat.cpp
	// So be sure to look in all three places if changes are needed. This needs to be addressed at some point.
	// -Zi
	S32 channel=0;
	if (gSavedSettings.getBOOL("FSNearbyChatbar") &&
		gSavedSettings.getBOOL("FSShowChatChannel"))
	{
		channel = (S32)(LLFloaterNearbyChat::getInstance()->getChild<LLSpinCtrl>("ChatChannel")->get());
	}
	// -Zi

	//	if( (length > 0) && (raw_text[0] != '/') )  // forward slash is used for escape (eg. emote) sequences
	// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0d
	if ( (length > 0) && (raw_text[0] != '/') && (!gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT)) )
		// [/RLVa:KB]
	{
		// only start typing animation if we are chatting without / on channel 0 -Zi
		if(channel==0)
			gAgent.startTyping();
	}
	else
	{
		gAgent.stopTyping();
	}

	KEY key = gKeyboard->currentKey();

	// Ignore "special" keys, like backspace, arrows, etc.
	if (length > 1
		&& raw_text[0] == '/'
		&& key < KEY_SPECIAL)
	{
		// we're starting a gesture, attempt to autocomplete

		std::string utf8_trigger = wstring_to_utf8str(raw_text);
		std::string utf8_out_str(utf8_trigger);

		if (LLGestureMgr::instance().matchPrefix(utf8_trigger, &utf8_out_str))
		{
			std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size());
			caller->setText(utf8_trigger + rest_of_match); // keep original capitalization for user-entered part
			S32 outlength = caller->getLength(); // in characters

			// Select to end of line, starting from the character
			// after the last one the user typed.
			caller->setSelection(length, outlength);
		}
		else if (matchChatTypeTrigger(utf8_trigger, &utf8_out_str))
		{
			std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size());
			caller->setText(utf8_trigger + rest_of_match + " "); // keep original capitalization for user-entered part
			caller->setCursorToEnd();
		}
	}
}

BOOL LLNearbyChatControl::matchChatTypeTrigger(const std::string& in_str, std::string* out_str)
{
	U32 in_len = in_str.length();
	S32 cnt = sizeof(sChatTypeTriggers) / sizeof(*sChatTypeTriggers);

	for (S32 n = 0; n < cnt; n++)
	{
		if (in_len > sChatTypeTriggers[n].name.length())
			continue;

		std::string trigger_trunc = sChatTypeTriggers[n].name;
		LLStringUtil::truncate(trigger_trunc, in_len);

		if (!LLStringUtil::compareInsensitive(in_str, trigger_trunc))
		{
			*out_str = sChatTypeTriggers[n].name;
			return TRUE;
		}
	}

	return FALSE;
}

// send our focus status to the LLNearbyChat hub
void LLNearbyChatControl::onFocusReceived()
{
	LLNearbyChat::instance().setFocusedInputEditor(this,TRUE);
	LLLineEditor::onFocusReceived();
}

void LLNearbyChatControl::onFocusLost()
{
	LLNearbyChat::instance().setFocusedInputEditor(this,FALSE);
	LLLineEditor::onFocusLost();
}

void LLNearbyChatControl::setFocus(BOOL focus)
{
	LLNearbyChat::instance().setFocusedInputEditor(this,focus);
	LLLineEditor::setFocus(focus);
}

void LLNearbyChatControl::autohide()
{
	if(getName()=="default_chat_bar")
	{
		if(gSavedSettings.getBOOL("CloseChatOnReturn"))
		{
			setFocus(FALSE);
		}

		if(gSavedSettings.getBOOL("AutohideChatBar"))
		{
			LLNearbyChat::instance().showDefaultChatBar(FALSE);
		}
	}
}

// handle ESC key here
BOOL LLNearbyChatControl::handleKeyHere(KEY key, MASK mask )
{
	BOOL handled = FALSE;
	EChatType type = CHAT_TYPE_NORMAL;

	// autohide the chat bar if escape key was pressed and we're the default chat bar
	if(key==KEY_ESCAPE && mask==MASK_NONE)
	{
		// we let ESC key go through to the rest of the UI code, so don't set handled=TRUE
		autohide();
		gAgent.stopTyping();
	}
	else if( KEY_RETURN == key )
	{
		llinfos << "Handling return key, mask=" << mask << llendl;
		if (mask == MASK_CONTROL)
		{
			// shout
			type = CHAT_TYPE_SHOUT;
			handled = TRUE;
		}
		else if (mask == MASK_SHIFT)
		{
			// whisper
			type = CHAT_TYPE_WHISPER;
			handled = TRUE;
		}
		else if (mask == MASK_ALT)
		{
			// OOC
			type = CHAT_TYPE_OOC;
			handled = TRUE;
		}
		else if (mask == MASK_NONE)
		{
			// say
			type = CHAT_TYPE_NORMAL;
			handled = TRUE;
		}
	}

	if (handled == TRUE)
	{
		// save current line in the history buffer
		LLLineEditor::onCommit();

		// send chat to nearby chat hub
		LLNearbyChat::instance().sendChat(getConvertedText(),type);

		setText(LLStringExplicit(""));
		autohide();
		return TRUE;
	}

	// let the line editor handle everything we don't handle
	return LLLineEditor::handleKeyHere(key,mask);
}
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/
#include "BaseDotVisitor.h"

#include <fstream>
#include <cassert>

#include <osg/Node>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Notify>

using namespace osg;

namespace osgDot {

  BaseDotVisitor::BaseDotVisitor()
  {
    _rankdir = "rankdir = LR;";
  }

  BaseDotVisitor::~BaseDotVisitor() {
  }

    void BaseDotVisitor::setOptions(const osgDB::Options* options)
    {
        _options = const_cast<osgDB::Options*>(options);
        OSG_INFO<<"BaseDotVisitor::setOptions("<<options<<")"<<std::endl;
        if (_options.valid() && !(_options->getOptionString().empty()))
        {

            std::string optionString = _options->getOptionString();

            OSG_INFO<<"  BaseDotVisitor::optionString ("<<optionString<<")"<<std::endl;

            std::string::size_type pos = optionString.find("rankdir");
            if (pos!=std::string::npos)
            {
                std::string::size_type semi_pos = optionString.find(";",pos);
                if (semi_pos!=std::string::npos)
                {
                    _rankdir = optionString.substr(pos, semi_pos-pos);
                    OSG_INFO<<"  BaseDotVisitor::Set _rankdir to "<<_rankdir<<std::endl;
                }
            }
        }

    }

    bool BaseDotVisitor::run( osg::Node& root, std::ostream* fout ) {
    setTraversalMode( TRAVERSE_ALL_CHILDREN );
    if ( fout && *fout ) {
      root.accept( *this );

      *fout << "digraph osg_scenegraph { "<<_rankdir<< std::endl;

      *fout << _nodes.str() << _edges.str();

      *fout << "}" << std::endl;

      _nodes.clear();
      _edges.clear();
      _objectMap.clear();

      return true;
    }

    return false;
  }

  void BaseDotVisitor::apply(Node& node) {
    int id;
    if ( getOrCreateId( &node, id ) ) {
      handle( node, id );
      handleNodeAndTraverse( node, id );
    }
  }

  void BaseDotVisitor::apply(Geode& node) {
    int id;
    if ( getOrCreateId( &node, id ) ) {
      handle( node, id );
      handleNodeAndTraverse( node, id );

      unsigned int i;
      for ( i = 0; i < node.getNumDrawables(); i++ ) {
        osg::Drawable* drawable = node.getDrawable( i );
        int id2;
        if ( getOrCreateId( drawable, id2 ) ) {
          handle( *drawable, id2 );
          osg::StateSet* s = drawable->getStateSet();
          if ( s ) {
            int id3;
            if ( getOrCreateId( s, id3 ) ) {
              handle( *s, id3 );
            }
            handle( *drawable, *s, id2, id3 );
          }
        }
        handle( node, *drawable, id, id2 );
      }

    }

  }

  void BaseDotVisitor::apply(Group& node) {
    int id;

    if ( getOrCreateId( &node, id ) ) {
      handle( node, id );
      handleNodeAndTraverse( node, id );

      unsigned int i;
      for ( i = 0; i < node.getNumChildren(); i++ ) {
        osg::Node* child = node.getChild( i );
        //handleNodeAndTraverse( *child );
        int id2;
        getOrCreateId( child, id2 );
        handle( node, *child, id, id2 );
      }

    }

  }

  void BaseDotVisitor::handle(osg::Node& node, int id) {
  }

  void BaseDotVisitor::handle(osg::Geode& node, int id) {
  }

  void BaseDotVisitor::handle(osg::Group& node, int id) {
  }

  void BaseDotVisitor::handle(osg::Group& parent, osg::Node& child, int parentID, int childID ) {
  }

  void BaseDotVisitor::handleNodeAndTraverse(osg::Node& node, int id) {
    osg::StateSet* ss = node.getStateSet();
    if ( ss ) {
      int id2;
      if ( getOrCreateId( ss, id2 ) ) {
        handle( *ss, id2 );
      }
      handle( node, *ss, id, id2 );
    }
    traverse(node);
  }

  void BaseDotVisitor::handle(osg::StateSet& stateset, int id) {
  }

  void BaseDotVisitor::handle(osg::Node& node, osg::StateSet& stateset, int parentID, int childID) {
  }

  void BaseDotVisitor::handle(osg::Drawable& drawable, int id) {
  }

  void BaseDotVisitor::handle(osg::Drawable& drawable, osg::StateSet& stateset, int parentID, int childID ) {
  }

  void BaseDotVisitor::handle(osg::Geode& geode, osg::Drawable& drawable, int parentID, int childID ) {
  }

  bool BaseDotVisitor::getOrCreateId( osg::Object* object, int &id ) {
    assert( object );
    ObjectMap::iterator it = _objectMap.find( object );
    if ( it != _objectMap.end() ) {
      id = it->second;
      return false;
    }

    id = _objectMap.size();
    _objectMap[ object ] = id;
    return true;
  }

} // namespace osgDot
<commit_msg>From Cory Riddell, "I've been using the dot plugin and found that our application which sets the global locale was generating bad dot files. Specifically, the node numbers had comma separators in them (like 1,234 rather than 1234).<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/
#include "BaseDotVisitor.h"

#include <fstream>
#include <cassert>

#include <osg/Node>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Notify>

using namespace osg;

namespace osgDot {

  BaseDotVisitor::BaseDotVisitor()
  {
    _rankdir = "rankdir = LR;";
    // Set the locale used by the _nodes and _edges streams to the
    //   classic or "C" locale. This is needed because most of the
    //   Graphviz tools are not locale sensitive and get confused
    //   by id numbers containing commas or periods.
    _nodes.imbue(std::locale("C"));
    _edges.imbue(std::locale("C"));
  }

  BaseDotVisitor::~BaseDotVisitor() {
  }

    void BaseDotVisitor::setOptions(const osgDB::Options* options)
    {
        _options = const_cast<osgDB::Options*>(options);
        OSG_INFO<<"BaseDotVisitor::setOptions("<<options<<")"<<std::endl;
        if (_options.valid() && !(_options->getOptionString().empty()))
        {

            std::string optionString = _options->getOptionString();

            OSG_INFO<<"  BaseDotVisitor::optionString ("<<optionString<<")"<<std::endl;

            std::string::size_type pos = optionString.find("rankdir");
            if (pos!=std::string::npos)
            {
                std::string::size_type semi_pos = optionString.find(";",pos);
                if (semi_pos!=std::string::npos)
                {
                    _rankdir = optionString.substr(pos, semi_pos-pos);
                    OSG_INFO<<"  BaseDotVisitor::Set _rankdir to "<<_rankdir<<std::endl;
                }
            }
        }

    }

    bool BaseDotVisitor::run( osg::Node& root, std::ostream* fout ) {
    setTraversalMode( TRAVERSE_ALL_CHILDREN );
    if ( fout && *fout ) {
      root.accept( *this );

      *fout << "digraph osg_scenegraph { "<<_rankdir<< std::endl;

      *fout << _nodes.str() << _edges.str();

      *fout << "}" << std::endl;

      _nodes.clear();
      _edges.clear();
      _objectMap.clear();

      return true;
    }

    return false;
  }

  void BaseDotVisitor::apply(Node& node) {
    int id;
    if ( getOrCreateId( &node, id ) ) {
      handle( node, id );
      handleNodeAndTraverse( node, id );
    }
  }

  void BaseDotVisitor::apply(Geode& node) {
    int id;
    if ( getOrCreateId( &node, id ) ) {
      handle( node, id );
      handleNodeAndTraverse( node, id );

      unsigned int i;
      for ( i = 0; i < node.getNumDrawables(); i++ ) {
        osg::Drawable* drawable = node.getDrawable( i );
        int id2;
        if ( getOrCreateId( drawable, id2 ) ) {
          handle( *drawable, id2 );
          osg::StateSet* s = drawable->getStateSet();
          if ( s ) {
            int id3;
            if ( getOrCreateId( s, id3 ) ) {
              handle( *s, id3 );
            }
            handle( *drawable, *s, id2, id3 );
          }
        }
        handle( node, *drawable, id, id2 );
      }

    }

  }

  void BaseDotVisitor::apply(Group& node) {
    int id;

    if ( getOrCreateId( &node, id ) ) {
      handle( node, id );
      handleNodeAndTraverse( node, id );

      unsigned int i;
      for ( i = 0; i < node.getNumChildren(); i++ ) {
        osg::Node* child = node.getChild( i );
        //handleNodeAndTraverse( *child );
        int id2;
        getOrCreateId( child, id2 );
        handle( node, *child, id, id2 );
      }

    }

  }

  void BaseDotVisitor::handle(osg::Node& node, int id) {
  }

  void BaseDotVisitor::handle(osg::Geode& node, int id) {
  }

  void BaseDotVisitor::handle(osg::Group& node, int id) {
  }

  void BaseDotVisitor::handle(osg::Group& parent, osg::Node& child, int parentID, int childID ) {
  }

  void BaseDotVisitor::handleNodeAndTraverse(osg::Node& node, int id) {
    osg::StateSet* ss = node.getStateSet();
    if ( ss ) {
      int id2;
      if ( getOrCreateId( ss, id2 ) ) {
        handle( *ss, id2 );
      }
      handle( node, *ss, id, id2 );
    }
    traverse(node);
  }

  void BaseDotVisitor::handle(osg::StateSet& stateset, int id) {
  }

  void BaseDotVisitor::handle(osg::Node& node, osg::StateSet& stateset, int parentID, int childID) {
  }

  void BaseDotVisitor::handle(osg::Drawable& drawable, int id) {
  }

  void BaseDotVisitor::handle(osg::Drawable& drawable, osg::StateSet& stateset, int parentID, int childID ) {
  }

  void BaseDotVisitor::handle(osg::Geode& geode, osg::Drawable& drawable, int parentID, int childID ) {
  }

  bool BaseDotVisitor::getOrCreateId( osg::Object* object, int &id ) {
    assert( object );
    ObjectMap::iterator it = _objectMap.find( object );
    if ( it != _objectMap.end() ) {
      id = it->second;
      return false;
    }

    id = _objectMap.size();
    _objectMap[ object ] = id;
    return true;
  }

} // namespace osgDot
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <sstream>

#include <getopt.h>

// This is the JSON header
#include "jsoncpp/json/json.h"

#include <mosquittopp.h>

#include "sysfs_gpio.h"
#include "common/utils.h"
#include "common/mqtt_wrapper.h"
#include<mutex>

using namespace std;

mutex gpio_lock;

enum class TGpioDirection {
    Input,
    Output
};

struct TGpioDesc
{
    int Gpio;
    bool Inverted = false;
    string Name = "";
    TGpioDirection Direction = TGpioDirection::Output;
};

class THandlerConfig
{
    public:
        vector<TGpioDesc> Gpios;
        void AddGpio(TGpioDesc& gpio_desc) { Gpios.push_back(gpio_desc); };

        string DeviceName;

};

class TMQTTGpioHandler : public TMQTTWrapper
{
    typedef pair<TGpioDesc, TSysfsGpio> TChannelDesc;

	public:
        TMQTTGpioHandler(const TMQTTGpioHandler::TConfig& mqtt_config, const THandlerConfig& handler_config);
		~TMQTTGpioHandler();

		void OnConnect(int rc);
		void OnMessage(const struct mosquitto_message *message);
		void OnSubscribe(int mid, int qos_count, const int *granted_qos);

        void UpdateChannelValues();
        void InitInterrupts(int epfd);
        string GetChannelTopic(const TGpioDesc& gpio_desc);

    private:
        THandlerConfig Config;
        vector<TChannelDesc> Channels;

};

TMQTTGpioHandler::TMQTTGpioHandler(const TMQTTGpioHandler::TConfig& mqtt_config, const THandlerConfig& handler_config)
    : TMQTTWrapper(mqtt_config)
    , Config(handler_config)
{
    // init gpios
    for (const TGpioDesc& gpio_desc : handler_config.Gpios) {
        TSysfsGpio gpio_handler(gpio_desc.Gpio, gpio_desc.Inverted);
        gpio_handler.Export();
        if (gpio_handler.IsExported()) {
            if (gpio_desc.Direction == TGpioDirection::Input)
                gpio_handler.SetInput();
            else
                gpio_handler.SetOutput();
            Channels.push_back(make_pair(gpio_desc, gpio_handler));
        } else {
            cerr << "ERROR: unable to export gpio " << gpio_desc.Gpio << endl;
        }
    }

	Connect();
}

TMQTTGpioHandler::~TMQTTGpioHandler() {}

void TMQTTGpioHandler::OnConnect(int rc)
{
	printf("Connected with code %d.\n", rc);
	if(rc == 0){
		/* Only attempt to Subscribe on a successful connect. */
        string prefix = string("/devices/") + MQTTConfig.Id + "/";

        // Meta
        Publish(NULL, prefix + "/meta/name", Config.DeviceName, 0, true);

        gpio_lock.lock();
        for (const auto& channel_desc : Channels) {
            const auto& gpio_desc = channel_desc.first;

            //~ cout << "GPIO: " << gpio_desc.Name << endl;
            string control_prefix = prefix + "controls/" + gpio_desc.Name;

            Publish(NULL, control_prefix + "/meta/type", "switch", 0, true);
            if (gpio_desc.Direction == TGpioDirection::Input)
                Publish(NULL, control_prefix + "/meta/readonly", "1", 0, true);
            else
                Subscribe(NULL, control_prefix + "/on");
        }
        gpio_lock.unlock();
//~ /devices/293723-demo/controls/Demo-Switch 0
//~ /devices/293723-demo/controls/Demo-Switch/on 1
//~ /devices/293723-demo/controls/Demo-Switch/meta/type switch

	}
}

void TMQTTGpioHandler::OnMessage(const struct mosquitto_message *message)
{
    string topic = message->topic;
    string payload = static_cast<const char *>(message->payload);

    const vector<string>& tokens = StringSplit(topic, '/');

    if (  (tokens.size() == 6) &&
          (tokens[0] == "") && (tokens[1] == "devices") &&
          (tokens[2] == MQTTConfig.Id) && (tokens[3] == "controls") &&
          (tokens[5] == "on") )
    {
        gpio_lock.lock();
        for (TChannelDesc& channel_desc : Channels) {
            const auto& gpio_desc = channel_desc.first;
            if (gpio_desc.Direction != TGpioDirection::Output)
                continue;

            if (tokens[4] == gpio_desc.Name) {
                auto & gpio_handler = channel_desc.second;

                int val = payload == "0" ? 0 : 1;
                if (gpio_handler.SetValue(val) == 0) {
                    // echo, retained
                    Publish(NULL, GetChannelTopic(gpio_desc), payload, 0, true);
                }
            }
        }
        gpio_lock.unlock();
    }
}

void TMQTTGpioHandler::OnSubscribe(int mid, int qos_count, const int *granted_qos)
{
	printf("Subscription succeeded.\n");
}

string TMQTTGpioHandler::GetChannelTopic(const TGpioDesc& gpio_desc) {
    static string controls_prefix = string("/devices/") + MQTTConfig.Id + "/controls/";
    return (controls_prefix + gpio_desc.Name);
}

void TMQTTGpioHandler::UpdateChannelValues() {
    gpio_lock.lock();
    for (TChannelDesc& channel_desc : Channels) {
        const auto& gpio_desc = channel_desc.first;
        auto& gpio_handler = channel_desc.second;

        // vv order matters
        int cached = gpio_handler.GetCachedValue();
        int value = gpio_handler.GetValue();

        if (value >= 0) {
            // Buggy GPIO driver may yield any non-zero number instead of 1,
            // so make sure it's either 1 or 0 here.
            // See https://github.com/torvalds/linux/commit/25b35da7f4cce82271859f1b6eabd9f3bd41a2bb
            value = !!value;
            if ((cached < 0) || (cached != value))
                Publish(NULL, GetChannelTopic(gpio_desc), to_string(value), 0, true); // Publish current value (make retained)
        }
    }
    gpio_lock.unlock();
}

void TMQTTGpioHandler::InitInterrupts(int epfd){
   gpio_lock.lock();
   int n;
    for ( auto& channel_desc : Channels) {
        const auto& gpio_desc = channel_desc.first;
         auto& gpio_handler = channel_desc.second;

        gpio_handler.InterruptUp();
        if (gpio_handler.getInterruptSupport()) {
             n=epoll_ctl(epfd,EPOLL_CTL_ADD,gpio_handler.getFileDes(),gpio_handler.getEpollStruct());
            if (n != 0 ) {
                cout<<"epoll_ctl gained error with GPIO"<<gpio_desc.Gpio<<endl;
            }
        }
    }
    gpio_lock.unlock();

}

int main(int argc, char *argv[])
{
	int rc;
    THandlerConfig handler_config;
    TMQTTGpioHandler::TConfig mqtt_config;
    mqtt_config.Host = "localhost";
    mqtt_config.Port = 1883;
    string config_fname;
    int epfd;
    struct epoll_event events[20];

    int c;
    //~ int digit_optind = 0;
    //~ int aopt = 0, bopt = 0;
    //~ char *copt = 0, *dopt = 0;
    while ( (c = getopt(argc, argv, "c:h:p:")) != -1) {
        //~ int this_option_optind = optind ? optind : 1;
        switch (c) {
        case 'c':
            printf ("option c with value '%s'\n", optarg);
            config_fname = optarg;
            break;
        case 'p':
            printf ("option p with value '%s'\n", optarg);
            mqtt_config.Port = stoi(optarg);
            break;
        case 'h':
            printf ("option h with value '%s'\n", optarg);
            mqtt_config.Host = optarg;
            break;
        case '?':
            break;
        default:
            printf ("?? getopt returned character code 0%o ??\n", c);
        }
    }
    //~ if (optind < argc) {
        //~ printf ("non-option ARGV-elements: ");
        //~ while (optind < argc)
            //~ printf ("%s ", argv[optind++]);
        //~ printf ("\n");
    //~ }

    {
        // Let's parse it
        Json::Value root;
        Json::Reader reader;

        if (config_fname.empty()) {
            cerr << "Please specify config file with -c option" << endl;
            return 1;
        }

        ifstream myfile (config_fname);

        bool parsedSuccess = reader.parse(myfile,
                                       root,
                                       false);

        if(not parsedSuccess)
        {
            // Report failures and their locations
            // in the document.
            cerr << "Failed to parse JSON" << endl
               << reader.getFormatedErrorMessages()
               << endl;
            return 1;
        }

        handler_config.DeviceName = root["device_name"].asString();

         // Let's extract the array contained
         // in the root object
        const auto& array = root["channels"];

         // Iterate over sequence elements and
         // print its values
        for(unsigned int index=0; index<array.size();
             ++index)
        {
            const auto& item = array[index];
            TGpioDesc gpio_desc;
            gpio_desc.Gpio = item["gpio"].asInt();
            gpio_desc.Name = item["name"].asString();
            if (item.isMember("inverted"))
                gpio_desc.Inverted = item["inverted"].asBool();
            if (item.isMember("direction") && item["direction"].asString() == "input")
                gpio_desc.Direction = TGpioDirection::Input;

            handler_config.AddGpio(gpio_desc);

        }
    }

	mosqpp::lib_init();

    mqtt_config.Id = "wb-gpio";
    std::shared_ptr<TMQTTGpioHandler> mqtt_handler(new TMQTTGpioHandler(mqtt_config, handler_config));
    mqtt_handler->Init();

    rc= mqtt_handler->loop_start();
    if (rc != 0 ) {
        cout << "couldn't start mosquitto_loop_start ! " << rc << endl;
    }else {
        epfd = epoll_create(1);
        mqtt_handler->InitInterrupts(epfd);

        while(1){
            n= epoll_wait(epfd,events,20,15);

            mqtt_handler->UpdateChannelValues();
        }
	}

	mosqpp::lib_cleanup();

	return 0;
}
//build-dep libmosquittopp-dev libmosquitto-dev
// dep: libjsoncpp0 libmosquittopp libmosquitto

// 2420 2032
// 6008 2348 1972
<commit_msg>interrupts are handled separately now<commit_after>#include <iostream>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <sstream>

#include <getopt.h>

// This is the JSON header
#include "jsoncpp/json/json.h"

#include <mosquittopp.h>

#include "sysfs_gpio.h"
#include "common/utils.h"
#include "common/mqtt_wrapper.h"
#include<mutex>
#include<chrono>

using namespace std;
using  std::chrono::duration_cast;
using  std::chrono::milliseconds;
using  std::chrono::steady_clock;
mutex gpio_lock;

enum class TGpioDirection {
    Input,
    Output
};

struct TGpioDesc
{
    int Gpio;
    bool Inverted = false;
    string Name = "";
    TGpioDirection Direction = TGpioDirection::Output;
};

class THandlerConfig
{
    public:
        vector<TGpioDesc> Gpios;
        void AddGpio(TGpioDesc& gpio_desc) { Gpios.push_back(gpio_desc); };

        string DeviceName;

};

class TMQTTGpioHandler : public TMQTTWrapper
{
    typedef pair<TGpioDesc, TSysfsGpio> TChannelDesc;

	public:
        TMQTTGpioHandler(const TMQTTGpioHandler::TConfig& mqtt_config, const THandlerConfig& handler_config);
		~TMQTTGpioHandler();

		void OnConnect(int rc);
		void OnMessage(const struct mosquitto_message *message);
		void OnSubscribe(int mid, int qos_count, const int *granted_qos);

        void UpdateChannelValues();
        void InitInterrupts(int epfd);
        string GetChannelTopic(const TGpioDesc& gpio_desc);
        void HoldInterrupts(int count, struct epoll_event* events);

    private:
        THandlerConfig Config;
        vector<TChannelDesc> Channels;

        void updateValue(const TGpioDesc& gpio_desc,TSysfsGpio& gpio_handler);

};

TMQTTGpioHandler::TMQTTGpioHandler(const TMQTTGpioHandler::TConfig& mqtt_config, const THandlerConfig& handler_config)
    : TMQTTWrapper(mqtt_config)
    , Config(handler_config)
{
    // init gpios
    for (const TGpioDesc& gpio_desc : handler_config.Gpios) {
        TSysfsGpio gpio_handler(gpio_desc.Gpio, gpio_desc.Inverted);
        gpio_handler.Export();
        if (gpio_handler.IsExported()) {
            if (gpio_desc.Direction == TGpioDirection::Input)
                gpio_handler.SetInput();
            else
                gpio_handler.SetOutput();
            Channels.push_back(make_pair(gpio_desc, gpio_handler));
        } else {
            cerr << "ERROR: unable to export gpio " << gpio_desc.Gpio << endl;
        }
    }

	Connect();
}

TMQTTGpioHandler::~TMQTTGpioHandler() {}

void TMQTTGpioHandler::OnConnect(int rc)
{
	printf("Connected with code %d.\n", rc);
	if(rc == 0){
		/* Only attempt to Subscribe on a successful connect. */
        string prefix = string("/devices/") + MQTTConfig.Id + "/";

        // Meta
        Publish(NULL, prefix + "/meta/name", Config.DeviceName, 0, true);

        gpio_lock.lock();
        for (const auto& channel_desc : Channels) {
            const auto& gpio_desc = channel_desc.first;

            //~ cout << "GPIO: " << gpio_desc.Name << endl;
            string control_prefix = prefix + "controls/" + gpio_desc.Name;

            Publish(NULL, control_prefix + "/meta/type", "switch", 0, true);
            if (gpio_desc.Direction == TGpioDirection::Input)
                Publish(NULL, control_prefix + "/meta/readonly", "1", 0, true);
            else
                Subscribe(NULL, control_prefix + "/on");
        }
        gpio_lock.unlock();
//~ /devices/293723-demo/controls/Demo-Switch 0
//~ /devices/293723-demo/controls/Demo-Switch/on 1
//~ /devices/293723-demo/controls/Demo-Switch/meta/type switch

	}
}

void TMQTTGpioHandler::OnMessage(const struct mosquitto_message *message)
{
    string topic = message->topic;
    string payload = static_cast<const char *>(message->payload);

    const vector<string>& tokens = StringSplit(topic, '/');

    if (  (tokens.size() == 6) &&
          (tokens[0] == "") && (tokens[1] == "devices") &&
          (tokens[2] == MQTTConfig.Id) && (tokens[3] == "controls") &&
          (tokens[5] == "on") )
    {
        gpio_lock.lock();
        for (TChannelDesc& channel_desc : Channels) {
            const auto& gpio_desc = channel_desc.first;
            if (gpio_desc.Direction != TGpioDirection::Output)
                continue;

            if (tokens[4] == gpio_desc.Name) {
                auto & gpio_handler = channel_desc.second;

                int val = payload == "0" ? 0 : 1;
                if (gpio_handler.SetValue(val) == 0) {
                    // echo, retained
                    Publish(NULL, GetChannelTopic(gpio_desc), payload, 0, true);
                }
            }
        }
        gpio_lock.unlock();
    }
}

void TMQTTGpioHandler::OnSubscribe(int mid, int qos_count, const int *granted_qos)
{
	printf("Subscription succeeded.\n");
}

string TMQTTGpioHandler::GetChannelTopic(const TGpioDesc& gpio_desc) {
    static string controls_prefix = string("/devices/") + MQTTConfig.Id + "/controls/";
    return (controls_prefix + gpio_desc.Name);
}

void TMQTTGpioHandler::updateValue( const TGpioDesc& gpio_desc,TSysfsGpio& gpio_handler) {
        // vv order matters
        int cached = gpio_handler.GetCachedValue();
        int value = gpio_handler.GetValue();

        if (value >= 0) {
            // Buggy GPIO driver may yield any non-zero number instead of 1,
            // so make sure it's either 1 or 0 here.
            // See https://github.com/torvalds/linux/commit/25b35da7f4cce82271859f1b6eabd9f3bd41a2bb
            value = !!value;
            if ((cached < 0) || (cached != value))
                Publish(NULL, GetChannelTopic(gpio_desc), to_string(value), 0, true); // Publish current value (make retained)
        }
}
void TMQTTGpioHandler::UpdateChannelValues() {
    for (TChannelDesc& channel_desc : Channels) {
        const auto& gpio_desc = channel_desc.first;
        auto& gpio_handler = channel_desc.second;
        gpio_lock.lock();
        updateValue(gpio_desc,gpio_handler);
        gpio_lock.unlock();
       }
}

void TMQTTGpioHandler::InitInterrupts(int epfd){
   gpio_lock.lock();
   int n;
    for ( auto& channel_desc : Channels) {
        const auto& gpio_desc = channel_desc.first;
         auto& gpio_handler = channel_desc.second;

        gpio_handler.InterruptUp();
        if (gpio_handler.getInterruptSupport()) {
             n=epoll_ctl(epfd,EPOLL_CTL_ADD,gpio_handler.getFileDes(),&gpio_handler.getEpollStruct());
            if (n != 0 ) {
                cout<<"epoll_ctl gained error with GPIO"<<gpio_desc.Gpio<<endl;
            }
        }
    }
    gpio_lock.unlock();

}

void TMQTTGpioHandler::HoldInterrupts(int count, struct epoll_event* events){
    int i;
    for ( auto& channel_desc : Channels) {
        const auto& gpio_desc = channel_desc.first;
        auto& gpio_handler = channel_desc.second;
        for (i=0; i < count; i++){
            if (gpio_handler.getFileDes() == events[i].data.fd) {
                gpio_lock.lock();
                updateValue(gpio_desc, gpio_handler);
                gpio_lock.unlock();
            }
        }
    }

}

int main(int argc, char *argv[])
{
	int rc;
    THandlerConfig handler_config;
    TMQTTGpioHandler::TConfig mqtt_config;
    mqtt_config.Host = "localhost";
    mqtt_config.Port = 1883;
    string config_fname;
    int epfd;
    struct epoll_event events[20];

    int c,n;
    //~ int digit_optind = 0;
    //~ int aopt = 0, bopt = 0;
    //~ char *copt = 0, *dopt = 0;
    while ( (c = getopt(argc, argv, "c:h:p:")) != -1) {
        //~ int this_option_optind = optind ? optind : 1;
        switch (c) {
        case 'c':
            printf ("option c with value '%s'\n", optarg);
            config_fname = optarg;
            break;
        case 'p':
            printf ("option p with value '%s'\n", optarg);
            mqtt_config.Port = stoi(optarg);
            break;
        case 'h':
            printf ("option h with value '%s'\n", optarg);
            mqtt_config.Host = optarg;
            break;
        case '?':
            break;
        default:
            printf ("?? getopt returned character code 0%o ??\n", c);
        }
    }
    //~ if (optind < argc) {
        //~ printf ("non-option ARGV-elements: ");
        //~ while (optind < argc)
            //~ printf ("%s ", argv[optind++]);
        //~ printf ("\n");
    //~ }

    {
        // Let's parse it
        Json::Value root;
        Json::Reader reader;

        if (config_fname.empty()) {
            cerr << "Please specify config file with -c option" << endl;
            return 1;
        }

        ifstream myfile (config_fname);

        bool parsedSuccess = reader.parse(myfile,
                                       root,
                                       false);

        if(not parsedSuccess)
        {
            // Report failures and their locations
            // in the document.
            cerr << "Failed to parse JSON" << endl
               << reader.getFormatedErrorMessages()
               << endl;
            return 1;
        }

        handler_config.DeviceName = root["device_name"].asString();

         // Let's extract the array contained
         // in the root object
        const auto& array = root["channels"];

         // Iterate over sequence elements and
         // print its values
        for(unsigned int index=0; index<array.size();
             ++index)
        {
            const auto& item = array[index];
            TGpioDesc gpio_desc;
            gpio_desc.Gpio = item["gpio"].asInt();
            gpio_desc.Name = item["name"].asString();
            if (item.isMember("inverted"))
                gpio_desc.Inverted = item["inverted"].asBool();
            if (item.isMember("direction") && item["direction"].asString() == "input")
                gpio_desc.Direction = TGpioDirection::Input;

            handler_config.AddGpio(gpio_desc);

        }
    }

	mosqpp::lib_init();

    mqtt_config.Id = "wb-gpio";
    std::shared_ptr<TMQTTGpioHandler> mqtt_handler(new TMQTTGpioHandler(mqtt_config, handler_config));
    mqtt_handler->Init();

    rc= mqtt_handler->loop_start();
    if (rc != 0 ) {
        cout << "couldn't start mosquitto_loop_start ! " << rc << endl;
    }else {
        epfd = epoll_create(1);
        mqtt_handler->InitInterrupts(epfd);
        steady_clock::time_point start;
        int interval;
        while(1){
            start=steady_clock::now();
            n= epoll_wait(epfd,events,20,500);
            interval = duration_cast<milliseconds>(steady_clock::now() - start).count() ;
            if ( interval > 400) {
                mqtt_handler->UpdateChannelValues();
            }else {
                mqtt_handler->HoldInterrupts(n,events);
            }
        }
	}

	mosqpp::lib_cleanup();

	return 0;
}
//build-dep libmosquittopp-dev libmosquitto-dev
// dep: libjsoncpp0 libmosquittopp libmosquitto

// 2420 2032
// 6008 2348 1972
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file rlp.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 * RLP test functions.
 */

#include <fstream>
#include <sstream>

#include <boost/test/unit_test.hpp>

#include <libdevcore/Log.h>
#include <libdevcore/RLP.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <algorithm>
#include "../JsonSpiritHeaders.h"
#include "../TestHelper.h"

using namespace std;
using namespace dev;
namespace js = json_spirit;

namespace dev
{
	namespace test
	{
		void buildRLP(js::mValue& _v, RLPStream& _rlp);
		void checkRLPAgainstJson(js::mValue& v, RLP& u);

		void doRlpTests(json_spirit::mValue& v, bool _fillin)
		{
			for (auto& i: v.get_obj())
			{
				js::mObject& o = i.second.get_obj();
				if (test::Options::get().singleTest && test::Options::get().singleTestName != i.first)
				{
					o.clear();
					continue;
				}

				std::cout << "  " << i.first << std::endl;
				TBOOST_REQUIRE((o.count("out") > 0));
				TBOOST_REQUIRE((!o["out"].is_null()));

				if (_fillin)
				{
					try
					{
						bytes payloadToDecode = fromHex(o["out"].get_str());
						RLP payload(payloadToDecode);
						if (payload.isEmpty())
							BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Decoded Empty RLP!"));
						o["in"] = "VALID";
					}
					catch (Exception const& _e)
					{
						cnote << "Exception: " << diagnostic_information(_e);
						o["in"] = "INVALID";
					}
					catch (std::exception const& _e)
					{
						cnote << "rlp exception: " << _e.what();
						o["in"] = "INVALID";
					}
				}
				else
				{
					//Check Encode
					TBOOST_REQUIRE((o.count("in") > 0));
					int skipEncode = 0;
					if (o["in"].type() == js::str_type)
					{
						if (o["in"].get_str() == "INVALID")
							skipEncode = 1;
						else	if (o["in"].get_str() == "VALID")
							skipEncode = 2;
					}

					if (skipEncode == 0)
					{
						RLPStream s;
						dev::test::buildRLP(o["in"], s);
						string computedText = toHex(s.out());

						std::string expectedText(o["out"].get_str());
						std::transform(expectedText.begin(), expectedText.end(), expectedText.begin(), ::tolower );

						std::stringstream msg;
						msg << "Encoding Failed: expected: " << expectedText << std::endl;
						msg << " But Computed: " << computedText;
						TBOOST_CHECK_MESSAGE(
							(expectedText == computedText),
							msg.str()
							);
					}

					//Check Decode
					// Uses the same test cases as encoding but in reverse.
					// We read into the string of hex values, convert to bytes,
					// and then compare the output structure to the json of the
					// input object.
					bool was_exception = false;
					js::mValue& inputData = o["in"];
					try
					{
						bytes payloadToDecode = fromHex(o["out"].get_str());
						RLP payload(payloadToDecode);

						if (skipEncode == 0)
							dev::test::checkRLPAgainstJson(inputData, payload);
					}
					catch (Exception const& _e)
					{
						cnote << "Exception: " << diagnostic_information(_e);
						was_exception = true;
					}
					catch (std::exception const& _e)
					{
						cnote << "rlp exception: " << _e.what();
						was_exception = true;
					}

					//Expect exception as input is INVALID
					if (skipEncode == 1 && was_exception)
						continue;

					//Expect exception as input is INVALID
					if (skipEncode == 1 && !was_exception)
						TBOOST_ERROR("Expected RLP Exception as rlp should be invalid!");

					if (was_exception)
						TBOOST_ERROR("Unexpected RLP Exception!");
				}
			}
		}

		void buildRLP(js::mValue& _v, RLPStream& _rlp)
		{
			if (_v.type() == js::array_type)
			{
				RLPStream s;
				for (auto& i: _v.get_array())
					buildRLP(i, s);
				_rlp.appendList(s.out());
			}
			else if (_v.type() == js::int_type)
				_rlp.append(_v.get_uint64());
			else if (_v.type() == js::str_type)
			{
				auto s = _v.get_str();
				if (s.size() && s[0] == '#')
					_rlp.append(bigint(s.substr(1)));
				else
					_rlp.append(s);
			}
		}

		void checkRLPAgainstJson(js::mValue& v, RLP& u)
		{
			if ( v.type() == js::str_type )
			{
				const std::string& expectedText = v.get_str();
				if ( !expectedText.empty() && expectedText.front() == '#' )
				{
					// Deal with bigint instead of a raw string
					std::string bigIntStr = expectedText.substr(1,expectedText.length()-1);
					std::stringstream bintStream(bigIntStr);
					bigint val;
					bintStream >> val;
					TBOOST_CHECK(( !u.isList() ));
					TBOOST_CHECK(( !u.isNull() ));
					TBOOST_CHECK(( u == val ));
				}
				else
				{
					TBOOST_CHECK(( !u.isList() ));
					TBOOST_CHECK(( !u.isNull() ));
					TBOOST_CHECK(( u.isData() ));
					TBOOST_CHECK(( u.size() == expectedText.length() ));
					TBOOST_CHECK(( u == expectedText ));
				}
			}
			else if ( v.type() == js::int_type )
			{
				const int expectedValue = v.get_int();
				TBOOST_CHECK(( u.isInt() ));
				TBOOST_CHECK(( !u.isList() ));
				TBOOST_CHECK(( !u.isNull() ));
				TBOOST_CHECK(( u == expectedValue ));
			}
			else if ( v.type() == js::array_type )
			{
				TBOOST_CHECK(( u.isList() ));
				TBOOST_CHECK(( !u.isInt() ));
				TBOOST_CHECK(( !u.isData() ));
				js::mArray& arr = v.get_array();
				TBOOST_CHECK(( u.itemCount() == arr.size() ));
				unsigned i;
				for( i = 0; i < arr.size(); i++ )
				{
					RLP item = u[i];
					checkRLPAgainstJson(arr[i], item);
				}
			}
			else
			{
				TBOOST_ERROR("Invalid Javascript object!");
			}
		}
	}
}

BOOST_AUTO_TEST_SUITE(RlpTests)

BOOST_AUTO_TEST_CASE(invalidRLPtest)
{
	dev::test::executeTests("invalidRLPTest", "/RLPTests", dev::test::getFolder(__FILE__) + "/RLPTestsFiller", dev::test::doRlpTests);
}

BOOST_AUTO_TEST_CASE(rlptest)
{
	dev::test::executeTests("rlptest", "/RLPTests", dev::test::getFolder(__FILE__) + "/RLPTestsFiller", dev::test::doRlpTests);
}

BOOST_AUTO_TEST_CASE(rlpRandom)
{
	test::Options::get();

	string testPath = dev::test::getTestPath();
	testPath += "/RLPTests/RandomRLPTests";

	vector<boost::filesystem::path> testFiles;
	boost::filesystem::directory_iterator iterator(testPath);
	for(; iterator != boost::filesystem::directory_iterator(); ++iterator)
		if (boost::filesystem::is_regular_file(iterator->path()) && iterator->path().extension() == ".json")
			testFiles.push_back(iterator->path());

	for (auto& path: testFiles)
	{
		try
		{
			cnote << "Testing ..." << path.filename();
			json_spirit::mValue v;
			string s = asString(dev::contents(path.string()));
			TBOOST_REQUIRE_MESSAGE((s.length() > 0), "Content of " + path.string() + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?");
			json_spirit::read_string(s, v);
			test::Listener::notifySuiteStarted(path.filename().string());
			dev::test::doRlpTests(v, false);
		}

		catch (Exception const& _e)
		{
			TBOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e));
		}
		catch (std::exception const& _e)
		{
			TBOOST_ERROR("Failed test with Exception: " << _e.what());
		}
	}
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>RLP test refactoring: style<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file rlp.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 * RLP test functions.
 */

#include <fstream>
#include <sstream>

#include <boost/test/unit_test.hpp>

#include <libdevcore/Log.h>
#include <libdevcore/RLP.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <algorithm>
#include "../JsonSpiritHeaders.h"
#include "../TestHelper.h"

using namespace std;
using namespace dev;
namespace js = json_spirit;

namespace dev
{
	namespace test
	{
		void buildRLP(js::mValue& _v, RLPStream& _rlp);
		void checkRLPAgainstJson(js::mValue& v, RLP& u);
		enum class RlpType
		{
			Valid,
			Invalid,
			Test
		};

		void doRlpTests(json_spirit::mValue& v, bool _fillin)
		{
			for (auto& i: v.get_obj())
			{
				js::mObject& o = i.second.get_obj();
				if (test::Options::get().singleTest && test::Options::get().singleTestName != i.first)
				{
					o.clear();
					continue;
				}

				cout << "  " << i.first << endl;
				TBOOST_REQUIRE((o.count("out") > 0));
				TBOOST_REQUIRE((!o["out"].is_null()));

				if (_fillin)
				{
					try
					{
						bytes payloadToDecode = fromHex(o["out"].get_str());
						RLP payload(payloadToDecode);
						if (payload.isEmpty())
							BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Decoded Empty RLP!"));
						o["in"] = "VALID";
					}
					catch (Exception const& _e)
					{
						cnote << "Exception: " << diagnostic_information(_e);
						o["in"] = "INVALID";
					}
					catch (std::exception const& _e)
					{
						cnote << "rlp exception: " << _e.what();
						o["in"] = "INVALID";
					}
				}
				else
				{
					//Check Encode
					TBOOST_REQUIRE((o.count("in") > 0));
					RlpType rlpType = RlpType::Test;
					if (o["in"].type() == js::str_type)
					{
						if (o["in"].get_str() == "INVALID")
							rlpType = RlpType::Invalid;
						else	if (o["in"].get_str() == "VALID")
							rlpType = RlpType::Valid;
					}

					if (rlpType == RlpType::Test)
					{
						RLPStream s;
						dev::test::buildRLP(o["in"], s);
						string computedText = toHex(s.out());

						string expectedText(o["out"].get_str());
						transform(expectedText.begin(), expectedText.end(), expectedText.begin(), ::tolower );

						stringstream msg;
						msg << "Encoding Failed: expected: " << expectedText << std::endl;
						msg << " But Computed: " << computedText;
						TBOOST_CHECK_MESSAGE(
							(expectedText == computedText),
							msg.str()
							);
					}

					//Check Decode
					// Uses the same test cases as encoding but in reverse.
					// We read into the string of hex values, convert to bytes,
					// and then compare the output structure to the json of the
					// input object.
					bool was_exception = false;
					js::mValue& inputData = o["in"];
					try
					{
						bytes payloadToDecode = fromHex(o["out"].get_str());
						RLP payload(payloadToDecode);

						if (rlpType == RlpType::Test)
							dev::test::checkRLPAgainstJson(inputData, payload);
					}
					catch (Exception const& _e)
					{
						cnote << "Exception: " << diagnostic_information(_e);
						was_exception = true;
					}
					catch (exception const& _e)
					{
						cnote << "rlp exception: " << _e.what();
						was_exception = true;
					}

					//Expect exception as input is INVALID
					if (rlpType == RlpType::Invalid && was_exception)
						continue;

					//Check that there was an exception as input is INVALID
					if (rlpType == RlpType::Invalid && !was_exception)
						TBOOST_ERROR("Expected RLP Exception as rlp should be invalid!");

					//input is VALID check that there was no exceptions
					if (was_exception)
						TBOOST_ERROR("Unexpected RLP Exception!");
				}
			}
		}

		void buildRLP(js::mValue& _v, RLPStream& _rlp)
		{
			if (_v.type() == js::array_type)
			{
				RLPStream s;
				for (auto& i: _v.get_array())
					buildRLP(i, s);
				_rlp.appendList(s.out());
			}
			else if (_v.type() == js::int_type)
				_rlp.append(_v.get_uint64());
			else if (_v.type() == js::str_type)
			{
				auto s = _v.get_str();
				if (s.size() && s[0] == '#')
					_rlp.append(bigint(s.substr(1)));
				else
					_rlp.append(s);
			}
		}

		void checkRLPAgainstJson(js::mValue& v, RLP& u)
		{
			if ( v.type() == js::str_type )
			{
				const string& expectedText = v.get_str();
				if ( !expectedText.empty() && expectedText.front() == '#' )
				{
					// Deal with bigint instead of a raw string
					string bigIntStr = expectedText.substr(1,expectedText.length()-1);
					stringstream bintStream(bigIntStr);
					bigint val;
					bintStream >> val;
					TBOOST_CHECK(( !u.isList() ));
					TBOOST_CHECK(( !u.isNull() ));
					TBOOST_CHECK(( u == val ));
				}
				else
				{
					TBOOST_CHECK(( !u.isList() ));
					TBOOST_CHECK(( !u.isNull() ));
					TBOOST_CHECK(( u.isData() ));
					TBOOST_CHECK(( u.size() == expectedText.length() ));
					TBOOST_CHECK(( u == expectedText ));
				}
			}
			else if ( v.type() == js::int_type )
			{
				const int expectedValue = v.get_int();
				TBOOST_CHECK(( u.isInt() ));
				TBOOST_CHECK(( !u.isList() ));
				TBOOST_CHECK(( !u.isNull() ));
				TBOOST_CHECK(( u == expectedValue ));
			}
			else if ( v.type() == js::array_type )
			{
				TBOOST_CHECK(( u.isList() ));
				TBOOST_CHECK(( !u.isInt() ));
				TBOOST_CHECK(( !u.isData() ));
				js::mArray& arr = v.get_array();
				TBOOST_CHECK(( u.itemCount() == arr.size() ));
				unsigned i;
				for( i = 0; i < arr.size(); i++ )
				{
					RLP item = u[i];
					checkRLPAgainstJson(arr[i], item);
				}
			}
			else
			{
				TBOOST_ERROR("Invalid Javascript object!");
			}
		}
	}
}

BOOST_AUTO_TEST_SUITE(RlpTests)

BOOST_AUTO_TEST_CASE(invalidRLPtest)
{
	dev::test::executeTests("invalidRLPTest", "/RLPTests", dev::test::getFolder(__FILE__) + "/RLPTestsFiller", dev::test::doRlpTests);
}

BOOST_AUTO_TEST_CASE(rlptest)
{
	dev::test::executeTests("rlptest", "/RLPTests", dev::test::getFolder(__FILE__) + "/RLPTestsFiller", dev::test::doRlpTests);
}

BOOST_AUTO_TEST_CASE(rlpRandom)
{
	test::Options::get();

	string testPath = dev::test::getTestPath();
	testPath += "/RLPTests/RandomRLPTests";

	vector<boost::filesystem::path> testFiles;
	boost::filesystem::directory_iterator iterator(testPath);
	for(; iterator != boost::filesystem::directory_iterator(); ++iterator)
		if (boost::filesystem::is_regular_file(iterator->path()) && iterator->path().extension() == ".json")
			testFiles.push_back(iterator->path());

	for (auto& path: testFiles)
	{
		try
		{
			cnote << "Testing ..." << path.filename();
			json_spirit::mValue v;
			string s = asString(dev::contents(path.string()));
			TBOOST_REQUIRE_MESSAGE((s.length() > 0), "Content of " + path.string() + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?");
			json_spirit::read_string(s, v);
			test::Listener::notifySuiteStarted(path.filename().string());
			dev::test::doRlpTests(v, false);
		}

		catch (Exception const& _e)
		{
			TBOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e));
		}
		catch (std::exception const& _e)
		{
			TBOOST_ERROR("Failed test with Exception: " << _e.what());
		}
	}
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: includes.cxx,v $
 * $Revision: 1.8 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_codemaker.hxx"

#include "includes.hxx"

#include "dumputils.hxx"

#include "codemaker/dependencies.hxx"
#include "codemaker/global.hxx"
#include "codemaker/typemanager.hxx"
#include "codemaker/unotype.hxx"

#include "osl/diagnose.h"
#include "rtl/string.hxx"
#include "rtl/ustring.hxx"
#include "sal/types.h"

#include <vector>

using codemaker::cppumaker::Includes;

Includes::Includes(
    TypeManager const & manager, codemaker::Dependencies const & dependencies,
    bool hpp):
    m_manager(manager), m_map(dependencies.getMap()), m_hpp(hpp),
    m_includeAny(dependencies.hasAnyDependency()), m_includeReference(false),
    m_includeSequence(dependencies.hasSequenceDependency()),
    m_includeType(dependencies.hasTypeDependency()),
    m_includeCppuMacrosHxx(false), m_includeCppuUnotypeHxx(false),
    m_includeOslDoublecheckedlockingH(false), m_includeOslMutexHxx(false),
    m_includeRtlStrbufHxx(false), m_includeRtlStringH(false),
    m_includeRtlTextencH(false), m_includeRtlUstrbufHxx(false),
    m_includeRtlUstringH(false),
    m_includeRtlUstringHxx(dependencies.hasStringDependency()),
    m_includeSalTypesH(
        dependencies.hasBooleanDependency() || dependencies.hasByteDependency()
        || dependencies.hasShortDependency()
        || dependencies.hasUnsignedShortDependency()
        || dependencies.hasLongDependency()
        || dependencies.hasUnsignedShortDependency()
        || dependencies.hasHyperDependency()
        || dependencies.hasUnsignedHyperDependency()
        || dependencies.hasCharDependency()),
    m_includeTypelibTypeclassH(false),
    m_includeTypelibTypedescriptionH(false)
{}

Includes::~Includes()
{}

void Includes::add(rtl::OString const & registryType) {
    sal_Int32 rank;
    std::vector< rtl::OString > args;
    rtl::OString type(
        codemaker::UnoType::decompose(registryType, &rank, &args));
    if (rank > 0) {
        m_includeSequence = true;
    }
    switch (codemaker::UnoType::getSort(type)) {
    case codemaker::UnoType::SORT_VOID:
        OSL_ASSERT(args.empty());
        OSL_ASSERT(false);
        break;

    case codemaker::UnoType::SORT_BOOLEAN:
    case codemaker::UnoType::SORT_BYTE:
    case codemaker::UnoType::SORT_SHORT:
    case codemaker::UnoType::SORT_UNSIGNED_SHORT:
    case codemaker::UnoType::SORT_LONG:
    case codemaker::UnoType::SORT_UNSIGNED_LONG:
    case codemaker::UnoType::SORT_HYPER:
    case codemaker::UnoType::SORT_UNSIGNED_HYPER:
    case codemaker::UnoType::SORT_CHAR:
        OSL_ASSERT(args.empty());
        m_includeSalTypesH = true;
        break;

    case codemaker::UnoType::SORT_FLOAT:
    case codemaker::UnoType::SORT_DOUBLE:
        OSL_ASSERT(args.empty());
        break;

    case codemaker::UnoType::SORT_STRING:
        OSL_ASSERT(args.empty());
        m_includeRtlUstringHxx = true;
        break;

    case codemaker::UnoType::SORT_TYPE:
        OSL_ASSERT(args.empty());
        m_includeType = true;
        break;

    case codemaker::UnoType::SORT_ANY:
        OSL_ASSERT(args.empty());
        m_includeAny = true;
        break;

    case codemaker::UnoType::SORT_COMPLEX:
        m_map.insert(
            codemaker::Dependencies::Map::value_type(
                type, codemaker::Dependencies::KIND_NO_BASE));
        {for (std::vector< rtl::OString >::iterator i(args.begin());
              i != args.end(); ++i)
        {
            add(*i);
        }}
        break;

    default:
        OSL_ASSERT(false);
        break;
    }
}

namespace {

void dumpEmptyLineBeforeFirst(FileStream & out, bool * first) {
    OSL_ASSERT(first != 0);
    if (*first) {
        out << "\n";
        *first = false;
    }
}

}

void Includes::dump(FileStream & out, rtl::OString const * companionHdl) {
    OSL_ASSERT(companionHdl == 0 || m_hpp);
    if (!m_includeReference) {
        for (codemaker::Dependencies::Map::iterator i(m_map.begin());
             i != m_map.end(); ++i)
        {
            if (isInterfaceType(i->first)) {
                m_includeReference = true;
                break;
            }
        }
    }
    out << "#include \"sal/config.h\"\n";
    if (companionHdl) {
        out << "\n";
        dumpInclude(out, *companionHdl, false);
    }
    bool first = true;
    for (codemaker::Dependencies::Map::iterator i(m_map.begin());
         i != m_map.end(); ++i)
    {
        dumpEmptyLineBeforeFirst(out, &first);
        if (m_hpp || i->second == codemaker::Dependencies::KIND_BASE
            || !isInterfaceType(i->first))
        {
            dumpInclude(out, i->first, m_hpp);
        } else {
            bool ns = dumpNamespaceOpen(out, i->first, false);
            if (ns) {
                out << " ";
            }
            out << "class ";
            dumpTypeIdentifier(out, i->first);
            out << ";";
            if (ns) {
                out << " ";
            }
            dumpNamespaceClose(out, i->first, false);
            out << "\n";
        }
    }
    static char const * hxxExtension[2] = { "h", "hxx" };
    if (m_includeAny) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"com/sun/star/uno/Any." << hxxExtension[m_hpp]
            << "\"\n";
    }
    if (m_includeReference) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"com/sun/star/uno/Reference."
            << hxxExtension[m_hpp] << "\"\n";
    }
    if (m_includeSequence) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"com/sun/star/uno/Sequence." << hxxExtension[m_hpp]
            << "\"\n";
    }
    if (m_includeType) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"com/sun/star/uno/Type." << hxxExtension[m_hpp]
            << "\"\n";
    }
    if (m_includeCppuMacrosHxx) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"cppu/macros.hxx\"\n");
    }
    if (m_includeCppuUnotypeHxx) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"cppu/unotype.hxx\"\n");
    }
    if (m_includeOslDoublecheckedlockingH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"osl/doublecheckedlocking.h\"\n");
    }
    if (m_includeOslMutexHxx) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"osl/mutex.hxx\"\n";
    }
    if (m_includeRtlStrbufHxx) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"rtl/strbuf.hxx\"\n");
    }
    if (m_includeRtlStringH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"rtl/string.h\"\n";
    }
    if (m_includeRtlTextencH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"rtl/textenc.h\"\n";
    }
    if (m_includeRtlUstrbufHxx) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"rtl/ustrbuf.hxx\"\n");
    }
    if (m_includeRtlUstringH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"rtl/ustring.h\"\n";
    }
    if (m_includeRtlUstringHxx) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"rtl/ustring.hxx\"\n");
    }
    if (m_includeSalTypesH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"sal/types.h\"\n";
    }
    if (m_includeTypelibTypeclassH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"typelib/typeclass.h\"\n");
    }
    if (m_includeTypelibTypedescriptionH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"typelib/typedescription.h\"\n");
    }
}

void Includes::dumpInclude(
    FileStream & out, rtl::OString const & registryType, bool hpp,
    rtl::OString const & suffix)
{
    static char const * extension[2] = { "hdl", "hpp" };
    out << "#include \""
        << registryType;
    if (suffix.getLength() > 0) {
        out << "/" << suffix;
    }
    out << "." << extension[hpp] << "\"\n";
}

bool Includes::isInterfaceType(rtl::OString const & registryType) const {
    return m_manager.getTypeClass(registryType) == RT_TYPE_INTERFACE;
}
<commit_msg>INTEGRATION: CWS jsc21 (1.7.34); FILE MERGED 2008/04/23 09:48:24 jsc 1.7.34.2: RESYNC: (1.7-1.8); FILE MERGED 2008/02/13 08:54:57 jsc 1.7.34.1: #i72964# remove external header guards<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: includes.cxx,v $
 * $Revision: 1.9 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_codemaker.hxx"

#include "includes.hxx"

#include "dumputils.hxx"

#include "codemaker/dependencies.hxx"
#include "codemaker/global.hxx"
#include "codemaker/typemanager.hxx"
#include "codemaker/unotype.hxx"

#include "osl/diagnose.h"
#include "rtl/string.hxx"
#include "rtl/ustring.hxx"
#include "sal/types.h"

#include <vector>

using codemaker::cppumaker::Includes;

Includes::Includes(
    TypeManager const & manager, codemaker::Dependencies const & dependencies,
    bool hpp):
    m_manager(manager), m_map(dependencies.getMap()), m_hpp(hpp),
    m_includeAny(dependencies.hasAnyDependency()), m_includeReference(false),
    m_includeSequence(dependencies.hasSequenceDependency()),
    m_includeType(dependencies.hasTypeDependency()),
    m_includeCppuMacrosHxx(false), m_includeCppuUnotypeHxx(false),
    m_includeOslDoublecheckedlockingH(false), m_includeOslMutexHxx(false),
    m_includeRtlStrbufHxx(false), m_includeRtlStringH(false),
    m_includeRtlTextencH(false), m_includeRtlUstrbufHxx(false),
    m_includeRtlUstringH(false),
    m_includeRtlUstringHxx(dependencies.hasStringDependency()),
    m_includeSalTypesH(
        dependencies.hasBooleanDependency() || dependencies.hasByteDependency()
        || dependencies.hasShortDependency()
        || dependencies.hasUnsignedShortDependency()
        || dependencies.hasLongDependency()
        || dependencies.hasUnsignedShortDependency()
        || dependencies.hasHyperDependency()
        || dependencies.hasUnsignedHyperDependency()
        || dependencies.hasCharDependency()),
    m_includeTypelibTypeclassH(false),
    m_includeTypelibTypedescriptionH(false)
{}

Includes::~Includes()
{}

void Includes::add(rtl::OString const & registryType) {
    sal_Int32 rank;
    std::vector< rtl::OString > args;
    rtl::OString type(
        codemaker::UnoType::decompose(registryType, &rank, &args));
    if (rank > 0) {
        m_includeSequence = true;
    }
    switch (codemaker::UnoType::getSort(type)) {
    case codemaker::UnoType::SORT_VOID:
        OSL_ASSERT(args.empty());
        OSL_ASSERT(false);
        break;

    case codemaker::UnoType::SORT_BOOLEAN:
    case codemaker::UnoType::SORT_BYTE:
    case codemaker::UnoType::SORT_SHORT:
    case codemaker::UnoType::SORT_UNSIGNED_SHORT:
    case codemaker::UnoType::SORT_LONG:
    case codemaker::UnoType::SORT_UNSIGNED_LONG:
    case codemaker::UnoType::SORT_HYPER:
    case codemaker::UnoType::SORT_UNSIGNED_HYPER:
    case codemaker::UnoType::SORT_CHAR:
        OSL_ASSERT(args.empty());
        m_includeSalTypesH = true;
        break;

    case codemaker::UnoType::SORT_FLOAT:
    case codemaker::UnoType::SORT_DOUBLE:
        OSL_ASSERT(args.empty());
        break;

    case codemaker::UnoType::SORT_STRING:
        OSL_ASSERT(args.empty());
        m_includeRtlUstringHxx = true;
        break;

    case codemaker::UnoType::SORT_TYPE:
        OSL_ASSERT(args.empty());
        m_includeType = true;
        break;

    case codemaker::UnoType::SORT_ANY:
        OSL_ASSERT(args.empty());
        m_includeAny = true;
        break;

    case codemaker::UnoType::SORT_COMPLEX:
        m_map.insert(
            codemaker::Dependencies::Map::value_type(
                type, codemaker::Dependencies::KIND_NO_BASE));
        {for (std::vector< rtl::OString >::iterator i(args.begin());
              i != args.end(); ++i)
        {
            add(*i);
        }}
        break;

    default:
        OSL_ASSERT(false);
        break;
    }
}

namespace {

void dumpEmptyLineBeforeFirst(FileStream & out, bool * first) {
    OSL_ASSERT(first != 0);
    if (*first) {
        out << "\n";
        *first = false;
    }
}

}

void Includes::dump(FileStream & out, rtl::OString const * companionHdl) {
    OSL_ASSERT(companionHdl == 0 || m_hpp);
    if (!m_includeReference) {
        for (codemaker::Dependencies::Map::iterator i(m_map.begin());
             i != m_map.end(); ++i)
        {
            if (isInterfaceType(i->first)) {
                m_includeReference = true;
                break;
            }
        }
    }
    out << "#include \"sal/config.h\"\n";
    if (companionHdl) {
        out << "\n";
        dumpInclude(out, *companionHdl, false);
    }
    bool first = true;
    for (codemaker::Dependencies::Map::iterator i(m_map.begin());
         i != m_map.end(); ++i)
    {
        dumpEmptyLineBeforeFirst(out, &first);
        if (m_hpp || i->second == codemaker::Dependencies::KIND_BASE
            || !isInterfaceType(i->first))
        {
            dumpInclude(out, i->first, m_hpp);
        } else {
            bool ns = dumpNamespaceOpen(out, i->first, false);
            if (ns) {
                out << " ";
            }
            out << "class ";
            dumpTypeIdentifier(out, i->first);
            out << ";";
            if (ns) {
                out << " ";
            }
            dumpNamespaceClose(out, i->first, false);
            out << "\n";
        }
    }
    static char const * hxxExtension[2] = { "h", "hxx" };
    if (m_includeAny) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"com/sun/star/uno/Any." << hxxExtension[m_hpp] << "\"\n";
    }
    if (m_includeReference) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"com/sun/star/uno/Reference." << hxxExtension[m_hpp] << "\"\n";
    }
    if (m_includeSequence) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"com/sun/star/uno/Sequence." << hxxExtension[m_hpp] << "\"\n";
    }
    if (m_includeType) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"com/sun/star/uno/Type." << hxxExtension[m_hpp] << "\"\n";
    }
    if (m_includeCppuMacrosHxx) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"cppu/macros.hxx\"\n");
    }
    if (m_includeCppuUnotypeHxx) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"cppu/unotype.hxx\"\n");
    }
    if (m_includeOslDoublecheckedlockingH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"osl/doublecheckedlocking.h\"\n");
    }
    if (m_includeOslMutexHxx) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"osl/mutex.hxx\"\n";
    }
    if (m_includeRtlStrbufHxx) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"rtl/strbuf.hxx\"\n");
    }
    if (m_includeRtlStringH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"rtl/string.h\"\n";
    }
    if (m_includeRtlTextencH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"rtl/textenc.h\"\n";
    }
    if (m_includeRtlUstrbufHxx) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"rtl/ustrbuf.hxx\"\n");
    }
    if (m_includeRtlUstringH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"rtl/ustring.h\"\n";
    }
    if (m_includeRtlUstringHxx) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"rtl/ustring.hxx\"\n");
    }
    if (m_includeSalTypesH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << "#include \"sal/types.h\"\n";
    }
    if (m_includeTypelibTypeclassH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"typelib/typeclass.h\"\n");
    }
    if (m_includeTypelibTypedescriptionH) {
        dumpEmptyLineBeforeFirst(out, &first);
        out << ("#include \"typelib/typedescription.h\"\n");
    }
}

void Includes::dumpInclude(
    FileStream & out, rtl::OString const & registryType, bool hpp,
    rtl::OString const & suffix)
{
    static char const * extension[2] = { "hdl", "hpp" };
    out << "#include \"" << registryType;
    if (suffix.getLength() > 0) {
        out << "/" << suffix;
    }
    out << "." << extension[hpp] << "\"\n";
}

bool Includes::isInterfaceType(rtl::OString const & registryType) const {
    return m_manager.getTypeClass(registryType) == RT_TYPE_INTERFACE;
}
<|endoftext|>