<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2014 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"
#include "OgreScriptLexer.h"

namespace Ogre{
    ScriptTokenListPtr ScriptLexer::tokenize(const String &str, const String &source)
    {
        // State enums
        enum{ READY = 0, COMMENT, MULTICOMMENT, WORD, QUOTE, VAR, POSSIBLECOMMENT };

        // Set up some constant characters of interest
        const wchar_t varopener = '$', quote = '\"', slash = '/', backslash = '\\', openbrace = '{', closebrace = '}', colon = ':', star = '*', cr = '\r', lf = '\n';
        char c = 0, lastc = 0;

        String lexeme;
        uint32 line = 1, state = READY, lastQuote = 0;
        ScriptTokenListPtr tokens(OGRE_NEW_T(ScriptTokenList, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);

        // Iterate over the input
        String::const_iterator i = str.begin(), end = str.end();
        while(i != end)
        {
            lastc = c;
            c = *i;

            if(c == quote)
                lastQuote = line;

            switch(state)
            {
            case READY:
                if(c == slash && lastc == slash)
                {
                    // Comment start, clear out the lexeme
                    lexeme = "";
                    state = COMMENT;
                }
                else if(c == star && lastc == slash)
                {
                    lexeme = "";
                    state = MULTICOMMENT;
                }
                else if(c == quote)
                {
                    // Clear out the lexeme ready to be filled with quotes!
                    lexeme = c;
                    state = QUOTE;
                }
                else if(c == varopener)
                {
                    // Set up to read in a variable
                    lexeme = c;
                    state = VAR;
                }
                else if(isNewline(c))
                {
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                }
                else if(!isWhitespace(c))
                {
                    lexeme = c;
                    if(c == slash)
                        state = POSSIBLECOMMENT;
                    else
                        state = WORD;
                }
                break;
            case COMMENT:
                if(isNewline(c))
                {
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                break;
            case MULTICOMMENT:
                if(c == slash && lastc == star)
                    state = READY;
                break;
            case POSSIBLECOMMENT:
                if(c == slash && lastc == slash)
                {
                    lexeme = "";
                    state = COMMENT;
                    break;
                }
                else if(c == star && lastc == slash)
                {
                    lexeme = "";
                    state = MULTICOMMENT;
                    break;
                }
                else
                {
                    state = WORD;
                    OGRE_FALLTHROUGH;
                }
            case WORD:
                if(isNewline(c))
                {
                    setToken(lexeme, line, source, tokens.get());
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else if(isWhitespace(c))
                {
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else if(c == openbrace || c == closebrace || c == colon)
                {
                    setToken(lexeme, line, source, tokens.get());
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else
                {
                    lexeme += c;
                }
                break;
            case QUOTE:
                if(c != backslash)
                {
                    // Allow embedded quotes with escaping
                    if(c == quote && lastc == backslash)
                    {
                        lexeme += c;
                    }
                    else if(c == quote)
                    {
                        lexeme += c;
                        setToken(lexeme, line, source, tokens.get());
                        state = READY;
                    }
                    else
                    {
                        // Backtrack here and allow a backslash normally within the quote
                        if(lastc == backslash)
                            lexeme = lexeme + "\\" + c;
                        else
                            lexeme += c;
                    }
                }
                break;
            case VAR:
                if(isNewline(c))
                {
                    setToken(lexeme, line, source, tokens.get());
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else if(isWhitespace(c))
                {
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else if(c == openbrace || c == closebrace || c == colon)
                {
                    setToken(lexeme, line, source, tokens.get());
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else
                {
                    lexeme += c;
                }
                break;
            }

            // Separate check for newlines just to track line numbers
            if(c == cr || (c == lf && lastc != cr))
                line++;

            i++;
        }

        // Check for valid exit states
        if(state == WORD || state == VAR)
        {
            if(!lexeme.empty())
                setToken(lexeme, line, source, tokens.get());
        }
        else
        {
            if(state == QUOTE)
            {
                OGRE_EXCEPT(Exception::ERR_INVALID_STATE,
                    Ogre::String("no matching \" found for \" at line ") +
                    Ogre::StringConverter::toString(lastQuote),
                    "ScriptLexer::tokenize");
            }
        }

        return tokens;
    }

    void ScriptLexer::setToken(const Ogre::String &lexeme, Ogre::uint32 line, const String &source, Ogre::ScriptTokenList *tokens)
    {
        const char openBracket = '{', closeBracket = '}', colon = ':',
            quote = '\"', var = '$';

        ScriptTokenPtr token(OGRE_NEW_T(ScriptToken, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
        token->lexeme = lexeme;
        token->line = line;
        token->file = source;
        bool ignore = false;

        // Check the user token map first
        if(lexeme.size() == 1 && isNewline(lexeme[0]))
        {
            token->type = TID_NEWLINE;
            if(!tokens->empty() && tokens->back()->type == TID_NEWLINE)
                ignore = true;
        }
        else if(lexeme.size() == 1 && lexeme[0] == openBracket)
            token->type = TID_LBRACKET;
        else if(lexeme.size() == 1 && lexeme[0] == closeBracket)
            token->type = TID_RBRACKET;
        else if(lexeme.size() == 1 && lexeme[0] == colon)
            token->type = TID_COLON;
        else if(lexeme[0] == var)
            token->type = TID_VARIABLE;
        else
        {
            // This is either a non-zero length phrase or quoted phrase
            if(lexeme.size() >= 2 && lexeme[0] == quote && lexeme[lexeme.size() - 1] == quote)
            {
                token->type = TID_QUOTE;
            }
            else
            {
                token->type = TID_WORD;
            }
        }

        if(!ignore)
            tokens->push_back(token);
    }

    bool ScriptLexer::isWhitespace(Ogre::String::value_type c)
    {
        return c == ' ' || c == '\r' || c == '\t';
    }

    bool ScriptLexer::isNewline(Ogre::String::value_type c)
    {
        return c == '\n' || c == '\r';
    }

}

<commit_msg>Add errors for too many or too litle braces in scripts Closes #701.<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2014 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"
#include "OgreScriptLexer.h"

namespace Ogre{
    ScriptTokenListPtr ScriptLexer::tokenize(const String &str, const String &source)
    {
        // State enums
        enum{ READY = 0, COMMENT, MULTICOMMENT, WORD, QUOTE, VAR, POSSIBLECOMMENT };

        // Set up some constant characters of interest
        const wchar_t varopener = '$', quote = '\"', slash = '/', backslash = '\\', openbrace = '{', closebrace = '}', colon = ':', star = '*', cr = '\r', lf = '\n';
        char c = 0, lastc = 0;

        String lexeme;
        uint32 line = 1, state = READY, lastQuote = 0, firstOpenBrace = 0, braceLayer = 0;
        ScriptTokenListPtr tokens(OGRE_NEW_T(ScriptTokenList, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);

        // Iterate over the input
        String::const_iterator i = str.begin(), end = str.end();
        while(i != end)
        {
            lastc = c;
            c = *i;

            if(c == quote)
                lastQuote = line;

            if(state == READY || state == WORD || state == VAR)
            {
                if(c == openbrace)
                {
                    if(braceLayer == 0)
                        firstOpenBrace = line;

                    braceLayer ++;
                }
                else if(c == closebrace)
                {
                    if(braceLayer == 0)
                        OGRE_EXCEPT(Exception::ERR_INVALID_STATE,
                            Ogre::String("no matching open bracket '{' found for close bracket '}' at line ") +
                            Ogre::StringConverter::toString(line),
                            "ScriptLexer::tokenize");

                    braceLayer --;
                }
            }

            switch(state)
            {
            case READY:
                if(c == slash && lastc == slash)
                {
                    // Comment start, clear out the lexeme
                    lexeme = "";
                    state = COMMENT;
                }
                else if(c == star && lastc == slash)
                {
                    lexeme = "";
                    state = MULTICOMMENT;
                }
                else if(c == quote)
                {
                    // Clear out the lexeme ready to be filled with quotes!
                    lexeme = c;
                    state = QUOTE;
                }
                else if(c == varopener)
                {
                    // Set up to read in a variable
                    lexeme = c;
                    state = VAR;
                }
                else if(isNewline(c))
                {
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                }
                else if(!isWhitespace(c))
                {
                    lexeme = c;
                    if(c == slash)
                        state = POSSIBLECOMMENT;
                    else
                        state = WORD;
                }
                break;
            case COMMENT:
                if(isNewline(c))
                {
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                break;
            case MULTICOMMENT:
                if(c == slash && lastc == star)
                    state = READY;
                break;
            case POSSIBLECOMMENT:
                if(c == slash && lastc == slash)
                {
                    lexeme = "";
                    state = COMMENT;
                    break;
                }
                else if(c == star && lastc == slash)
                {
                    lexeme = "";
                    state = MULTICOMMENT;
                    break;
                }
                else
                {
                    state = WORD;
                    OGRE_FALLTHROUGH;
                }
            case WORD:
                if(isNewline(c))
                {
                    setToken(lexeme, line, source, tokens.get());
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else if(isWhitespace(c))
                {
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else if(c == openbrace || c == closebrace || c == colon)
                {
                    setToken(lexeme, line, source, tokens.get());
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else
                {
                    lexeme += c;
                }
                break;
            case QUOTE:
                if(c != backslash)
                {
                    // Allow embedded quotes with escaping
                    if(c == quote && lastc == backslash)
                    {
                        lexeme += c;
                    }
                    else if(c == quote)
                    {
                        lexeme += c;
                        setToken(lexeme, line, source, tokens.get());
                        state = READY;
                    }
                    else
                    {
                        // Backtrack here and allow a backslash normally within the quote
                        if(lastc == backslash)
                            lexeme = lexeme + "\\" + c;
                        else
                            lexeme += c;
                    }
                }
                break;
            case VAR:
                if(isNewline(c))
                {
                    setToken(lexeme, line, source, tokens.get());
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else if(isWhitespace(c))
                {
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else if(c == openbrace || c == closebrace || c == colon)
                {
                    setToken(lexeme, line, source, tokens.get());
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else
                {
                    lexeme += c;
                }
                break;
            }

            // Separate check for newlines just to track line numbers
            if(c == cr || (c == lf && lastc != cr))
                line++;

            i++;
        }

        // Check for valid exit states
        if(state == WORD || state == VAR)
        {
            if(!lexeme.empty())
                setToken(lexeme, line, source, tokens.get());
        }
        else
        {
            if(state == QUOTE)
            {
                OGRE_EXCEPT(Exception::ERR_INVALID_STATE,
                    Ogre::String("no matching \" found for \" at line ") +
                    Ogre::StringConverter::toString(lastQuote),
                    "ScriptLexer::tokenize");
            }
        }

        // Check that all opened brackets have been closed
        if (braceLayer == 1)
        {
            OGRE_EXCEPT(Exception::ERR_INVALID_STATE,
                Ogre::String("no matching closing bracket '}' for open bracket '{' at line ") +
                Ogre::StringConverter::toString(firstOpenBrace),
                "ScriptLexer::tokenize");
        }
        else if (braceLayer > 1)
        {
            OGRE_EXCEPT(Exception::ERR_INVALID_STATE,
                Ogre::String("too many open brackets '{' without matching closing bracket '}' (") +
                Ogre::StringConverter::toString(braceLayer) +
                Ogre::String(")"),
                "ScriptLexer::tokenize");
        }

        return tokens;
    }

    void ScriptLexer::setToken(const Ogre::String &lexeme, Ogre::uint32 line, const String &source, Ogre::ScriptTokenList *tokens)
    {
        const char openBracket = '{', closeBracket = '}', colon = ':',
            quote = '\"', var = '$';

        ScriptTokenPtr token(OGRE_NEW_T(ScriptToken, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
        token->lexeme = lexeme;
        token->line = line;
        token->file = source;
        bool ignore = false;

        // Check the user token map first
        if(lexeme.size() == 1 && isNewline(lexeme[0]))
        {
            token->type = TID_NEWLINE;
            if(!tokens->empty() && tokens->back()->type == TID_NEWLINE)
                ignore = true;
        }
        else if(lexeme.size() == 1 && lexeme[0] == openBracket)
            token->type = TID_LBRACKET;
        else if(lexeme.size() == 1 && lexeme[0] == closeBracket)
            token->type = TID_RBRACKET;
        else if(lexeme.size() == 1 && lexeme[0] == colon)
            token->type = TID_COLON;
        else if(lexeme[0] == var)
            token->type = TID_VARIABLE;
        else
        {
            // This is either a non-zero length phrase or quoted phrase
            if(lexeme.size() >= 2 && lexeme[0] == quote && lexeme[lexeme.size() - 1] == quote)
            {
                token->type = TID_QUOTE;
            }
            else
            {
                token->type = TID_WORD;
            }
        }

        if(!ignore)
            tokens->push_back(token);
    }

    bool ScriptLexer::isWhitespace(Ogre::String::value_type c)
    {
        return c == ' ' || c == '\r' || c == '\t';
    }

    bool ScriptLexer::isNewline(Ogre::String::value_type c)
    {
        return c == '\n' || c == '\r';
    }

}

<|endoftext|>


<commit_before><commit_msg>Replace endl with \n to get rid of many unnecessary flushes<commit_after><|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993-2011 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* bzflag special common - 1st one */
#include "common.h"

#include <iostream>
#include <string>

#include "WorldEventManager.h"

//-------------------WorldEventManager--------------------
WorldEventManager::WorldEventManager()
{
}

WorldEventManager::~WorldEventManager()
{
  tvEventList::iterator eventItr = eventList.begin();
  while (eventItr != eventList.end())
	delete (*eventItr++);

  eventList.clear();
}

void WorldEventManager::addEvent ( bz_eEventType eventType, bz_EventHandler* theEvent )
{
  if (!theEvent)
    return;

  theEvent->AddEvent(eventType);
  if (std::find(eventList.begin(),eventList.end(),theEvent) == eventList.end())
	  eventList.push_back(theEvent);
}

void WorldEventManager::removeEvent ( bz_eEventType eventType, bz_EventHandler* theEvent )
{
  if (!theEvent)
    return;

  theEvent->RemoveEvent(eventType);
}

bool WorldEventManager::removeHandler(bz_EventHandler* theEvent)
{
  tvEventList::iterator itr = std::find(eventList.begin(),eventList.end(),theEvent);
  if (itr != eventList.end())
	  eventList.erase(itr);

  return itr != eventList.end();
}

void WorldEventManager::callEvents ( bz_eEventType eventType, bz_EventData  *eventData )
{
  if (!eventData)
    return;

  eventData->eventType = eventType;

  tvEventList::iterator itr = eventList.begin();
  while (itr != eventList.end())
  {
	  if ((*itr)->HasEvent(eventType))
		  (*itr)->process(eventData);
	  itr++;
  }
}

void WorldEventManager::callEvents (  bz_EventData  *eventData )
{
  callEvents(eventData->eventType,eventData);
}

std::map<bz_Plugin*,bz_EventHandler*> HandlerMap;

bool RegisterEvent ( bz_eEventType eventType, bz_Plugin* plugin )
{
  if (!plugin)
    return false;

  bz_EventHandler *handler = NULL;

  if (HandlerMap.find(plugin) == HandlerMap.end())
  {
	  handler = new bz_EventHandler();
      handler->plugin = plugin;
	  HandlerMap[plugin] = handler;
  }
  else
	  handler = HandlerMap[plugin];

  worldEventManager.addEvent(eventType,handler);
  return true;
}

bool RemoveEvent ( bz_eEventType eventType, bz_Plugin* plugin )
{
  if (!plugin || HandlerMap.find(plugin) == HandlerMap.end())
    return false;

	bz_EventHandler *handler = HandlerMap[plugin];
	worldEventManager.removeEvent(eventType,handler);

	if (handler->HandledEvents.empty())
		worldEventManager.removeHandler(handler);

  return true;
}

bool FlushEvents(bz_Plugin* plugin)
{
	if (!plugin || HandlerMap.find(plugin) == HandlerMap.end())
		return false;

	bz_EventHandler *handler = HandlerMap[plugin];
	worldEventManager.removeHandler(handler);

	return true;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>clear the handler map too.<commit_after>/* bzflag
 * Copyright (c) 1993-2011 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* bzflag special common - 1st one */
#include "common.h"

#include <iostream>
#include <string>

#include "WorldEventManager.h"

std::map<bz_Plugin*,bz_EventHandler*> HandlerMap;

//-------------------WorldEventManager--------------------
WorldEventManager::WorldEventManager()
{
}

WorldEventManager::~WorldEventManager()
{
  tvEventList::iterator eventItr = eventList.begin();
  while (eventItr != eventList.end())
	delete (*eventItr++);

  eventList.clear();
  HandlerMap.clear();
}

void WorldEventManager::addEvent ( bz_eEventType eventType, bz_EventHandler* theEvent )
{
  if (!theEvent)
    return;

  theEvent->AddEvent(eventType);
  if (std::find(eventList.begin(),eventList.end(),theEvent) == eventList.end())
	  eventList.push_back(theEvent);
}

void WorldEventManager::removeEvent ( bz_eEventType eventType, bz_EventHandler* theEvent )
{
  if (!theEvent)
    return;

  theEvent->RemoveEvent(eventType);
}

bool WorldEventManager::removeHandler(bz_EventHandler* theEvent)
{
  tvEventList::iterator itr = std::find(eventList.begin(),eventList.end(),theEvent);
  if (itr != eventList.end())
	  eventList.erase(itr);

  return itr != eventList.end();
}

void WorldEventManager::callEvents ( bz_eEventType eventType, bz_EventData  *eventData )
{
  if (!eventData)
    return;

  eventData->eventType = eventType;

  tvEventList::iterator itr = eventList.begin();
  while (itr != eventList.end())
  {
	  if ((*itr)->HasEvent(eventType))
		  (*itr)->process(eventData);
	  itr++;
  }
}

void WorldEventManager::callEvents (  bz_EventData  *eventData )
{
  callEvents(eventData->eventType,eventData);
}

bool RegisterEvent ( bz_eEventType eventType, bz_Plugin* plugin )
{
  if (!plugin)
    return false;

  bz_EventHandler *handler = NULL;

  if (HandlerMap.find(plugin) == HandlerMap.end())
  {
	  handler = new bz_EventHandler();
      handler->plugin = plugin;
	  HandlerMap[plugin] = handler;
  }
  else
	  handler = HandlerMap[plugin];

  worldEventManager.addEvent(eventType,handler);
  return true;
}

bool RemoveEvent ( bz_eEventType eventType, bz_Plugin* plugin )
{
  if (!plugin || HandlerMap.find(plugin) == HandlerMap.end())
    return false;

	bz_EventHandler *handler = HandlerMap[plugin];
	worldEventManager.removeEvent(eventType,handler);

	if (handler->HandledEvents.empty())
		worldEventManager.removeHandler(handler);

  return true;
}

bool FlushEvents(bz_Plugin* plugin)
{
	if (!plugin || HandlerMap.find(plugin) == HandlerMap.end())
		return false;

	bz_EventHandler *handler = HandlerMap[plugin];
	worldEventManager.removeHandler(handler);

	return true;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#include "BluPrivatePCH.h"

UBluWidget::UBluWidget(const class FObjectInitializer& PCIP)
	: Super(PCIP)
{

	Width = 800;
	Height = 600;

	bIsTransparent = false;

}

void UBluWidget::init()
{

	browserSettings.universal_access_from_file_urls = STATE_ENABLED;
	browserSettings.file_access_from_file_urls = STATE_ENABLED;

	info.width = Width;
	info.height = Height;

	// Set transparant option
	info.SetAsWindowless(NULL, bIsTransparent);

	renderer = new RenderHandler(Width, Height, this);
	g_handler = new BrowserClient(renderer);
	browser = CefBrowserHost::CreateBrowserSync(info, g_handler.get(), "about:blank", browserSettings, NULL);

	// Setup JS event emitter
	g_handler->SetEventEmitter(&ScriptEventEmitter);

	UE_LOG(LogBlu, Log, TEXT("Component Initialized"));
	CefString str = *DefaultURL;
	UE_LOG(LogBlu, Log, TEXT("Loading URL: %s"), *DefaultURL);

	// Load the URL
	browser->GetMainFrame()->LoadURL(*DefaultURL);
	ResetTexture();

}

void UBluWidget::ResetTexture()
{

	// Here we init the texture to its initial state
	DestroyTexture();

	// init the new Texture2D
	Texture = UTexture2D::CreateTransient(Width, Height);
	Texture->AddToRoot();
	Texture->UpdateResource();

}

void UBluWidget::DestroyTexture()
{
	// Here we destory the texture and its resource
	if (Texture)
	{
		Texture->RemoveFromRoot();

		if (Texture->Resource)
		{
			BeginReleaseResource(Texture->Resource);
			FlushRenderingCommands();
		}

		Texture->MarkPendingKill();
		Texture = nullptr;
	}
}

void UBluWidget::TextureUpdate(const void *buffer)
{
	if (!browser || !bEnabled)
	{
		UE_LOG(LogBlu, Warning, TEXT("NO BROWSER ACCESS OR NOT ENABLED"))
			// UE_LOG(LogBlu, Warning, TEXT("No browesr, or component is not enabled"));
			return;
	}

	if (Texture && Texture->Resource)
	{

		// Is our texture ready?
		auto ref = static_cast<FTexture2DResource*>(Texture->Resource)->GetTexture2DRHI();
		if (!ref)
		{
			UE_LOG(LogBlu, Warning, TEXT("NO REF"))
				return;
		}

		if (buffer == nullptr)
		{
			UE_LOG(LogBlu, Warning, TEXT("NO TEXTDATA"))
				return;
		}

		const size_t size = Width * Height * sizeof(uint32);

		// @TODO This is a bit heavy to keep reallocating/deallocating, but not a big deal. Maybe we can ping pong between buffers instead.
		TArray<uint32> ViewBuffer;
		ViewBuffer.Init(Width * Height);
		FMemory::Memcpy(ViewBuffer.GetData(), buffer, size);

		TextureDataPtr dataPtr = MakeShareable(new TextureData);

		dataPtr->SetRawData(Width, Height, sizeof(uint32), ViewBuffer);

		// Clean up from the per-render
		ViewBuffer.Empty();
		buffer = 0;

		ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER(
			TextureData,
			TextureDataPtr, ImageData, dataPtr,
			FTexture2DRHIRef, TargetTexture, ref,
			const size_t, DataSize, size,
			{
			uint32 stride = 0;
			void* MipData = GDynamicRHI->RHILockTexture2D(TargetTexture, 0, RLM_WriteOnly, stride, false);

			if (MipData)
			{
				FMemory::Memcpy(MipData, ImageData->GetRawBytesPtr(), ImageData->GetDataSize());
				GDynamicRHI->RHIUnlockTexture2D(TargetTexture, 0, false);
			}

			ImageData.Reset();
		});

	}
	else {
		UE_LOG(LogBlu, Warning, TEXT("no Texture or Texture->resource"))
	}

}

void UBluWidget::ExecuteJS(FString code)
{
	CefString codeStr = *code;
	UE_LOG(LogBlu, Log, TEXT("Execute JS: %s"), *code)
	browser->GetMainFrame()->ExecuteJavaScript(codeStr, "", 0);
	// create an event function that can be called from JS
}

void UBluWidget::TriggerMouseMove(FVector2D pos)
{

	mouse_event.x = pos.X;
	mouse_event.y = pos.Y;

	UE_LOG(LogBlu, Warning, TEXT("Mouse Update pos: %s"), *pos.ToString())

	browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseMoveEvent(mouse_event, false);
}

void UBluWidget::TriggerLeftClickDown(FVector2D pos)
{

	mouse_event.x = pos.X;
	mouse_event.y = pos.Y;

	browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, false, 1);

	UE_LOG(LogBlu, Warning, TEXT("Left Click %s"), *pos.ToString())
}

void UBluWidget::TriggerRightClickDown(FVector2D pos)
{

	mouse_event.x = pos.X;
	mouse_event.y = pos.Y;

	browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, false, 1);

	UE_LOG(LogBlu, Warning, TEXT("Right click %s"), *pos.ToString())
}

void UBluWidget::KeyDown(FGeometry Geometry, FKeyEvent InKeyEvent)
{

	CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("key_event");
	msg->GetArgumentList()->SetInt(0, InKeyEvent.GetKeyCode());
	msg->GetArgumentList()->SetInt(1, InKeyEvent.GetCharacter());

	// Check key mod flags!
	// We'll check alt first
	if (InKeyEvent.IsAltDown())
	{
		msg->GetArgumentList()->SetBool(0, true);
	} else {
		msg->GetArgumentList()->SetBool(0, false);
	}

	// Then control takes priority
	if (InKeyEvent.IsControlDown())
	{
		msg->GetArgumentList()->SetBool(1, true);
	} else {
		msg->GetArgumentList()->SetBool(1, false);
	}

	// Shift should be checked last, more important!
	if (InKeyEvent.IsShiftDown())
	{
		msg->GetArgumentList()->SetBool(2, true);
	} else {
		msg->GetArgumentList()->SetBool(2, false);
	}

	browser->SendProcessMessage(PID_RENDERER, msg);

	UE_LOG(LogBlu, Warning, TEXT("SEND KEY EVENT"))
}

UTexture2D* UBluWidget::GetTexture() const
{
	check(Texture)
	return Texture;
}<commit_msg>Working mouse click events<commit_after>#include "BluPrivatePCH.h"

UBluWidget::UBluWidget(const class FObjectInitializer& PCIP)
	: Super(PCIP)
{

	Width = 800;
	Height = 600;

	bIsTransparent = false;

}

void UBluWidget::init()
{

	browserSettings.universal_access_from_file_urls = STATE_ENABLED;
	browserSettings.file_access_from_file_urls = STATE_ENABLED;

	info.width = Width;
	info.height = Height;

	// Set transparant option
	info.SetAsWindowless(NULL, bIsTransparent);

	renderer = new RenderHandler(Width, Height, this);
	g_handler = new BrowserClient(renderer);
	browser = CefBrowserHost::CreateBrowserSync(info, g_handler.get(), "about:blank", browserSettings, NULL);

	// Setup JS event emitter
	g_handler->SetEventEmitter(&ScriptEventEmitter);

	UE_LOG(LogBlu, Log, TEXT("Component Initialized"));
	CefString str = *DefaultURL;
	UE_LOG(LogBlu, Log, TEXT("Loading URL: %s"), *DefaultURL);

	// Load the URL
	browser->GetMainFrame()->LoadURL(*DefaultURL);
	ResetTexture();

}

void UBluWidget::ResetTexture()
{

	// Here we init the texture to its initial state
	DestroyTexture();

	// init the new Texture2D
	Texture = UTexture2D::CreateTransient(Width, Height);
	Texture->AddToRoot();
	Texture->UpdateResource();

}

void UBluWidget::DestroyTexture()
{
	// Here we destory the texture and its resource
	if (Texture)
	{
		Texture->RemoveFromRoot();

		if (Texture->Resource)
		{
			BeginReleaseResource(Texture->Resource);
			FlushRenderingCommands();
		}

		Texture->MarkPendingKill();
		Texture = nullptr;
	}
}

void UBluWidget::TextureUpdate(const void *buffer)
{
	if (!browser || !bEnabled)
	{
		UE_LOG(LogBlu, Warning, TEXT("NO BROWSER ACCESS OR NOT ENABLED"))
			// UE_LOG(LogBlu, Warning, TEXT("No browesr, or component is not enabled"));
			return;
	}

	if (Texture && Texture->Resource)
	{

		// Is our texture ready?
		auto ref = static_cast<FTexture2DResource*>(Texture->Resource)->GetTexture2DRHI();
		if (!ref)
		{
			UE_LOG(LogBlu, Warning, TEXT("NO REF"))
				return;
		}

		if (buffer == nullptr)
		{
			UE_LOG(LogBlu, Warning, TEXT("NO TEXTDATA"))
				return;
		}

		const size_t size = Width * Height * sizeof(uint32);

		// @TODO This is a bit heavy to keep reallocating/deallocating, but not a big deal. Maybe we can ping pong between buffers instead.
		TArray<uint32> ViewBuffer;
		ViewBuffer.Init(Width * Height);
		FMemory::Memcpy(ViewBuffer.GetData(), buffer, size);

		TextureDataPtr dataPtr = MakeShareable(new TextureData);

		dataPtr->SetRawData(Width, Height, sizeof(uint32), ViewBuffer);

		// Clean up from the per-render
		ViewBuffer.Empty();
		buffer = 0;

		ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER(
			TextureData,
			TextureDataPtr, ImageData, dataPtr,
			FTexture2DRHIRef, TargetTexture, ref,
			const size_t, DataSize, size,
			{
			uint32 stride = 0;
			void* MipData = GDynamicRHI->RHILockTexture2D(TargetTexture, 0, RLM_WriteOnly, stride, false);

			if (MipData)
			{
				FMemory::Memcpy(MipData, ImageData->GetRawBytesPtr(), ImageData->GetDataSize());
				GDynamicRHI->RHIUnlockTexture2D(TargetTexture, 0, false);
			}

			ImageData.Reset();
		});

	}
	else {
		UE_LOG(LogBlu, Warning, TEXT("no Texture or Texture->resource"))
	}

}

void UBluWidget::ExecuteJS(FString code)
{
	CefString codeStr = *code;
	UE_LOG(LogBlu, Log, TEXT("Execute JS: %s"), *code)
	browser->GetMainFrame()->ExecuteJavaScript(codeStr, "", 0);
	// create an event function that can be called from JS
}

void UBluWidget::TriggerMouseMove(FVector2D pos)
{

	mouse_event.x = pos.X;
	mouse_event.y = pos.Y;

	UE_LOG(LogBlu, Warning, TEXT("Mouse Update pos: %s"), *pos.ToString())

	browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseMoveEvent(mouse_event, false);
}

void UBluWidget::TriggerLeftClickDown(FVector2D pos)
{

	mouse_event.x = pos.X;
	mouse_event.y = pos.Y;

	//browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, false, 1);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, true, 1);

	UE_LOG(LogBlu, Warning, TEXT("Left Click %s"), *pos.ToString())
}

void UBluWidget::TriggerRightClickDown(FVector2D pos)
{

	mouse_event.x = pos.X;
	mouse_event.y = pos.Y;

	//browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, false, 1);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, true, 1);

	UE_LOG(LogBlu, Warning, TEXT("Right click %s"), *pos.ToString())
}

void UBluWidget::KeyDown(FGeometry Geometry, FKeyEvent InKeyEvent)
{

	CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("key_event");
	msg->GetArgumentList()->SetInt(0, InKeyEvent.GetKeyCode());
	msg->GetArgumentList()->SetInt(1, InKeyEvent.GetCharacter());

	// Check key mod flags!
	// We'll check alt first
	if (InKeyEvent.IsAltDown())
	{
		msg->GetArgumentList()->SetBool(0, true);
	} else {
		msg->GetArgumentList()->SetBool(0, false);
	}

	// Then control takes priority
	if (InKeyEvent.IsControlDown())
	{
		msg->GetArgumentList()->SetBool(1, true);
	} else {
		msg->GetArgumentList()->SetBool(1, false);
	}

	// Shift should be checked last, more important!
	if (InKeyEvent.IsShiftDown())
	{
		msg->GetArgumentList()->SetBool(2, true);
	} else {
		msg->GetArgumentList()->SetBool(2, false);
	}

	browser->SendProcessMessage(PID_RENDERER, msg);

	UE_LOG(LogBlu, Warning, TEXT("SEND KEY EVENT"))
}

UTexture2D* UBluWidget::GetTexture() const
{
	check(Texture)
	return Texture;
}<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////
// File:        tessdatamanager.cpp
// Description: Functions to handle loading/combining tesseract data files.
// Author:      Daria Antonova
// Created:     Wed Jun 03 11:26:43 PST 2009
//
// (C) Copyright 2009, Google Inc.
// 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.
//
///////////////////////////////////////////////////////////////////////

#ifdef HAVE_CONFIG_H
#include "config_auto.h"
#endif

#include "tessdatamanager.h"

#include <cstdio>

#include "errcode.h"
#include "helpers.h"
#include "serialis.h"
#include "strngs.h"
#include "tprintf.h"
#include "params.h"

namespace tesseract {

TessdataManager::TessdataManager() : reader_(nullptr), is_loaded_(false), swap_(false) {
  SetVersionString(PACKAGE_VERSION);
}

TessdataManager::TessdataManager(FileReader reader)
  : reader_(reader),
    is_loaded_(false),
    swap_(false) {
  SetVersionString(PACKAGE_VERSION);
}

// Lazily loads from the the given filename. Won't actually read the file
// until it needs it.
void TessdataManager::LoadFileLater(const char *data_file_name) {
  Clear();
  data_file_name_ = data_file_name;
}

bool TessdataManager::Init(const char *data_file_name) {
  GenericVector<char> data;
  if (reader_ == nullptr) {
    if (!LoadDataFromFile(data_file_name, &data)) return false;
  } else {
    if (!(*reader_)(data_file_name, &data)) return false;
  }
  return LoadMemBuffer(data_file_name, &data[0], data.size());
}

// Loads from the given memory buffer as if a file.
bool TessdataManager::LoadMemBuffer(const char *name, const char *data,
                                    int size) {
  Clear();
  data_file_name_ = name;
  TFile fp;
  fp.Open(data, size);
  int32_t num_entries = TESSDATA_NUM_ENTRIES;
  if (fp.FRead(&num_entries, sizeof(num_entries), 1) != 1) return false;
  swap_ = num_entries > kMaxNumTessdataEntries || num_entries < 0;
  fp.set_swap(swap_);
  if (swap_) ReverseN(&num_entries, sizeof(num_entries));
  if (num_entries > kMaxNumTessdataEntries || num_entries < 0) return false;
  GenericVector<int64_t> offset_table;
  offset_table.resize_no_init(num_entries);
  if (fp.FReadEndian(&offset_table[0], sizeof(offset_table[0]), num_entries) !=
      num_entries)
    return false;
  for (int i = 0; i < num_entries && i < TESSDATA_NUM_ENTRIES; ++i) {
    if (offset_table[i] >= 0) {
      int64_t entry_size = size - offset_table[i];
      int j = i + 1;
      while (j < num_entries && offset_table[j] == -1) ++j;
      if (j < num_entries) entry_size = offset_table[j] - offset_table[i];
      entries_[i].resize_no_init(entry_size);
      if (fp.FRead(&entries_[i][0], 1, entry_size) != entry_size) return false;
    }
  }
  if (entries_[TESSDATA_VERSION].empty()) {
    SetVersionString("Pre-4.0.0");
  }
  is_loaded_ = true;
  return true;
}

// Overwrites a single entry of the given type.
void TessdataManager::OverwriteEntry(TessdataType type, const char *data,
                                     int size) {
  is_loaded_ = true;
  entries_[type].resize_no_init(size);
  memcpy(&entries_[type][0], data, size);
}

// Saves to the given filename.
bool TessdataManager::SaveFile(const STRING &filename,
                               FileWriter writer) const {
  ASSERT_HOST(is_loaded_);
  GenericVector<char> data;
  Serialize(&data);
  if (writer == nullptr)
    return SaveDataToFile(data, filename);
  else
    return (*writer)(data, filename);
}

// Serializes to the given vector.
void TessdataManager::Serialize(GenericVector<char> *data) const {
  ASSERT_HOST(is_loaded_);
  // Compute the offset_table and total size.
  int64_t offset_table[TESSDATA_NUM_ENTRIES];
  int64_t offset = sizeof(int32_t) + sizeof(offset_table);
  for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
    if (entries_[i].empty()) {
      offset_table[i] = -1;
    } else {
      offset_table[i] = offset;
      offset += entries_[i].size();
    }
  }
  data->init_to_size(offset, 0);
  int32_t num_entries = TESSDATA_NUM_ENTRIES;
  TFile fp;
  fp.OpenWrite(data);
  fp.FWrite(&num_entries, sizeof(num_entries), 1);
  fp.FWrite(offset_table, sizeof(offset_table), 1);
  for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
    if (!entries_[i].empty()) {
      fp.FWrite(&entries_[i][0], entries_[i].size(), 1);
    }
  }
}

// Resets to the initial state, keeping the reader.
void TessdataManager::Clear() {
  for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
    entries_[i].clear();
  }
  is_loaded_ = false;
}

// Prints a directory of contents.
void TessdataManager::Directory() const {
  tprintf("Version string:%s\n", VersionString().c_str());
  int offset = TESSDATA_NUM_ENTRIES * sizeof(int64_t);
  for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
    if (!entries_[i].empty()) {
      tprintf("%d:%s:size=%d, offset=%d\n", i, kTessdataFileSuffixes[i],
              entries_[i].size(), offset);
      offset += entries_[i].size();
    }
  }
}

// Opens the given TFile pointer to the given component type.
// Returns false in case of failure.
bool TessdataManager::GetComponent(TessdataType type, TFile *fp) {
  if (!is_loaded_ && !Init(data_file_name_.string())) return false;
  const TessdataManager *const_this = this;
  return const_this->GetComponent(type, fp);
}

// As non-const version except it can't load the component if not already
// loaded.
bool TessdataManager::GetComponent(TessdataType type, TFile *fp) const {
  ASSERT_HOST(is_loaded_);
  if (entries_[type].empty()) return false;
  fp->Open(&entries_[type][0], entries_[type].size());
  fp->set_swap(swap_);
  return true;
}

// Returns the current version string.
std::string TessdataManager::VersionString() const {
  return std::string(&entries_[TESSDATA_VERSION][0],
                     entries_[TESSDATA_VERSION].size());
}

// Sets the version string to the given v_str.
void TessdataManager::SetVersionString(const std::string &v_str) {
  entries_[TESSDATA_VERSION].resize_no_init(v_str.size());
  memcpy(&entries_[TESSDATA_VERSION][0], v_str.data(), v_str.size());
}

bool TessdataManager::CombineDataFiles(
    const char *language_data_path_prefix,
    const char *output_filename) {
  // Load individual tessdata components from files.
  for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
    TessdataType type;
    ASSERT_HOST(TessdataTypeFromFileSuffix(kTessdataFileSuffixes[i], &type));
    STRING filename = language_data_path_prefix;
    filename += kTessdataFileSuffixes[i];
    FILE *fp = fopen(filename.string(), "rb");
    if (fp != nullptr) {
      fclose(fp);
      if (!LoadDataFromFile(filename, &entries_[type])) {
        tprintf("Load of file %s failed!\n", filename.string());
        return false;
      }
    }
  }
  is_loaded_ = true;

  // Make sure that the required components are present.
  if (!IsBaseAvailable() && !IsLSTMAvailable()) {
    tprintf(
        "Error: traineddata file must contain at least (a unicharset file"
        "and inttemp) OR an lstm file.\n");
    return false;
  }
  // Write updated data to the output traineddata file.
  return SaveFile(output_filename, nullptr);
}

bool TessdataManager::OverwriteComponents(
    const char *new_traineddata_filename,
    char **component_filenames,
    int num_new_components) {
  // Open the files with the new components.
  for (int i = 0; i < num_new_components; ++i) {
    TessdataType type;
    if (TessdataTypeFromFileName(component_filenames[i], &type)) {
      if (!LoadDataFromFile(component_filenames[i], &entries_[type])) {
        tprintf("Failed to read component file:%s\n", component_filenames[i]);
        return false;
      }
    }
  }

  // Write updated data to the output traineddata file.
  return SaveFile(new_traineddata_filename, nullptr);
}

bool TessdataManager::ExtractToFile(const char *filename) {
  TessdataType type = TESSDATA_NUM_ENTRIES;
  ASSERT_HOST(
      tesseract::TessdataManager::TessdataTypeFromFileName(filename, &type));
  if (entries_[type].empty()) return false;
  return SaveDataToFile(entries_[type], filename);
}

bool TessdataManager::TessdataTypeFromFileSuffix(const char *suffix,
                                                 TessdataType *type) {
  for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
    if (strcmp(kTessdataFileSuffixes[i], suffix) == 0) {
      *type = static_cast<TessdataType>(i);
      return true;
    }
  }
  tprintf("TessdataManager can't determine which tessdata"
         " component is represented by %s\n", suffix);
  return false;
}

bool TessdataManager::TessdataTypeFromFileName(const char *filename,
                                               TessdataType *type) {
  // Get the file suffix (extension)
  const char *suffix = strrchr(filename, '.');
  if (suffix == nullptr || *(++suffix) == '\0') return false;
  return TessdataTypeFromFileSuffix(suffix, type);
}

}  // namespace tesseract
<commit_msg>TessdataManager: Use new serialization API<commit_after>///////////////////////////////////////////////////////////////////////
// File:        tessdatamanager.cpp
// Description: Functions to handle loading/combining tesseract data files.
// Author:      Daria Antonova
// Created:     Wed Jun 03 11:26:43 PST 2009
//
// (C) Copyright 2009, Google Inc.
// 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.
//
///////////////////////////////////////////////////////////////////////

#ifdef HAVE_CONFIG_H
#include "config_auto.h"
#endif

#include "tessdatamanager.h"

#include <cstdio>

#include "errcode.h"
#include "helpers.h"
#include "serialis.h"
#include "strngs.h"
#include "tprintf.h"
#include "params.h"

namespace tesseract {

TessdataManager::TessdataManager() : reader_(nullptr), is_loaded_(false), swap_(false) {
  SetVersionString(PACKAGE_VERSION);
}

TessdataManager::TessdataManager(FileReader reader)
  : reader_(reader),
    is_loaded_(false),
    swap_(false) {
  SetVersionString(PACKAGE_VERSION);
}

// Lazily loads from the the given filename. Won't actually read the file
// until it needs it.
void TessdataManager::LoadFileLater(const char *data_file_name) {
  Clear();
  data_file_name_ = data_file_name;
}

bool TessdataManager::Init(const char *data_file_name) {
  GenericVector<char> data;
  if (reader_ == nullptr) {
    if (!LoadDataFromFile(data_file_name, &data)) return false;
  } else {
    if (!(*reader_)(data_file_name, &data)) return false;
  }
  return LoadMemBuffer(data_file_name, &data[0], data.size());
}

// Loads from the given memory buffer as if a file.
bool TessdataManager::LoadMemBuffer(const char *name, const char *data,
                                    int size) {
  Clear();
  data_file_name_ = name;
  TFile fp;
  fp.Open(data, size);
  uint32_t num_entries;
  if (!fp.DeSerialize(&num_entries)) return false;
  swap_ = num_entries > kMaxNumTessdataEntries;
  fp.set_swap(swap_);
  if (swap_) ReverseN(&num_entries, sizeof(num_entries));
  if (num_entries > kMaxNumTessdataEntries) return false;
  GenericVector<int64_t> offset_table;
  offset_table.resize_no_init(num_entries);
  if (!fp.DeSerialize(&offset_table[0], num_entries)) return false;
  for (int i = 0; i < num_entries && i < TESSDATA_NUM_ENTRIES; ++i) {
    if (offset_table[i] >= 0) {
      int64_t entry_size = size - offset_table[i];
      int j = i + 1;
      while (j < num_entries && offset_table[j] == -1) ++j;
      if (j < num_entries) entry_size = offset_table[j] - offset_table[i];
      entries_[i].resize_no_init(entry_size);
      if (!fp.DeSerialize(&entries_[i][0], entry_size)) return false;
    }
  }
  if (entries_[TESSDATA_VERSION].empty()) {
    SetVersionString("Pre-4.0.0");
  }
  is_loaded_ = true;
  return true;
}

// Overwrites a single entry of the given type.
void TessdataManager::OverwriteEntry(TessdataType type, const char *data,
                                     int size) {
  is_loaded_ = true;
  entries_[type].resize_no_init(size);
  memcpy(&entries_[type][0], data, size);
}

// Saves to the given filename.
bool TessdataManager::SaveFile(const STRING &filename,
                               FileWriter writer) const {
  ASSERT_HOST(is_loaded_);
  GenericVector<char> data;
  Serialize(&data);
  if (writer == nullptr)
    return SaveDataToFile(data, filename);
  else
    return (*writer)(data, filename);
}

// Serializes to the given vector.
void TessdataManager::Serialize(GenericVector<char> *data) const {
  ASSERT_HOST(is_loaded_);
  // Compute the offset_table and total size.
  int64_t offset_table[TESSDATA_NUM_ENTRIES];
  int64_t offset = sizeof(int32_t) + sizeof(offset_table);
  for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
    if (entries_[i].empty()) {
      offset_table[i] = -1;
    } else {
      offset_table[i] = offset;
      offset += entries_[i].size();
    }
  }
  data->init_to_size(offset, 0);
  int32_t num_entries = TESSDATA_NUM_ENTRIES;
  TFile fp;
  fp.OpenWrite(data);
  fp.Serialize(&num_entries);
  fp.Serialize(&offset_table[0], countof(offset_table));
  for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
    if (!entries_[i].empty()) {
      fp.Serialize(&entries_[i][0], entries_[i].size());
    }
  }
}

// Resets to the initial state, keeping the reader.
void TessdataManager::Clear() {
  for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
    entries_[i].clear();
  }
  is_loaded_ = false;
}

// Prints a directory of contents.
void TessdataManager::Directory() const {
  tprintf("Version string:%s\n", VersionString().c_str());
  int offset = TESSDATA_NUM_ENTRIES * sizeof(int64_t);
  for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
    if (!entries_[i].empty()) {
      tprintf("%d:%s:size=%d, offset=%d\n", i, kTessdataFileSuffixes[i],
              entries_[i].size(), offset);
      offset += entries_[i].size();
    }
  }
}

// Opens the given TFile pointer to the given component type.
// Returns false in case of failure.
bool TessdataManager::GetComponent(TessdataType type, TFile *fp) {
  if (!is_loaded_ && !Init(data_file_name_.string())) return false;
  const TessdataManager *const_this = this;
  return const_this->GetComponent(type, fp);
}

// As non-const version except it can't load the component if not already
// loaded.
bool TessdataManager::GetComponent(TessdataType type, TFile *fp) const {
  ASSERT_HOST(is_loaded_);
  if (entries_[type].empty()) return false;
  fp->Open(&entries_[type][0], entries_[type].size());
  fp->set_swap(swap_);
  return true;
}

// Returns the current version string.
std::string TessdataManager::VersionString() const {
  return std::string(&entries_[TESSDATA_VERSION][0],
                     entries_[TESSDATA_VERSION].size());
}

// Sets the version string to the given v_str.
void TessdataManager::SetVersionString(const std::string &v_str) {
  entries_[TESSDATA_VERSION].resize_no_init(v_str.size());
  memcpy(&entries_[TESSDATA_VERSION][0], v_str.data(), v_str.size());
}

bool TessdataManager::CombineDataFiles(
    const char *language_data_path_prefix,
    const char *output_filename) {
  // Load individual tessdata components from files.
  for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
    TessdataType type;
    ASSERT_HOST(TessdataTypeFromFileSuffix(kTessdataFileSuffixes[i], &type));
    STRING filename = language_data_path_prefix;
    filename += kTessdataFileSuffixes[i];
    FILE *fp = fopen(filename.string(), "rb");
    if (fp != nullptr) {
      fclose(fp);
      if (!LoadDataFromFile(filename, &entries_[type])) {
        tprintf("Load of file %s failed!\n", filename.string());
        return false;
      }
    }
  }
  is_loaded_ = true;

  // Make sure that the required components are present.
  if (!IsBaseAvailable() && !IsLSTMAvailable()) {
    tprintf(
        "Error: traineddata file must contain at least (a unicharset file"
        "and inttemp) OR an lstm file.\n");
    return false;
  }
  // Write updated data to the output traineddata file.
  return SaveFile(output_filename, nullptr);
}

bool TessdataManager::OverwriteComponents(
    const char *new_traineddata_filename,
    char **component_filenames,
    int num_new_components) {
  // Open the files with the new components.
  for (int i = 0; i < num_new_components; ++i) {
    TessdataType type;
    if (TessdataTypeFromFileName(component_filenames[i], &type)) {
      if (!LoadDataFromFile(component_filenames[i], &entries_[type])) {
        tprintf("Failed to read component file:%s\n", component_filenames[i]);
        return false;
      }
    }
  }

  // Write updated data to the output traineddata file.
  return SaveFile(new_traineddata_filename, nullptr);
}

bool TessdataManager::ExtractToFile(const char *filename) {
  TessdataType type = TESSDATA_NUM_ENTRIES;
  ASSERT_HOST(
      tesseract::TessdataManager::TessdataTypeFromFileName(filename, &type));
  if (entries_[type].empty()) return false;
  return SaveDataToFile(entries_[type], filename);
}

bool TessdataManager::TessdataTypeFromFileSuffix(const char *suffix,
                                                 TessdataType *type) {
  for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
    if (strcmp(kTessdataFileSuffixes[i], suffix) == 0) {
      *type = static_cast<TessdataType>(i);
      return true;
    }
  }
  tprintf("TessdataManager can't determine which tessdata"
         " component is represented by %s\n", suffix);
  return false;
}

bool TessdataManager::TessdataTypeFromFileName(const char *filename,
                                               TessdataType *type) {
  // Get the file suffix (extension)
  const char *suffix = strrchr(filename, '.');
  if (suffix == nullptr || *(++suffix) == '\0') return false;
  return TessdataTypeFromFileSuffix(suffix, type);
}

}  // namespace tesseract
<|endoftext|>


<commit_before>/*
 Copyright (c) 2010, The Barbarian Group
 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.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
*/

#include "cinder/audio/PcmBuffer.h"

namespace cinder { namespace audio {

template<typename T>
void deleteBuffer( BufferT<T> * aBuffer )
{
	delete [] aBuffer;
	delete aBuffer;
}

#define DELETE_BUFFER_PROTOTYPES(r,data,T)\
	template void deleteBuffer( BufferT<T> * aBuffer );

BOOST_PP_SEQ_FOR_EACH( DELETE_BUFFER_PROTOTYPES, ~, AUDIO_DATA_TYPES )

template<typename T>
PcmBufferT<T>::PcmBufferT( uint32_t aMaxSampleCount, uint16_t aChannelCount, bool isInterleaved )
	: mMaxSampleCount( aMaxSampleCount ), mChannelCount( aChannelCount ), mIsInterleaved( isInterleaved )
{
	uint64_t bufferSize = 0;
	uint16_t channelsPerBuffer = 0;
	if( ! mIsInterleaved ) {
		mBufferCount = mChannelCount;
		bufferSize = mMaxSampleCount;
		channelsPerBuffer = 1;
	} else {
		mBufferCount = 1;
		bufferSize = mMaxSampleCount * mChannelCount;
		channelsPerBuffer = mChannelCount;
	}

	mBufferSampleCounts = new uint32_t[mBufferCount];
	void (*fn)( BufferT<T> * ) = deleteBuffer;
	for( int i = 0; i < mBufferCount; i++ ) {
		shared_ptr<BufferT<T> > buffer( new BufferT<T>, fn );
		mBuffers.push_back( buffer );
		buffer->mNumberChannels = channelsPerBuffer;
		buffer->mDataByteSize = bufferSize * sizeof(T);
		buffer->mData = new T[bufferSize];
		mBufferSampleCounts[i] = 0;
	}
}

template<typename T>
PcmBufferT<T>::~PcmBufferT()
{
	delete [] mBufferSampleCounts;
}

template<typename T>
shared_ptr<BufferT<T> > PcmBufferT<T>::getChannelData( ChannelIdentifier channelId ) const {
	if( channelId > mChannelCount - 1 ) {
		throw InvalidChannelPcmBufferException();
	}

	if( mIsInterleaved ) {
		void (*fn)( BufferT<T> * ) = deleteBuffer;
		shared_ptr<BufferT<T> > buffer( new BufferT<T> );
		buffer->mData = new T[mMaxSampleCount];
		for( uint32_t i = 0; i < mMaxSampleCount; i++ ) {
			buffer->mData[i] = mBuffers[0]->mData[i * mChannelCount + channelId];
		}
		buffer->mNumberChannels = 1;
		buffer->mDataByteSize = mMaxSampleCount * sizeof( T );
		return buffer;
	}

	return mBuffers[channelId];
}

template<typename T>
shared_ptr<BufferT<T> > PcmBufferT<T>::getInterleavedData() const {
	if( ! mIsInterleaved ) {
		void (*fn)( BufferT<T> * ) = deleteBuffer;
		shared_ptr<BufferT<T> > buffer( new BufferT<T>, fn );
		buffer->mData = new T[mMaxSampleCount * mChannelCount];
		for( uint32_t i = 0; i < mMaxSampleCount; i++ ) {
			for( uint16_t j = 0; j < mChannelCount; j++ ) {
				buffer->mData[i * mChannelCount + j] = mBuffers[j]->mData[i];
			}
		}
		buffer->mNumberChannels = mChannelCount;
		buffer->mDataByteSize = mMaxSampleCount * mChannelCount * sizeof( T );
		return buffer;
	}
	return mBuffers[0];
}

template<typename T>
void PcmBufferT<T>::appendInterleavedData( T * aData, uint32_t aSampleCount )
{
	if( mBufferSampleCounts[0] + aSampleCount > mMaxSampleCount ) {
		throw OutOfRangePcmBufferException();
	}

	if( ! mIsInterleaved ) {
		//iterate data and copy it into separate buffers
		for( uint32_t i = 0; i < aSampleCount; i++ ) {
			for( uint16_t j = 0; j < mChannelCount; j++ ) {
				mBuffers[j]->mData[mBufferSampleCounts[j]] = aData[i + j];
				mBufferSampleCounts[0] += 1;
			}
		}
	} else {
		memcpy( &( mBuffers[0]->mData[mBufferSampleCounts[0] * mChannelCount] ), aData, aSampleCount * mChannelCount * sizeof(T) );
		mBufferSampleCounts[0] += aSampleCount;
	}
}

template<typename T>
void PcmBufferT<T>::appendChannelData( T * aData, uint32_t aSampleCount, ChannelIdentifier channelId )
{
	if( mBufferSampleCounts[channelId] + aSampleCount > mMaxSampleCount ) {
		throw OutOfRangePcmBufferException();
	}

	if( channelId > mChannelCount - 1 ) {
		throw InvalidChannelPcmBufferException();
	}

	if( mIsInterleaved ) {
		//TODO: iterate data and copy into single buffers
	} else {
		memcpy( &( mBuffers[channelId]->mData[mBufferSampleCounts[channelId]] ), aData, aSampleCount * sizeof(T) );
		mBufferSampleCounts[channelId] += aSampleCount;
	}
}

#define PCM_BUFFER_PROTOTYPES(r,data,T)\
	template class PcmBufferT<T>;\

BOOST_PP_SEQ_FOR_EACH( PCM_BUFFER_PROTOTYPES, ~, AUDIO_DATA_TYPES )

}} //namespace<commit_msg>windows pcm buffering with massive memory leaks<commit_after>/*
 Copyright (c) 2010, The Barbarian Group
 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.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
*/

#include "cinder/audio/PcmBuffer.h"

namespace cinder { namespace audio {

template<typename T>
void deleteBuffer( BufferT<T> * aBuffer )
{
	delete [] aBuffer;
	delete aBuffer;
}

#define DELETE_BUFFER_PROTOTYPES(r,data,T)\
	template void deleteBuffer( BufferT<T> * aBuffer );

BOOST_PP_SEQ_FOR_EACH( DELETE_BUFFER_PROTOTYPES, ~, AUDIO_DATA_TYPES )

template<typename T>
PcmBufferT<T>::PcmBufferT( uint32_t aMaxSampleCount, uint16_t aChannelCount, bool isInterleaved )
	: mMaxSampleCount( aMaxSampleCount ), mChannelCount( aChannelCount ), mIsInterleaved( isInterleaved )
{
	uint64_t bufferSize = 0;
	uint16_t channelsPerBuffer = 0;
	if( ! mIsInterleaved ) {
		mBufferCount = mChannelCount;
		bufferSize = mMaxSampleCount;
		channelsPerBuffer = 1;
	} else {
		mBufferCount = 1;
		bufferSize = mMaxSampleCount * mChannelCount;
		channelsPerBuffer = mChannelCount;
	}

	mBufferSampleCounts = new uint32_t[mBufferCount];
	void (*fn)( BufferT<T> * ) = deleteBuffer;
	for( int i = 0; i < mBufferCount; i++ ) {
		shared_ptr<BufferT<T> > buffer( new BufferT<T> );
		mBuffers.push_back( buffer );
		buffer->mNumberChannels = channelsPerBuffer;
		buffer->mDataByteSize = bufferSize * sizeof(T);
		buffer->mData = new T[bufferSize];
		mBufferSampleCounts[i] = 0;
	}
}

template<typename T>
PcmBufferT<T>::~PcmBufferT()
{
	delete [] mBufferSampleCounts;
}

template<typename T>
shared_ptr<BufferT<T> > PcmBufferT<T>::getChannelData( ChannelIdentifier channelId ) const {
	if( channelId > mChannelCount - 1 ) {
		throw InvalidChannelPcmBufferException();
	}

	if( mIsInterleaved ) {
		void (*fn)( BufferT<T> * ) = deleteBuffer;
		shared_ptr<BufferT<T> > buffer( new BufferT<T> );
		buffer->mData = new T[mMaxSampleCount];
		for( uint32_t i = 0; i < mMaxSampleCount; i++ ) {
			buffer->mData[i] = mBuffers[0]->mData[i * mChannelCount + channelId];
		}
		buffer->mNumberChannels = 1;
		buffer->mDataByteSize = mMaxSampleCount * sizeof( T );
		return buffer;
	}

	return mBuffers[channelId];
}

template<typename T>
shared_ptr<BufferT<T> > PcmBufferT<T>::getInterleavedData() const {
	if( ! mIsInterleaved ) {
		void (*fn)( BufferT<T> * ) = deleteBuffer;
		shared_ptr<BufferT<T> > buffer( new BufferT<T>, fn );
		buffer->mData = new T[mMaxSampleCount * mChannelCount];
		for( uint32_t i = 0; i < mMaxSampleCount; i++ ) {
			for( uint16_t j = 0; j < mChannelCount; j++ ) {
				buffer->mData[i * mChannelCount + j] = mBuffers[j]->mData[i];
			}
		}
		buffer->mNumberChannels = mChannelCount;
		buffer->mDataByteSize = mMaxSampleCount * mChannelCount * sizeof( T );
		return buffer;
	}
	return mBuffers[0];
}

template<typename T>
void PcmBufferT<T>::appendInterleavedData( T * aData, uint32_t aSampleCount )
{
	if( mBufferSampleCounts[0] + aSampleCount > mMaxSampleCount ) {
		throw OutOfRangePcmBufferException();
	}

	if( ! mIsInterleaved ) {
		//iterate data and copy it into separate buffers
		for( uint32_t i = 0; i < aSampleCount; i++ ) {
			for( uint16_t j = 0; j < mChannelCount; j++ ) {
				mBuffers[j]->mData[mBufferSampleCounts[j]] = aData[i + j];
				mBufferSampleCounts[0] += 1;
			}
		}
	} else {
		memcpy( &( mBuffers[0]->mData[mBufferSampleCounts[0] * mChannelCount] ), aData, aSampleCount * mChannelCount * sizeof(T) );
		mBufferSampleCounts[0] += aSampleCount;
	}
}

template<typename T>
void PcmBufferT<T>::appendChannelData( T * aData, uint32_t aSampleCount, ChannelIdentifier channelId )
{
	if( mBufferSampleCounts[channelId] + aSampleCount > mMaxSampleCount ) {
		throw OutOfRangePcmBufferException();
	}

	if( channelId > mChannelCount - 1 ) {
		throw InvalidChannelPcmBufferException();
	}

	if( mIsInterleaved ) {
		//TODO: iterate data and copy into single buffers
	} else {
		memcpy( &( mBuffers[channelId]->mData[mBufferSampleCounts[channelId]] ), aData, aSampleCount * sizeof(T) );
		mBufferSampleCounts[channelId] += aSampleCount;
	}
}

#define PCM_BUFFER_PROTOTYPES(r,data,T)\
	template class PcmBufferT<T>;\

BOOST_PP_SEQ_FOR_EACH( PCM_BUFFER_PROTOTYPES, ~, AUDIO_DATA_TYPES )

}} //namespace<|endoftext|>


<commit_before>// Copyright (c) 2016 by Contributors
// implementation of common tensor operators
#include <tinyflow/base.h>
#include <dmlc/parameter.h>
#include <nnvm/op_attr_types.h>
#include <utility>
#include "./op_util.h"

namespace tinyflow {

// shape given the ZeroParam
using namespace nnvm;

// shape parameter for zeros, ones
struct ZeroParam : public dmlc::Parameter<ZeroParam> {
  TShape shape;
  int dtype;
  DMLC_DECLARE_PARAMETER(ZeroParam) {
    DMLC_DECLARE_FIELD(shape).set_default(TShape());
    DMLC_DECLARE_FIELD(dtype).set_default(kFloat32);
  }
};
DMLC_REGISTER_PARAMETER(ZeroParam);

inline bool ZeroShape(const NodeAttrs& attrs,
                      std::vector<TShape> *ishape,
                      std::vector<TShape> *oshape) {
  const TShape& ts = dmlc::get<ZeroParam>(attrs.parsed).shape;
  if (ts.ndim() != 0) {
    SHAPE_ASSIGN(oshape->at(0), ts);
    return true;
  } else {
    return false;
  }
}

inline bool ZeroType(const NodeAttrs& attrs,
                     std::vector<int> *iattr,
                     std::vector<int> *oattr) {
  int dtype = dmlc::get<ZeroParam>(attrs.parsed).dtype;
  DTYPE_ASSIGN(oattr->at(0), dtype);
  return true;
}

NNVM_REGISTER_OP_GROUP(ElementwiseOpAttr)
.set_attr<bool>("IsElementWise", true)
.set_attr<FInferShape>("FInferShape", SameShape);

NNVM_REGISTER_OP(zeros)
.describe("zeros")
.set_num_inputs(0)
.set_attr_parser(ParamParser<ZeroParam>)
.set_attr<FInferShape>("FInferShape", ZeroShape)
.set_attr<FInferType>("FInferType", ZeroType);

NNVM_REGISTER_OP(ones)
.describe("ones")
.set_num_inputs(0)
.set_attr_parser(ParamParser<ZeroParam>)
.set_attr<FInferShape>("FInferShape", ZeroShape)
.set_attr<FInferType>("FInferType", ZeroType);

NNVM_REGISTER_OP(normal)
.describe("normal distribution")
.set_num_inputs(0)
.set_attr_parser(ParamParser<ZeroParam>)
.set_attr<FInferShape>("FInferShape", ZeroShape)
.set_attr<FInferType>("FInferType", ZeroType);

NNVM_REGISTER_OP(equal)
.describe("Equal comparitor")
.set_num_inputs(2)
.set_attr<FInferShape>("FInferShape", SameShape);

NNVM_REGISTER_OP(ones_like)
.describe("ones_like")
.set_num_inputs(1)
.set_attr<FInferShape>("FInferShape", SameShape);

NNVM_REGISTER_OP(__add_symbol__)
.describe("add two data together")
.set_num_inputs(2)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds){
      return std::vector<NodeEntry>{ograds[0], ograds[0]};
});

NNVM_REGISTER_OP(__sub_symbol__)
.describe("do subtract")
.set_num_inputs(2)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds){
      return std::vector<NodeEntry>{
        MakeNode("__mul_scalar__", n->attrs.name + "_grad_0",
                 {ograds[0]}, {{"scalar", "1"}}),
        MakeNode("__mul_scalar__", n->attrs.name + "_grad_1",
                 {ograds[0]}, {{"scalar", "-1"}}),
      };
});

NNVM_REGISTER_OP(mul)
.add_alias("__mul_symbol__")
.describe("add two data together")
.set_num_inputs(2)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds){
      return std::vector<NodeEntry>{
        MakeNode("mul", n->attrs.name + "_grad_0",
                 {ograds[0], n->inputs[1]}),
        MakeNode("mul", n->attrs.name + "_grad_1",
                 {ograds[0], n->inputs[0]})
      };
});

NNVM_REGISTER_OP(div)
.add_alias("__div_symbol__")
.describe("do division")
.set_num_inputs(2)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds){
      NodeEntry n1 = MakeNode("mul", n->attrs.name + "_grad_sub_0",
                              {ograds[0], n->inputs[0]});
      NodeEntry n2 = MakeNode("__mul_scalar__", n->attrs.name + "_grad_sub_1",
                             {n1, {{"scalar", "-1"}}),
      NodeEntry n2 = MakeNode("mul", n->attrs.name + "_grad_sub_2",
                              {n->inputs[1], n->inputs[1]});
      return std::vector<NodeEntry>{
        MakeNode("__div_symbol__", n->attrs.name + "_grad_0",
                 {ograds[0], n->inputs[1]}),
        MakeNode("__div_symbol__", n->attrs.name + "_grad_1",
                 {n1, n2})
      };
});

NNVM_REGISTER_OP(__mul_scalar__)
.describe("Multiply symbol with scalar")
.set_num_inputs(1)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds){
      return std::vector<NodeEntry>{
        MakeNode("__mul_scalar__", n->attrs.name + "_grad_0",
                 {ograds[0]}, {{"scalar", n->attrs.dict["scalar"]}}),
      };
});

NNVM_REGISTER_OP(exp)
.describe("take elemtnwise exponation")
.set_num_inputs(1)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds) {
      return std::vector<NodeEntry>{
        MakeNode("__mul_symbol__", n->attrs.name + "_grad_0",
                 {ograds[0], NodePtr{n, 0, 0}})
      };
});

NNVM_REGISTER_OP(log)
.describe("take elemtnwise logarithm")
.set_num_inputs(1)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds) {
      return std::vector<NodeEntry>{
        MakeNode("__div_symbol__", n->attrs.name + "_grad_0",
                 {ograds[0], n->inputs[0]})
      };
});

NNVM_REGISTER_OP(matmul)
.describe("Matrix multiplication")
.set_num_inputs(2)
.set_attr<FInferShape>(
    "FInferShape", [](const NodeAttrs& attrs,
                      std::vector<TShape> *ishape,
                      std::vector<TShape> *oshape) {
      if (ishape->at(0).ndim() == 0) return false;
      if (ishape->at(1).ndim() == 0) return false;
      CHECK_EQ(ishape->at(0).ndim(), 2);
      CHECK_EQ(ishape->at(1).ndim(), 2);
      CHECK_EQ(ishape->at(0)[1], ishape->at(1)[0]);
      TShape target{ishape->at(0)[0], ishape->at(1)[1]};
      SHAPE_ASSIGN(oshape->at(0), target);
      return true;
    })
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds) {
      return MakeBackwardGrads("_matmul_backward", n,
                               {ograds[0], n->inputs[0], n->inputs[1]});
    });

// simply register a bulk op for backward
NNVM_REGISTER_OP(_matmul_backward)
.set_num_inputs(3)
.set_num_outputs(2)
.set_attr<FBackwardOutToInIndex>(
    "FBackwardOutToInIndex", [](const NodeAttrs& attrs) {
      return std::vector<uint32_t>{0, 1};
    })
.set_attr<FBackwardInGradIndex>(
    "FBackwardInGradIndex", [](const NodeAttrs& attrs) {
      return std::vector<uint32_t>{0};
    })
.set_attr<FInplaceOption>(
    "FInplaceOption", [](const NodeAttrs& attrs) {
      // lhs->gradLhs
      return std::vector<std::pair<int, int> >{{1, 0}};
    });

struct ReduceParam : public dmlc::Parameter<ReduceParam> {
  Tuple<int> reduction_indices;
  DMLC_DECLARE_PARAMETER(ReduceParam) {
    DMLC_DECLARE_FIELD(reduction_indices).set_default(Tuple<int>());
  }
};
DMLC_REGISTER_PARAMETER(ReduceParam);

inline bool ReduceShape(const NodeAttrs& attrs,
                        std::vector<TShape> *ishape,
                        std::vector<TShape> *oshape) {
  const auto& axis
      = dmlc::get<ReduceParam>(attrs.parsed).reduction_indices;
  if (ishape->at(0).ndim() == 0) return false;
  if (axis.ndim() == 0) {
    SHAPE_ASSIGN(oshape->at(0), TShape{1});
  } else {
    TShape tmp = ishape->at(0);
    for (uint32_t idx : axis) {
      tmp[idx] = 0;
    }
    std::vector<uint32_t> ret;
    for (uint32_t x : tmp) {
      if (x != 0) ret.push_back(x);
    }
    if (ret.size() == 0) ret.push_back(1);
    SHAPE_ASSIGN(oshape->at(0), TShape(ret.begin(), ret.end()));
  }
  return true;
}

NNVM_REGISTER_OP(reduce_sum)
.describe("reduce sum")
.set_attr_parser(ParamParser<ReduceParam>)
.set_num_inputs(1)
.set_attr<FInferShape>("FInferShape", ReduceShape)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds) {
      return MakeBackwardGrads("_reduce_sum_backward", n,
                               {ograds[0]}, n->attrs.dict);
    });

NNVM_REGISTER_OP(reduce_mean)
.describe("reduce mean")
.set_attr_parser(ParamParser<ReduceParam>)
.set_num_inputs(1)
.set_attr<FInferShape>("FInferShape", ReduceShape)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds) {
      return MakeBackwardGrads("_reduce_mean_backward", n,
                               {ograds[0]}, n->attrs.dict);
    });

NNVM_REGISTER_OP_GROUP(ReduceBackwardIndeAttr)
.set_attr<FBackwardOutToInIndex>(
    "FBackwardOutToInIndex", [](const NodeAttrs& attrs) {
      return std::vector<uint32_t>{0};
    })
.set_attr<FBackwardInGradIndex>(
    "FBackwardInGradIndex", [](const NodeAttrs& attrs) {
      return std::vector<uint32_t>{0};
    });

NNVM_REGISTER_OP(_reduce_sum_backward)
.set_num_inputs(1)
.set_num_outputs(1)
.include("ReduceBackwardIndeAttr");

NNVM_REGISTER_OP(_reduce_mean_backward)
.set_num_inputs(1)
.set_num_outputs(1)
.include("ReduceBackwardIndeAttr");

NNVM_REGISTER_OP(_argmax)
.set_attr_parser(ParamParser<ReduceParam>)
.set_num_inputs(1)
.set_attr<FInferShape>("FInferShape", ReduceShape);

}  // namespace tinyflow
<commit_msg>fix typo<commit_after>// Copyright (c) 2016 by Contributors
// implementation of common tensor operators
#include <tinyflow/base.h>
#include <dmlc/parameter.h>
#include <nnvm/op_attr_types.h>
#include <utility>
#include "./op_util.h"

namespace tinyflow {

// shape given the ZeroParam
using namespace nnvm;

// shape parameter for zeros, ones
struct ZeroParam : public dmlc::Parameter<ZeroParam> {
  TShape shape;
  int dtype;
  DMLC_DECLARE_PARAMETER(ZeroParam) {
    DMLC_DECLARE_FIELD(shape).set_default(TShape());
    DMLC_DECLARE_FIELD(dtype).set_default(kFloat32);
  }
};
DMLC_REGISTER_PARAMETER(ZeroParam);

inline bool ZeroShape(const NodeAttrs& attrs,
                      std::vector<TShape> *ishape,
                      std::vector<TShape> *oshape) {
  const TShape& ts = dmlc::get<ZeroParam>(attrs.parsed).shape;
  if (ts.ndim() != 0) {
    SHAPE_ASSIGN(oshape->at(0), ts);
    return true;
  } else {
    return false;
  }
}

inline bool ZeroType(const NodeAttrs& attrs,
                     std::vector<int> *iattr,
                     std::vector<int> *oattr) {
  int dtype = dmlc::get<ZeroParam>(attrs.parsed).dtype;
  DTYPE_ASSIGN(oattr->at(0), dtype);
  return true;
}

NNVM_REGISTER_OP_GROUP(ElementwiseOpAttr)
.set_attr<bool>("IsElementWise", true)
.set_attr<FInferShape>("FInferShape", SameShape);

NNVM_REGISTER_OP(zeros)
.describe("zeros")
.set_num_inputs(0)
.set_attr_parser(ParamParser<ZeroParam>)
.set_attr<FInferShape>("FInferShape", ZeroShape)
.set_attr<FInferType>("FInferType", ZeroType);

NNVM_REGISTER_OP(ones)
.describe("ones")
.set_num_inputs(0)
.set_attr_parser(ParamParser<ZeroParam>)
.set_attr<FInferShape>("FInferShape", ZeroShape)
.set_attr<FInferType>("FInferType", ZeroType);

NNVM_REGISTER_OP(normal)
.describe("normal distribution")
.set_num_inputs(0)
.set_attr_parser(ParamParser<ZeroParam>)
.set_attr<FInferShape>("FInferShape", ZeroShape)
.set_attr<FInferType>("FInferType", ZeroType);

NNVM_REGISTER_OP(equal)
.describe("Equal comparitor")
.set_num_inputs(2)
.set_attr<FInferShape>("FInferShape", SameShape);

NNVM_REGISTER_OP(ones_like)
.describe("ones_like")
.set_num_inputs(1)
.set_attr<FInferShape>("FInferShape", SameShape);

NNVM_REGISTER_OP(__add_symbol__)
.describe("add two data together")
.set_num_inputs(2)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds){
      return std::vector<NodeEntry>{ograds[0], ograds[0]};
});

NNVM_REGISTER_OP(__sub_symbol__)
.describe("do subtract")
.set_num_inputs(2)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds){
      return std::vector<NodeEntry>{
        MakeNode("__mul_scalar__", n->attrs.name + "_grad_0",
                 {ograds[0]}, {{"scalar", "1"}}),
        MakeNode("__mul_scalar__", n->attrs.name + "_grad_1",
                 {ograds[0]}, {{"scalar", "-1"}}),
      };
});

NNVM_REGISTER_OP(mul)
.add_alias("__mul_symbol__")
.describe("add two data together")
.set_num_inputs(2)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds){
      return std::vector<NodeEntry>{
        MakeNode("mul", n->attrs.name + "_grad_0",
                 {ograds[0], n->inputs[1]}),
        MakeNode("mul", n->attrs.name + "_grad_1",
                 {ograds[0], n->inputs[0]})
      };
});

NNVM_REGISTER_OP(div)
.add_alias("__div_symbol__")
.describe("do division")
.set_num_inputs(2)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds){
      NodeEntry n1 = MakeNode("mul", n->attrs.name + "_grad_sub_0",
                              {ograds[0], n->inputs[0]});
      NodeEntry n2 = MakeNode("__mul_scalar__", n->attrs.name + "_grad_sub_1",
                              {n1}, {{"scalar", "-1"}});
      NodeEntry n3 = MakeNode("mul", n->attrs.name + "_grad_sub_2",
                              {n->inputs[1], n->inputs[1]});
      return std::vector<NodeEntry>{
        MakeNode("__div_symbol__", n->attrs.name + "_grad_0",
                 {ograds[0], n->inputs[1]}),
        MakeNode("__div_symbol__", n->attrs.name + "_grad_1",
                 {n1, n2})
      };
});

NNVM_REGISTER_OP(__mul_scalar__)
.describe("Multiply symbol with scalar")
.set_num_inputs(1)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds){
      return std::vector<NodeEntry>{
        MakeNode("__mul_scalar__", n->attrs.name + "_grad_0",
                 {ograds[0]}, {{"scalar", n->attrs.dict["scalar"]}}),
      };
});

NNVM_REGISTER_OP(exp)
.describe("take elemtnwise exponation")
.set_num_inputs(1)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds) {
      return std::vector<NodeEntry>{
        MakeNode("__mul_symbol__", n->attrs.name + "_grad_0",
                 {ograds[0], NodeEntry{n, 0, 0}})
      };
});

NNVM_REGISTER_OP(log)
.describe("take elemtnwise logarithm")
.set_num_inputs(1)
.include("ElementwiseOpAttr")
.set_attr<FInplaceOption>("FInplaceOption", InplaceIn0Out0)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds) {
      return std::vector<NodeEntry>{
        MakeNode("__div_symbol__", n->attrs.name + "_grad_0",
                 {ograds[0], n->inputs[0]})
      };
});

NNVM_REGISTER_OP(matmul)
.describe("Matrix multiplication")
.set_num_inputs(2)
.set_attr<FInferShape>(
    "FInferShape", [](const NodeAttrs& attrs,
                      std::vector<TShape> *ishape,
                      std::vector<TShape> *oshape) {
      if (ishape->at(0).ndim() == 0) return false;
      if (ishape->at(1).ndim() == 0) return false;
      CHECK_EQ(ishape->at(0).ndim(), 2);
      CHECK_EQ(ishape->at(1).ndim(), 2);
      CHECK_EQ(ishape->at(0)[1], ishape->at(1)[0]);
      TShape target{ishape->at(0)[0], ishape->at(1)[1]};
      SHAPE_ASSIGN(oshape->at(0), target);
      return true;
    })
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds) {
      return MakeBackwardGrads("_matmul_backward", n,
                               {ograds[0], n->inputs[0], n->inputs[1]});
    });

// simply register a bulk op for backward
NNVM_REGISTER_OP(_matmul_backward)
.set_num_inputs(3)
.set_num_outputs(2)
.set_attr<FBackwardOutToInIndex>(
    "FBackwardOutToInIndex", [](const NodeAttrs& attrs) {
      return std::vector<uint32_t>{0, 1};
    })
.set_attr<FBackwardInGradIndex>(
    "FBackwardInGradIndex", [](const NodeAttrs& attrs) {
      return std::vector<uint32_t>{0};
    })
.set_attr<FInplaceOption>(
    "FInplaceOption", [](const NodeAttrs& attrs) {
      // lhs->gradLhs
      return std::vector<std::pair<int, int> >{{1, 0}};
    });

struct ReduceParam : public dmlc::Parameter<ReduceParam> {
  Tuple<int> reduction_indices;
  DMLC_DECLARE_PARAMETER(ReduceParam) {
    DMLC_DECLARE_FIELD(reduction_indices).set_default(Tuple<int>());
  }
};
DMLC_REGISTER_PARAMETER(ReduceParam);

inline bool ReduceShape(const NodeAttrs& attrs,
                        std::vector<TShape> *ishape,
                        std::vector<TShape> *oshape) {
  const auto& axis
      = dmlc::get<ReduceParam>(attrs.parsed).reduction_indices;
  if (ishape->at(0).ndim() == 0) return false;
  if (axis.ndim() == 0) {
    SHAPE_ASSIGN(oshape->at(0), TShape{1});
  } else {
    TShape tmp = ishape->at(0);
    for (uint32_t idx : axis) {
      tmp[idx] = 0;
    }
    std::vector<uint32_t> ret;
    for (uint32_t x : tmp) {
      if (x != 0) ret.push_back(x);
    }
    if (ret.size() == 0) ret.push_back(1);
    SHAPE_ASSIGN(oshape->at(0), TShape(ret.begin(), ret.end()));
  }
  return true;
}

NNVM_REGISTER_OP(reduce_sum)
.describe("reduce sum")
.set_attr_parser(ParamParser<ReduceParam>)
.set_num_inputs(1)
.set_attr<FInferShape>("FInferShape", ReduceShape)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds) {
      return MakeBackwardGrads("_reduce_sum_backward", n,
                               {ograds[0]}, n->attrs.dict);
    });

NNVM_REGISTER_OP(reduce_mean)
.describe("reduce mean")
.set_attr_parser(ParamParser<ReduceParam>)
.set_num_inputs(1)
.set_attr<FInferShape>("FInferShape", ReduceShape)
.set_attr<FGradient>(
    "FGradient", [](const NodePtr& n,
                    const std::vector<NodeEntry>& ograds) {
      return MakeBackwardGrads("_reduce_mean_backward", n,
                               {ograds[0]}, n->attrs.dict);
    });

NNVM_REGISTER_OP_GROUP(ReduceBackwardIndeAttr)
.set_attr<FBackwardOutToInIndex>(
    "FBackwardOutToInIndex", [](const NodeAttrs& attrs) {
      return std::vector<uint32_t>{0};
    })
.set_attr<FBackwardInGradIndex>(
    "FBackwardInGradIndex", [](const NodeAttrs& attrs) {
      return std::vector<uint32_t>{0};
    });

NNVM_REGISTER_OP(_reduce_sum_backward)
.set_num_inputs(1)
.set_num_outputs(1)
.include("ReduceBackwardIndeAttr");

NNVM_REGISTER_OP(_reduce_mean_backward)
.set_num_inputs(1)
.set_num_outputs(1)
.include("ReduceBackwardIndeAttr");

NNVM_REGISTER_OP(_argmax)
.set_attr_parser(ParamParser<ReduceParam>)
.set_num_inputs(1)
.set_attr<FInferShape>("FInferShape", ReduceShape);

}  // namespace tinyflow
<|endoftext|>


<commit_before>#include <fstream>
#include <ncurses.h>

#include "hooks.hh"
#include "open_file.hh"
#include "prompt.hh"

namespace vick {

struct full_diff : public change {
    contents o, n;
    full_diff(contents o, contents n)
        : o(o)
        , n(n)
    {
    }
    virtual bool is_overriding() override { return true; }
    virtual void undo(contents& cont) override { cont = o; }
    virtual void redo(contents& cont) override { cont = n; }
    virtual std::shared_ptr<change>
    regenerate(const contents& cont) const override
    {
        return std::make_shared<full_diff>(cont, n);
    }
};

boost::optional<std::shared_ptr<change> >
open_file_i(contents& cont, boost::optional<int>)
{
    attron(COLOR_PAIR(1));
    auto opt = prompt("File to open: ");
    attroff(COLOR_PAIR(1));
    if (not opt) return boost::none;
    return open_file(cont, *opt);
}

contents open_file(std::string file)
{
    contents cont;
    bool& windows = cont.windows_file_endings;
    bool asked = false;

    std::string line;
    std::ifstream myfile(file);

    if (std::getline(myfile, line)) {
        if (not line.empty() and line.back() == 13) {
            line.pop_back();
            windows = true;
        }
        cont.cont.push_back(line);
        while (std::getline(myfile, line)) {
            if (not line.empty() and line.back() == 13) {
                if (not windows and not asked) {
                    asked = true;
                    windows =
                        repeat_remove_optional(prompt_yes_no,
                                               "Windows file endings detected, "
                                               "use them when saving? ");
                }
                line.pop_back();
            }
            cont.cont.push_back(line);
        }
    } else {
        cont.cont.push_back("");
    }

    hook::proc(hook::open_file, cont);

    return cont;
}

boost::optional<std::shared_ptr<change> >
open_file(contents& cont, std::string file)
{
    contents before = cont;
    cont.y = 0;
    cont.x = 0;
    cont.cont.clear();
    bool& windows = cont.windows_file_endings;
    bool asked = false;
    std::string line;
    std::ifstream myfile(file);

    if (std::getline(myfile, line)) {
        if (not line.empty() and line.back() == 13) {
            line.pop_back();
            windows = true;
        }
        cont.cont.push_back(line);
        while (std::getline(myfile, line)) {
            if (not line.empty() and line.back() == 13) {
                if (not windows and not asked) {
                    asked = true;
                    windows =
                        repeat_remove_optional(prompt_yes_no,
                                               "Windows file endings detected, "
                                               "use them when saving? ");
                }
                line.pop_back();
            }
            cont.cont.push_back(line);
        }
    }
    else
        cont.cont.push_back("");

    hook::proc(hook::open_file, cont);

    if (before.cont == cont.cont) return boost::none;
    return boost::optional<std::shared_ptr<change> >(
        std::make_shared<full_diff>(std::move(before), cont));
}

}
<commit_msg>Replace `13` with `'\r'`<commit_after>#include <fstream>
#include <ncurses.h>

#include "hooks.hh"
#include "open_file.hh"
#include "prompt.hh"

namespace vick {

struct full_diff : public change {
    contents o, n;
    full_diff(contents o, contents n)
        : o(o)
        , n(n)
    {
    }
    virtual bool is_overriding() override { return true; }
    virtual void undo(contents& cont) override { cont = o; }
    virtual void redo(contents& cont) override { cont = n; }
    virtual std::shared_ptr<change>
    regenerate(const contents& cont) const override
    {
        return std::make_shared<full_diff>(cont, n);
    }
};

boost::optional<std::shared_ptr<change> >
open_file_i(contents& cont, boost::optional<int>)
{
    attron(COLOR_PAIR(1));
    auto opt = prompt("File to open: ");
    attroff(COLOR_PAIR(1));
    if (not opt) return boost::none;
    return open_file(cont, *opt);
}

contents open_file(std::string file)
{
    contents cont;
    bool& windows = cont.windows_file_endings;
    bool asked = false;

    std::string line;
    std::ifstream myfile(file);

    if (std::getline(myfile, line)) {
        if (not line.empty() and line.back() == '\r') {
            line.pop_back();
            windows = true;
        }
        cont.cont.push_back(line);
        while (std::getline(myfile, line)) {
            if (not line.empty() and line.back() == '\r') {
                if (not windows and not asked) {
                    asked = true;
                    windows =
                        repeat_remove_optional(prompt_yes_no,
                                               "Windows file endings detected, "
                                               "use them when saving? ");
                }
                line.pop_back();
            }
            cont.cont.push_back(line);
        }
    } else {
        cont.cont.push_back("");
    }

    hook::proc(hook::open_file, cont);

    return cont;
}

boost::optional<std::shared_ptr<change> >
open_file(contents& cont, std::string file)
{
    contents before = cont;
    cont.y = 0;
    cont.x = 0;
    cont.cont.clear();
    bool& windows = cont.windows_file_endings;
    bool asked = false;
    std::string line;
    std::ifstream myfile(file);

    if (std::getline(myfile, line)) {
        if (not line.empty() and line.back() == '\r') {
            line.pop_back();
            windows = true;
        }
        cont.cont.push_back(line);
        while (std::getline(myfile, line)) {
            if (not line.empty() and line.back() == '\r') {
                if (not windows and not asked) {
                    asked = true;
                    windows =
                        repeat_remove_optional(prompt_yes_no,
                                               "Windows file endings detected, "
                                               "use them when saving? ");
                }
                line.pop_back();
            }
            cont.cont.push_back(line);
        }
    }
    else
        cont.cont.push_back("");

    hook::proc(hook::open_file, cont);

    if (before.cont == cont.cont) return boost::none;
    return boost::optional<std::shared_ptr<change> >(
        std::make_shared<full_diff>(std::move(before), cont));
}

}
<|endoftext|>