<commit_before>/**
 * @file    ANSIModephrase.hh
 * @author  Paul Tagliamonte <tag@pault.ag>
 * @license MIT
 * @created Tue Nov  8 14:19:15 UTC 2011
 */

#include "StateMachine.hh"
#include "ANSIModephrase.hh"
#include "Exception.hh"
#include "InvalidState.hh"
#include "CSIValue.hh"

/* A bit of Wikipedia background:
 * Escape sequences start with the character ESC (ASCII decimal 27/hex
 * 0x1B/octal 033). For two character sequences the second character is in
 * the range ASCII 64 to 95 (@ to _). Most of the sequences are however more
 * than two characters, and start with the characters ESC and [ (left bracket).
 * This sequence is called CSI for Control Sequence Introducer (or Control
 * Sequence Initiator). The final character of these sequences is in the range
 * ASCII 64 to 126 (@ to ~).
 */

void ANSIModephrase::feed( char c ) {
	/* OK. We're escaped. Let's find out if we could have
	   a CSI entry, or a private-mode ANSI escape sequence */
	if ( c == '[' ) {
		/* OK. We've hit a CSI escape sequence. */
		ansi_next_state = &ansi_state_CSIValue;
	} else if ( c >= '@' && c <= '_' ) {
		/* We've hit a private-mode escape sequence */
	} else {
		/* We've hit garbage. */
		ansi_next_state = &ansi_state_InvalidState;
		throw new InvalidSequence();
	}
}

void ANSIModephrase::enter() {}
void ANSIModephrase::exit()  {}

ANSIModephrase ansi_state_ANSIModephrase;
<commit_msg>Private mode parsing is totally unimplemented<commit_after>/**
 * @file    ANSIModephrase.hh
 * @author  Paul Tagliamonte <tag@pault.ag>
 * @license MIT
 * @created Tue Nov  8 14:19:15 UTC 2011
 */

#include "StateMachine.hh"
#include "ANSIModephrase.hh"
#include "Exception.hh"
#include "InvalidState.hh"
#include "CSIValue.hh"

/* A bit of Wikipedia background:
 * Escape sequences start with the character ESC (ASCII decimal 27/hex
 * 0x1B/octal 033). For two character sequences the second character is in
 * the range ASCII 64 to 95 (@ to _). Most of the sequences are however more
 * than two characters, and start with the characters ESC and [ (left bracket).
 * This sequence is called CSI for Control Sequence Introducer (or Control
 * Sequence Initiator). The final character of these sequences is in the range
 * ASCII 64 to 126 (@ to ~).
 */

void ANSIModephrase::feed( char c ) {
	/* OK. We're escaped. Let's find out if we could have
	   a CSI entry, or a private-mode ANSI escape sequence */
	if ( c == '[' ) {
		/* OK. We've hit a CSI escape sequence. */
		ansi_next_state = &ansi_state_CSIValue;
	} else if ( c >= 64 && c <= 95 ) {
		/* We've hit a private-mode escape sequence */
		/* XXX: Implement the private-mode parsing */
		ansi_next_state = &ansi_state_InvalidState;
		throw new InvalidSequence();
	} else {
		/* We've hit garbage. */
		ansi_next_state = &ansi_state_InvalidState;
		throw new InvalidSequence();
	}
}

void ANSIModephrase::enter() {}
void ANSIModephrase::exit()  {}

ANSIModephrase ansi_state_ANSIModephrase;
<|endoftext|>


<commit_before>/*
 * geometry.cpp
 *
 *  Created on: 5. des. 2015
 *      Author: larso
 */

#include "geometry.h"
#include <stdexcept>

geometry::geometry() :
    initialized(false), ibuffer(0), vbuffer(0)
{
}

geometry::~geometry()
{
    glDeleteBuffers(1, &vbuffer);
    glDeleteBuffers(1, &ibuffer);
}

void geometry::initialize()
{
    glGenBuffers(1, &vbuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vbuffer);
    glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);

    glGenBuffers(1, &index_buffer);
    glBindBuffer(GL_ARRAY_BUFFER, ibuffer);
    glBufferData(GL_ARRAY_BUFFER, indices.size()*sizeof(GLushort), indices.data(), GL_STATIC_DRAW);
}

void geometry::vertex(glm::vec3 v)
{
    vertices.push_back(v);
}

void geometry::face(GLushort a, GLushort b, GLushort c)
{
    indices.push_back(a);
    indices.push_back(b);
    indices.push_back(c);
}

size_t geometry::element_count() const
{
    return indices.size();
}

GLuint geometry::vertex_buffer() const
{
    if(!initialized)
    {
        throw std::runtime_error("Must be initialized before retrieval of vertex buffer");
    }
    return vbuffer;
}

GLuint geometry::index_buffer() const
{
    if(!initialized)
    {
        throw std::runtime_error("Must be initialized before retrieval of index buffer");
    }
    return ibuffer;
}
<commit_msg>Fiksa bug der geometri ikkje ville kompilere<commit_after>/*
 * geometry.cpp
 *
 *  Created on: 5. des. 2015
 *      Author: larso
 */

#include "geometry.h"
#include <stdexcept>

geometry::geometry() :
    initialized(false), ibuffer(0), vbuffer(0)
{
}

geometry::~geometry()
{
    glDeleteBuffers(1, &vbuffer);
    glDeleteBuffers(1, &ibuffer);
}

void geometry::initialize()
{
    glGenBuffers(1, &vbuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vbuffer);
    glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);

    glGenBuffers(1, &ibuffer);
    glBindBuffer(GL_ARRAY_BUFFER, ibuffer);
    glBufferData(GL_ARRAY_BUFFER, indices.size()*sizeof(GLushort), indices.data(), GL_STATIC_DRAW);
}

void geometry::vertex(glm::vec3 v)
{
    vertices.push_back(v);
}

void geometry::face(GLushort a, GLushort b, GLushort c)
{
    indices.push_back(a);
    indices.push_back(b);
    indices.push_back(c);
}

size_t geometry::element_count() const
{
    return indices.size();
}

GLuint geometry::vertex_buffer() const
{
    if(!initialized)
    {
        throw std::runtime_error("Must be initialized before retrieval of vertex buffer");
    }
    return vbuffer;
}

GLuint geometry::index_buffer() const
{
    if(!initialized)
    {
        throw std::runtime_error("Must be initialized before retrieval of index buffer");
    }
    return ibuffer;
}
<|endoftext|>


<commit_before>/*
 *  This file is part of Poedit (https://poedit.net)
 *
 *  Copyright (C) 2000-2017 Vaclav Slavik
 *
 *  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 <wx/utils.h>
#include <wx/log.h>
#include <wx/process.h>
#include <wx/txtstrm.h>
#include <wx/string.h>
#include <wx/intl.h>
#include <wx/stdpaths.h>
#include <wx/translation.h>
#include <wx/filename.h>

#include <boost/throw_exception.hpp>

#include "gexecute.h"
#include "errors.h"

// GCC's libstdc++ didn't have functional std::regex implementation until 4.9
#if (defined(__GNUC__) && !defined(__clang__) && !wxCHECK_GCC_VERSION(4,9))
    #include <boost/regex.hpp>
    using boost::wregex;
    using boost::wsmatch;
    using boost::regex_match;
#else
    #include <regex>
    using std::wregex;
    using std::wsmatch;
    using std::regex_match;
#endif

namespace
{

#ifdef __WXOSX__
wxString GetGettextPluginPath()
{
    return wxStandardPaths::Get().GetPluginsDir() + "/GettextTools.bundle";
}
#endif // __WXOSX__

#if defined(__WXOSX__) || defined(__WXMSW__)

inline wxString GetAuxBinariesDir()
{
    return GetGettextPackagePath() + "/bin";
}

wxString GetPathToAuxBinary(const wxString& program)
{
    wxFileName path;
    path.SetPath(GetAuxBinariesDir());
    path.SetName(program);
#ifdef __WXMSW__
    path.SetExt("exe");
#endif
    if ( path.IsFileExecutable() )
    {
        return wxString::Format(_T("\"%s\""), path.GetFullPath().c_str());
    }
    else
    {
        wxLogTrace("poedit.execute",
                   L"%s doesn’t exist, falling back to %s",
                   path.GetFullPath().c_str(),
                   program.c_str());
        return program;
    }
}
#endif // __WXOSX__ || __WXMSW__

bool ReadOutput(wxInputStream& s, wxArrayString& out)
{
    // the stream could be already at EOF or in wxSTREAM_BROKEN_PIPE state
    s.Reset();
    wxTextInputStream tis(s, " ", wxConvUTF8);

    while (true)
    {
        wxString line = tis.ReadLine();
        if ( !line.empty() )
            out.push_back(line);
        if (s.Eof())
            break;
        if ( !s )
            return false;
    }

    return true;
}

long DoExecuteGettext(const wxString& cmdline_, wxArrayString& gstderr)
{
    wxExecuteEnv env;
    wxString cmdline(cmdline_);

#if defined(__WXOSX__) || defined(__WXMSW__)
    wxString binary = cmdline.BeforeFirst(_T(' '));
    cmdline = GetPathToAuxBinary(binary) + cmdline.Mid(binary.length());
    wxGetEnvMap(&env.env);
    env.env["GETTEXTIOENCODING"] = "UTF-8";

    wxString lang = wxTranslations::Get()->GetBestTranslation("gettext-tools");
	if ( !lang.empty() )
        env.env["LANG"] = lang;
#endif // __WXOSX__ || __WXMSW__

#ifdef __WXOSX__
    // Hack alert! On Windows, relocation works, but building with it is too
    // messy/broken on macOS, so just use some custom hacks instead:
    auto sharedir = GetGettextPackagePath() + "/share";
    env.env["POEDIT_LOCALEDIR"] = sharedir + "/locale";
    env.env["GETTEXTDATADIR"] = sharedir + "/gettext";
#endif

    wxLogTrace("poedit.execute", "executing: %s", cmdline.c_str());

    wxScopedPtr<wxProcess> process(new wxProcess);
    process->Redirect();

    long retcode = wxExecute(cmdline, wxEXEC_BLOCK | wxEXEC_NODISABLE | wxEXEC_NOEVENTS, process.get(), &env);

	wxInputStream *std_err = process->GetErrorStream();
    if ( std_err && !ReadOutput(*std_err, gstderr) )
        retcode = -1;

    if ( retcode == -1 )
    {
        BOOST_THROW_EXCEPTION(Exception(wxString::Format(_("Cannot execute program: %s"), cmdline.c_str())));
    }

    return retcode;
}

} // anonymous namespace

bool ExecuteGettext(const wxString& cmdline)
{
    wxArrayString gstderr;
    long retcode = DoExecuteGettext(cmdline, gstderr);

    wxString pending;
    for (auto& ln: gstderr)
    {
        if (ln.empty())
            continue;

        // special handling of multiline errors
        if (ln[0] == ' ' || ln[0] == '\t')
        {
            pending += "\n\t" + ln.Strip(wxString::both);
        }
        else
        {
            if (!pending.empty())
                wxLogError("%s", pending);

            pending = ln;
        }
    }

    if (!pending.empty())
        wxLogError("%s", pending);

    return retcode == 0;
}

bool ExecuteGettextAndParseOutput(const wxString& cmdline, GettextErrors& errors)
{
    wxArrayString gstderr;
    long retcode = DoExecuteGettext(cmdline, gstderr);

    static const wregex RE_ERROR(L".*\\.po:([0-9]+)(:[0-9]+)?: (.*)");

    for (const auto& ewx: gstderr)
    {
        const auto e = ewx.ToStdWstring();
        wxLogTrace("poedit", "  stderr: %s", e.c_str());
        if ( e.empty() )
            continue;

        GettextError rec;

        wsmatch match;
        if (regex_match(e, match, RE_ERROR))
        {
            rec.line = std::stoi(match.str(1));
            rec.text = match.str(3);
            errors.push_back(rec);
            wxLogTrace("poedit.execute",
                       _T("        => parsed error = \"%s\" at %d"),
                       rec.text.c_str(), rec.line);
        }
        else
        {
            wxLogTrace("poedit.execute", "        (unrecognized line!)");
            // FIXME: handle the rest of output gracefully too
        }
    }

    return retcode == 0;
}

wxString QuoteCmdlineArg(const wxString& s)
{
    wxString s2(s);
#ifdef __UNIX__
    s2.Replace("\"", "\\\"");
#endif
    return "\"" + s2 + "\"";
}

#if defined(__WXOSX__) || defined(__WXMSW__)
wxString GetGettextPackagePath()
{
#if defined(__WXOSX__)
    return GetGettextPluginPath() + "/Contents/MacOS";
#elif defined(__WXMSW__)
    return wxStandardPaths::Get().GetDataDir() + wxFILE_SEP_PATH + "GettextTools";
#endif
}
#endif // __WXOSX__ || __WXMSW__

<commit_msg>Fix handling of invalid-UTF-8 output of gettext tools<commit_after>/*
 *  This file is part of Poedit (https://poedit.net)
 *
 *  Copyright (C) 2000-2017 Vaclav Slavik
 *
 *  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 <wx/utils.h>
#include <wx/log.h>
#include <wx/process.h>
#include <wx/txtstrm.h>
#include <wx/string.h>
#include <wx/intl.h>
#include <wx/stdpaths.h>
#include <wx/translation.h>
#include <wx/filename.h>

#include <boost/throw_exception.hpp>

#include "gexecute.h"
#include "errors.h"

// GCC's libstdc++ didn't have functional std::regex implementation until 4.9
#if (defined(__GNUC__) && !defined(__clang__) && !wxCHECK_GCC_VERSION(4,9))
    #include <boost/regex.hpp>
    using boost::wregex;
    using boost::wsmatch;
    using boost::regex_match;
#else
    #include <regex>
    using std::wregex;
    using std::wsmatch;
    using std::regex_match;
#endif

namespace
{

#ifdef __WXOSX__
wxString GetGettextPluginPath()
{
    return wxStandardPaths::Get().GetPluginsDir() + "/GettextTools.bundle";
}
#endif // __WXOSX__

#if defined(__WXOSX__) || defined(__WXMSW__)

inline wxString GetAuxBinariesDir()
{
    return GetGettextPackagePath() + "/bin";
}

wxString GetPathToAuxBinary(const wxString& program)
{
    wxFileName path;
    path.SetPath(GetAuxBinariesDir());
    path.SetName(program);
#ifdef __WXMSW__
    path.SetExt("exe");
#endif
    if ( path.IsFileExecutable() )
    {
        return wxString::Format(_T("\"%s\""), path.GetFullPath().c_str());
    }
    else
    {
        wxLogTrace("poedit.execute",
                   L"%s doesn’t exist, falling back to %s",
                   path.GetFullPath().c_str(),
                   program.c_str());
        return program;
    }
}
#endif // __WXOSX__ || __WXMSW__

bool ReadOutput(wxInputStream& s, wxArrayString& out)
{
    // the stream could be already at EOF or in wxSTREAM_BROKEN_PIPE state
    s.Reset();
    wxTextInputStream tis(s, " ", wxConvAuto() /* UTF-8, fallback if impossible */);

    while (true)
    {
        wxString line = tis.ReadLine();
        if ( !line.empty() )
            out.push_back(line);
        if (s.Eof())
            break;
        if ( !s )
            return false;
    }

    return true;
}

long DoExecuteGettext(const wxString& cmdline_, wxArrayString& gstderr)
{
    wxExecuteEnv env;
    wxString cmdline(cmdline_);

#if defined(__WXOSX__) || defined(__WXMSW__)
    wxString binary = cmdline.BeforeFirst(_T(' '));
    cmdline = GetPathToAuxBinary(binary) + cmdline.Mid(binary.length());
    wxGetEnvMap(&env.env);
    env.env["GETTEXTIOENCODING"] = "UTF-8";

    wxString lang = wxTranslations::Get()->GetBestTranslation("gettext-tools");
	if ( !lang.empty() )
        env.env["LANG"] = lang;
#endif // __WXOSX__ || __WXMSW__

#ifdef __WXOSX__
    // Hack alert! On Windows, relocation works, but building with it is too
    // messy/broken on macOS, so just use some custom hacks instead:
    auto sharedir = GetGettextPackagePath() + "/share";
    env.env["POEDIT_LOCALEDIR"] = sharedir + "/locale";
    env.env["GETTEXTDATADIR"] = sharedir + "/gettext";
#endif

    wxLogTrace("poedit.execute", "executing: %s", cmdline.c_str());

    wxScopedPtr<wxProcess> process(new wxProcess);
    process->Redirect();

    long retcode = wxExecute(cmdline, wxEXEC_BLOCK | wxEXEC_NODISABLE | wxEXEC_NOEVENTS, process.get(), &env);

	wxInputStream *std_err = process->GetErrorStream();
    if ( std_err && !ReadOutput(*std_err, gstderr) )
        retcode = -1;

    if ( retcode == -1 )
    {
        BOOST_THROW_EXCEPTION(Exception(wxString::Format(_("Cannot execute program: %s"), cmdline.c_str())));
    }

    return retcode;
}

} // anonymous namespace

bool ExecuteGettext(const wxString& cmdline)
{
    wxArrayString gstderr;
    long retcode = DoExecuteGettext(cmdline, gstderr);

    wxString pending;
    for (auto& ln: gstderr)
    {
        if (ln.empty())
            continue;

        // special handling of multiline errors
        if (ln[0] == ' ' || ln[0] == '\t')
        {
            pending += "\n\t" + ln.Strip(wxString::both);
        }
        else
        {
            if (!pending.empty())
                wxLogError("%s", pending);

            pending = ln;
        }
    }

    if (!pending.empty())
        wxLogError("%s", pending);

    return retcode == 0;
}

bool ExecuteGettextAndParseOutput(const wxString& cmdline, GettextErrors& errors)
{
    wxArrayString gstderr;
    long retcode = DoExecuteGettext(cmdline, gstderr);

    static const wregex RE_ERROR(L".*\\.po:([0-9]+)(:[0-9]+)?: (.*)");

    for (const auto& ewx: gstderr)
    {
        const auto e = ewx.ToStdWstring();
        wxLogTrace("poedit", "  stderr: %s", e.c_str());
        if ( e.empty() )
            continue;

        GettextError rec;

        wsmatch match;
        if (regex_match(e, match, RE_ERROR))
        {
            rec.line = std::stoi(match.str(1));
            rec.text = match.str(3);
            errors.push_back(rec);
            wxLogTrace("poedit.execute",
                       _T("        => parsed error = \"%s\" at %d"),
                       rec.text.c_str(), rec.line);
        }
        else
        {
            wxLogTrace("poedit.execute", "        (unrecognized line!)");
            // FIXME: handle the rest of output gracefully too
        }
    }

    return retcode == 0;
}

wxString QuoteCmdlineArg(const wxString& s)
{
    wxString s2(s);
#ifdef __UNIX__
    s2.Replace("\"", "\\\"");
#endif
    return "\"" + s2 + "\"";
}

#if defined(__WXOSX__) || defined(__WXMSW__)
wxString GetGettextPackagePath()
{
#if defined(__WXOSX__)
    return GetGettextPluginPath() + "/Contents/MacOS";
#elif defined(__WXMSW__)
    return wxStandardPaths::Get().GetDataDir() + wxFILE_SEP_PATH + "GettextTools";
#endif
}
#endif // __WXOSX__ || __WXMSW__

<|endoftext|>


<commit_before>#include <CQCustomCombo.h>
#include <QListWidgetItem>
#include <QItemDelegate>
#include <QPainter>
#include <QApplication>

class CQCustomComboItem : public QListWidgetItem {
 public:
  CQCustomComboItem(CQCustomCombo *combo, const QString &str);

  virtual ~CQCustomComboItem() { }

  void setIsTitle(bool b) {
    isTitle_ = b;

    if (isTitle_)
      setSelectable(false);
  }

  bool isTitle() const { return isTitle_; }

  void setSelectable(bool selectable) {
    selectable_ = selectable;

    if (selectable_)
      setFlags(flags() |  (Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));
    else
      setFlags(flags() & ~(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));
  }

  bool isSelectable() const {
    return (flags() & (Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));
  }

 private:
  CQCustomCombo *combo_;
  bool           isTitle_;
  bool           selectable_;
};

//------

class CQCustomComboDelegate : public QItemDelegate {
 public:
  CQCustomComboDelegate(CQCustomCombo *combo) :
   combo_(combo) {
  }

  void paint(QPainter *painter, const QStyleOptionViewItem &option,
             const QModelIndex &index) const {
<<<<<<< HEAD
    CQCustomComboItem *item = static_cast<CQCustomComboItem *>(combo_->list()->item(index.row()));
=======
    int row = index.row();

    CQCustomComboItem *item = static_cast<CQCustomComboItem *>(combo_->list()->item(row));

    //painter->save();
>>>>>>> 14bd61b68d7f0e1815af59bdfd719ec9088c4c09

    QStyleOptionMenuItem opt = getStyleOption(option, index, item);

    painter->fillRect(opt.rect, opt.palette.background());

    combo_->style()->drawControl(QStyle::CE_MenuItem, &opt, painter, combo_);
<<<<<<< HEAD
  }

  QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
    CQCustomComboItem *item = static_cast<CQCustomComboItem *>(combo_->list()->item(index.row()));

    QStyleOptionMenuItem opt = getStyleOption(option, index, item);

    return combo_->style()->sizeFromContents(QStyle::CT_MenuItem, &opt, option.rect.size(), combo_);
=======

    //painter->restore();
  }

  QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &index) const {
    QFontMetrics fm(combo_->font());

    int row = index.row();

    QString text = combo_->itemText(row);

    return QSize(fm.width(text) + 4, fm.height() + 4);
>>>>>>> 14bd61b68d7f0e1815af59bdfd719ec9088c4c09
  }

  QStyleOptionMenuItem getStyleOption(const QStyleOptionViewItem &option,
                                      const QModelIndex &index, CQCustomComboItem *item) const {
    QStyleOptionMenuItem menuOption;

    QPalette resolvedpalette = option.palette.resolve(QApplication::palette("QMenu"));

    QBrush textBrush = resolvedpalette.brush(QPalette::Active, QPalette::Text);

    QVariant value = index.data(Qt::ForegroundRole);

    if (value.canConvert<QBrush>())
      textBrush = qvariant_cast<QBrush>(value);

    if (! item->isSelectable())
      textBrush = resolvedpalette.brush(QPalette::Disabled, QPalette::Text);

    if (item->isTitle())
      textBrush = resolvedpalette.brush(QPalette::Active, QPalette::HighlightedText);

    resolvedpalette.setBrush(QPalette::WindowText, textBrush);
    resolvedpalette.setBrush(QPalette::ButtonText, textBrush);
    resolvedpalette.setBrush(QPalette::Text      , textBrush);

    menuOption.palette = resolvedpalette;
    menuOption.state   = QStyle::State_None;

    if (combo_->window()->isActiveWindow())
      menuOption.state = QStyle::State_Active;

    if ((option.state & QStyle::State_Enabled) && (index.model()->flags(index) & Qt::ItemIsEnabled))
      menuOption.state |= QStyle::State_Enabled;
    else
      menuOption.palette.setCurrentColorGroup(QPalette::Disabled);

    if (option.state & QStyle::State_Selected)
      menuOption.state |= QStyle::State_Selected;

    menuOption.checkType = QStyleOptionMenuItem::NonExclusive;
    menuOption.checked   = (combo_->currentIndex() == index.row());

    if (isSeparator(index))
      menuOption.menuItemType = QStyleOptionMenuItem::Separator;
    else
      menuOption.menuItemType = QStyleOptionMenuItem::Normal;

    QVariant variant = index.model()->data(index, Qt::DecorationRole);

#if 0
    switch (variant.type()) {
      case QVariant::Icon:
        menuOption.icon = qvariant_cast<QIcon>(variant);
        break;
      case QVariant::Color: {
        static QPixmap pixmap(option.decorationSize);
        pixmap.fill(qvariant_cast<QColor>(variant));
        menuOption.icon = pixmap;
        break; }
      default:
        menuOption.icon = qvariant_cast<QPixmap>(variant);
        break;
    }
#endif

    QBrush bgBrush = menuOption.palette.brush(QPalette::Background);

    if (index.data(Qt::BackgroundRole).canConvert<QBrush>())
      bgBrush = qvariant_cast<QBrush>(index.data(Qt::BackgroundRole));

    if (item->isTitle())
      bgBrush = resolvedpalette.brush(QPalette::Active, QPalette::Highlight);

    menuOption.palette.setBrush(QPalette::All, QPalette::Background, bgBrush);

    menuOption.text = index.model()->data(index, Qt::DisplayRole).toString();
<<<<<<< HEAD
  //menuOption.text = menuOption.text.replace(QLatin1Char('&'), QLatin1String("&&"));
=======
    //menuOption.text = menuOption.text.replace(QLatin1Char('&'), QLatin1String("&&"));
>>>>>>> 14bd61b68d7f0e1815af59bdfd719ec9088c4c09

    menuOption.tabWidth     = 0;
    menuOption.maxIconWidth = option.decorationSize.width() + 4;
    menuOption.menuRect     = option.rect;
    menuOption.rect         = option.rect;
    menuOption.font         = combo_->font();
    menuOption.fontMetrics  = QFontMetrics(menuOption.font);

    if (item->isTitle())
      menuOption.font.setBold(true);

    return menuOption;
  }

  static bool isSeparator(const QModelIndex &index) {
    return (index.data(Qt::AccessibleDescriptionRole).toString() == "separator");
  }

 private:
  CQCustomCombo *combo_;
};

//------

class CQCustomComboTitle : public CQCustomComboItem {
 public:
  CQCustomComboTitle(CQCustomCombo *combo, const QString &str) :
   CQCustomComboItem(combo, str) {
    setSelectable(false);

    setIsTitle(true);
  }
};

//------

CQCustomComboItem::
CQCustomComboItem(CQCustomCombo *combo, const QString &str) :
 QListWidgetItem(str), combo_(combo), isTitle_(false), selectable_(true)
{
}

//------

CQCustomCombo::
CQCustomCombo(QWidget *parent) :
 QComboBox(parent), list_(0)
{
  list_ = new QListWidget;
  list_->setItemDelegate(new CQCustomComboDelegate(this));

  setModel(list_->model());
  setView(list_);
}

void
CQCustomCombo::
addTitle(const QString &text)
{
  list_->addItem(new CQCustomComboTitle(this, text));

  resetCurrentInd();
}

void
CQCustomCombo::
addItem(const QString &text)
{
  list_->addItem(new CQCustomComboItem(this, text));

  resetCurrentInd();
}

void
CQCustomCombo::
setIsTitle(int ind, bool b)
{
  CQCustomComboItem *item = dynamic_cast<CQCustomComboItem *>(list_->item(ind));

  item->setIsTitle(b);

  resetCurrentInd();
}

void
CQCustomCombo::
setSelectable(int ind, bool b)
{
  CQCustomComboItem *item = dynamic_cast<CQCustomComboItem *>(list_->item(ind));

  item->setSelectable(b);

  resetCurrentInd();
}

void
CQCustomCombo::
resetCurrentInd()
{
  CQCustomComboItem *item = static_cast<CQCustomComboItem *>(list()->item(currentIndex()));

  if (item->isSelectable())
    return;

  for (int i = 0; i < count(); ++i) {
    CQCustomComboItem *item = static_cast<CQCustomComboItem *>(list()->item(i));

    if (item->isSelectable()) {
      setCurrentIndex(i);
      break;
    }
  }
}
<commit_msg>new files<commit_after>#include <CQCustomCombo.h>
#include <QListWidgetItem>
#include <QItemDelegate>
#include <QPainter>
#include <QApplication>

class CQCustomComboItem : public QListWidgetItem {
 public:
  CQCustomComboItem(CQCustomCombo *combo, const QString &str);

  virtual ~CQCustomComboItem() { }

  void setIsTitle(bool b) {
    isTitle_ = b;

    if (isTitle_)
      setSelectable(false);
  }

  bool isTitle() const { return isTitle_; }

  void setSelectable(bool selectable) {
    selectable_ = selectable;

    if (selectable_)
      setFlags(flags() |  (Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));
    else
      setFlags(flags() & ~(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));
  }

  bool isSelectable() const {
    return (flags() & (Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));
  }

 private:
  CQCustomCombo *combo_;
  bool           isTitle_;
  bool           selectable_;
};

//------

class CQCustomComboDelegate : public QItemDelegate {
 public:
  CQCustomComboDelegate(CQCustomCombo *combo) :
   combo_(combo) {
  }

  void paint(QPainter *painter, const QStyleOptionViewItem &option,
             const QModelIndex &index) const {
    CQCustomComboItem *item = static_cast<CQCustomComboItem *>(combo_->list()->item(index.row()));

    QStyleOptionMenuItem opt = getStyleOption(option, index, item);

    painter->fillRect(opt.rect, opt.palette.background());

    combo_->style()->drawControl(QStyle::CE_MenuItem, &opt, painter, combo_);
  }

  QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
    CQCustomComboItem *item = static_cast<CQCustomComboItem *>(combo_->list()->item(index.row()));

    QStyleOptionMenuItem opt = getStyleOption(option, index, item);

    return combo_->style()->sizeFromContents(QStyle::CT_MenuItem, &opt, option.rect.size(), combo_);
  }

  QStyleOptionMenuItem getStyleOption(const QStyleOptionViewItem &option,
                                      const QModelIndex &index, CQCustomComboItem *item) const {
    QStyleOptionMenuItem menuOption;

    QPalette resolvedpalette = option.palette.resolve(QApplication::palette("QMenu"));

    QBrush textBrush = resolvedpalette.brush(QPalette::Active, QPalette::Text);

    QVariant value = index.data(Qt::ForegroundRole);

    if (value.canConvert<QBrush>())
      textBrush = qvariant_cast<QBrush>(value);

    if (! item->isSelectable())
      textBrush = resolvedpalette.brush(QPalette::Disabled, QPalette::Text);

    if (item->isTitle())
      textBrush = resolvedpalette.brush(QPalette::Active, QPalette::HighlightedText);

    resolvedpalette.setBrush(QPalette::WindowText, textBrush);
    resolvedpalette.setBrush(QPalette::ButtonText, textBrush);
    resolvedpalette.setBrush(QPalette::Text      , textBrush);

    menuOption.palette = resolvedpalette;
    menuOption.state   = QStyle::State_None;

    if (combo_->window()->isActiveWindow())
      menuOption.state = QStyle::State_Active;

    if ((option.state & QStyle::State_Enabled) && (index.model()->flags(index) & Qt::ItemIsEnabled))
      menuOption.state |= QStyle::State_Enabled;
    else
      menuOption.palette.setCurrentColorGroup(QPalette::Disabled);

    if (option.state & QStyle::State_Selected)
      menuOption.state |= QStyle::State_Selected;

    menuOption.checkType = QStyleOptionMenuItem::NonExclusive;
    menuOption.checked   = (combo_->currentIndex() == index.row());

    if (isSeparator(index))
      menuOption.menuItemType = QStyleOptionMenuItem::Separator;
    else
      menuOption.menuItemType = QStyleOptionMenuItem::Normal;

    QVariant variant = index.model()->data(index, Qt::DecorationRole);

#if 0
    switch (variant.type()) {
      case QVariant::Icon:
        menuOption.icon = qvariant_cast<QIcon>(variant);
        break;
      case QVariant::Color: {
        static QPixmap pixmap(option.decorationSize);
        pixmap.fill(qvariant_cast<QColor>(variant));
        menuOption.icon = pixmap;
        break; }
      default:
        menuOption.icon = qvariant_cast<QPixmap>(variant);
        break;
    }
#endif

    QBrush bgBrush = menuOption.palette.brush(QPalette::Background);

    if (index.data(Qt::BackgroundRole).canConvert<QBrush>())
      bgBrush = qvariant_cast<QBrush>(index.data(Qt::BackgroundRole));

    if (item->isTitle())
      bgBrush = resolvedpalette.brush(QPalette::Active, QPalette::Highlight);

    menuOption.palette.setBrush(QPalette::All, QPalette::Background, bgBrush);

    menuOption.text = index.model()->data(index, Qt::DisplayRole).toString();
  //menuOption.text = menuOption.text.replace(QLatin1Char('&'), QLatin1String("&&"));

    menuOption.tabWidth     = 0;
    menuOption.maxIconWidth = option.decorationSize.width() + 4;
    menuOption.menuRect     = option.rect;
    menuOption.rect         = option.rect;
    menuOption.font         = combo_->font();
    menuOption.fontMetrics  = QFontMetrics(menuOption.font);

    if (item->isTitle())
      menuOption.font.setBold(true);

    return menuOption;
  }

  static bool isSeparator(const QModelIndex &index) {
    return (index.data(Qt::AccessibleDescriptionRole).toString() == "separator");
  }

 private:
  CQCustomCombo *combo_;
};

//------

class CQCustomComboTitle : public CQCustomComboItem {
 public:
  CQCustomComboTitle(CQCustomCombo *combo, const QString &str) :
   CQCustomComboItem(combo, str) {
    setSelectable(false);

    setIsTitle(true);
  }
};

//------

CQCustomComboItem::
CQCustomComboItem(CQCustomCombo *combo, const QString &str) :
 QListWidgetItem(str), combo_(combo), isTitle_(false), selectable_(true)
{
}

//------

CQCustomCombo::
CQCustomCombo(QWidget *parent) :
 QComboBox(parent), list_(0)
{
  list_ = new QListWidget;
  list_->setItemDelegate(new CQCustomComboDelegate(this));

  setModel(list_->model());
  setView(list_);
}

void
CQCustomCombo::
addTitle(const QString &text)
{
  list_->addItem(new CQCustomComboTitle(this, text));

  resetCurrentInd();
}

void
CQCustomCombo::
addItem(const QString &text)
{
  list_->addItem(new CQCustomComboItem(this, text));

  resetCurrentInd();
}

void
CQCustomCombo::
setIsTitle(int ind, bool b)
{
  CQCustomComboItem *item = dynamic_cast<CQCustomComboItem *>(list_->item(ind));

  item->setIsTitle(b);

  resetCurrentInd();
}

void
CQCustomCombo::
setSelectable(int ind, bool b)
{
  CQCustomComboItem *item = dynamic_cast<CQCustomComboItem *>(list_->item(ind));

  item->setSelectable(b);

  resetCurrentInd();
}

void
CQCustomCombo::
resetCurrentInd()
{
  CQCustomComboItem *item = static_cast<CQCustomComboItem *>(list()->item(currentIndex()));

  if (item->isSelectable())
    return;

  for (int i = 0; i < count(); ++i) {
    CQCustomComboItem *item = static_cast<CQCustomComboItem *>(list()->item(i));

    if (item->isSelectable()) {
      setCurrentIndex(i);
      break;
    }
  }
}
<|endoftext|>


<commit_before>/**
  ******************************************************************************
  * @file    voodoospark.cpp
  * @author  Chris Williams
  * @version V2.0.0
  * @date    07-May-2014
  * @brief   Exposes the firmware level API through a TCP Connection initiated
  *          to the spark device
  ******************************************************************************
  Copyright (c) 2014 Chris Williams  All rights reserved.

  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.
  ******************************************************************************
  */

#define DEBUG 0

 // Port = 0xbeef
#define PORT 48879

// TCPClient client;
TCPServer server = TCPServer(PORT);
TCPClient client;
byte readBuffer[128];
byte reading[20];
byte previous[20];
Servo servos[20];

long SerialSpeed[] = { 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200 };

void send(int action, int pin, int value) {
  if (previous[pin] != value) {
    server.write(action);
    server.write(pin);
    server.write(value);
  }
  previous[pin] = value;
}

void report() {
  for (int i = 0; i < 20; i++) {
    if (reading[i]) {
      int dr = (reading[i] & 1);
      int ar = (reading[i] & 2);

      if (i < 10 && dr) {
        send(0x03, i, digitalRead(i));
      } else {
        if (dr) {
          send(0x03, i, digitalRead(i));
        } else {
          if (ar) {
            send(0x04, i, analogRead(i));
          }
        }
      }
    }
  }
}

char myIpString[24];

void setup() {

  for (int i = 0; i < 20; i++) {
    reading[i] = 0;
    previous[i] = 0;
  }

  server.begin();
  netapp_ipconfig(&ip_config);

  #ifdef DEBUG
  Serial.begin(115200);
  #endif

  IPAddress myIp = Network.localIP();
  sprintf(myIpString, "%d.%d.%d.%d:%d", myIp[0], myIp[1], myIp[2], myIp[3], PORT);
  Spark.variable("endpoint", myIpString, STRING);

}

// table of action codes
// to do: make this an enum?
#define msg_pinMode                    (0x00)
#define msg_digitalWrite               (0x01)
#define msg_analogWrite                (0x02)
#define msg_digitalRead                (0x03)
#define msg_analogRead                 (0x04)
#define msg_setAlwaysSendBit           (0x05)
/* NOTE GAP */
#define msg_serialBegin                (0x10)
#define msg_serialEnd                  (0x11)
#define msg_serialPeek                 (0x12)
#define msg_serialAvailable            (0x13)
#define msg_serialWrite                (0x14)
#define msg_serialRead                 (0x15)
#define msg_serialFlush                (0x16)
/* NOTE GAP */
#define msg_spiBegin                   (0x20)
#define msg_spiEnd                     (0x21)
#define msg_spiSetBitOrder             (0x22)
#define msg_spiSetClockDivider         (0x23)
#define msg_spiSetDataMode             (0x24)
#define msg_spiTransfer                (0x25)
/* NOTE GAP */
#define msg_wireBegin                  (0x30)
#define msg_wireRequestFrom            (0x31)
#define msg_wireBeginTransmission      (0x32)
#define msg_wireEndTransmission        (0x33)
#define msg_wireWrite                  (0x34)
#define msg_wireAvailable              (0x35)
#define msg_wireRead                   (0x36)
/* NOTE GAP */
#define msg_servoAttach                (0x40)
#define msg_servoWrite                 (0x41)
#define msg_servoWriteMicroseconds     (0x42)
#define msg_servoRead                  (0x43)
#define msg_servoAttached              (0x44)
#define msg_servoDetach                (0x45)

#define msg_count                      (0x46)

//
// each position in the array corresponds to an action received from the client.
// e.g. msgMinLength[0] corresponds to action == 0 in the switch(action) in loop().
//      msgMinLength[0] == 2 (one byte each for pin and mode)
//
uint8_t msgMinLength[] = {
   // digital/analog I/O
   2,    // msg_pinMode
   2,    // msg_digitalWrite
   2,    // msg_analogWrite
   1,    // msg_digitalRead
   1,    // msg_analogRead
   2,    // msg_setAlwaysSendBit
   // gap from 0x06-0x0f
   0,    // msg_0x06
   0,    // msg_0x07
   0,    // msg_0x08
   0,    // msg_0x09
   0,    // msg_0x0a
   0,    // msg_0x0b
   0,    // msg_0x0c
   0,    // msg_0x0d
   0,    // msg_0x0e
   0,    // msg_0x0f
   // serial I/O
   2,    // msg_serialBegin
   1,    // msg_serialEnd
   1,    // msg_serialPeek
   1,    // msg_serialAvailable
   2,    // msg_serialWrite  -- variable length message!
   1,    // msg_serialRead
   1,    // msg_serialFlush
   // gap from 0x17-0x1f
   0,    // msg_0x17
   0,    // msg_0x18
   0,    // msg_0x19
   0,    // msg_0x1a
   0,    // msg_0x1b
   0,    // msg_0x1c
   0,    // msg_0x1d
   0,    // msg_0x1e
   0,    // msg_0x1f
   // SPI I/O
   0,    // msg_spiBegin
   0,    // msg_spiEnd
   1,    // msg_spiSetBitOrder
   1,    // msg_spiSetClockDivider
   1,    // msg_spiSetDataMode
   1,    // msg_spiTransfer
   // gap from 0x26-0x2f
   0,    // msg_0x26
   0,    // msg_0x27
   0,    // msg_0x28
   0,    // msg_0x29
   0,    // msg_0x2a
   0,    // msg_0x2b
   0,    // msg_0x2c
   0,    // msg_0x2d
   0,    // msg_0x2e
   0,    // msg_0x2f
   // wire I/O
   1,    // msg_wireBegin
   3,    // msg_wireRequestFrom
   1,    // msg_wireBeginTransmission
   1,    // msg_wireEndTransmission
   1,    // msg_wireWrite  -- variable length message!
   0,    // msg_wireAvailable
   0,    // msg_wireRead
   // gap from 0x37-0x3f
   0,    // msg_0x37
   0,    // msg_0x38
   0,    // msg_0x39
   0,    // msg_0x3a
   0,    // msg_0x3b
   0,    // msg_0x3c
   0,    // msg_0x3d
   0,    // msg_0x3e
   0,    // msg_0x3f
   // servo
   1,    // msg_servoAttach
   2,    // msg_servoWrite
   2,    // msg_servoWriteMicroseconds
   1,    // msg_servoRead
   1,    // msg_servoAttached
   1,    // msg_servoDetach
};

// these are outside loop() so they'll retain their values
//    between calls to loop()
int length = 0;
int idx,action,a;

void loop() {
  if (client.connected()) {
    // report();

    a = client.available();
    if (a > 0) {

      // length == current buffer length
      // a == # bytes available
      // if the sum exceeds the size of the buffer, decrease the
      //    # of bytes to read by length
      if (length + a > (int) sizeof readBuffer)
         a = sizeof readBuffer - length;

      // read into the buffer at offset length
      client.read(readBuffer+length, a);

      // increase length by # of extra bytes read
      length += a;

      // start at beginning of buffer.  should be an action.
      idx = 0;

      // parse and execute commands

      while (idx < length)
      {
         action = readBuffer[idx++];
          #ifdef DEBUG
          Serial.println("Action received: " + ('0' + action));
          #endif

         // is the action valid?
         if (action < msg_count)
         {
            // is there enough data left in the buffer to
            //    process this action?
            // if not, stop and fix
            if (idx + msgMinLength[action] < length)
            {

               int pin, mode, val, type, speed, address, stop, len, i;
               switch (action) {
               case msg_pinMode:  // pinMode
                  pin = readBuffer[idx++];
                  mode = readBuffer[idx++];
                  // mode is modeled after Standard Firmata
                  if (mode == 0x00) {
                     pinMode(pin, INPUT);
                  } else if (mode == 0x02) {
                     pinMode(pin, INPUT_PULLUP);
                  } else if (mode == 0x03) {
                     pinMode(pin, INPUT_PULLDOWN);
                  } else if (mode == 0x01) {
                     pinMode(pin, OUTPUT);
                  }
                  break;
               case msg_digitalWrite:  // digitalWrite
                  pin = readBuffer[idx++];
                  val = readBuffer[idx++];
                  digitalWrite(pin, val);
                  break;
               case msg_analogWrite:  // analogWrite
                  pin = readBuffer[idx++];
                  val = readBuffer[idx++];
                  analogWrite(pin, val);
                  break;
               case msg_digitalRead:  // digitalRead
                  pin = readBuffer[idx++];
                  val = digitalRead(pin);
                  server.write(0x03);    // could be (action)
                  server.write(pin);
                  server.write(val);
                  break;
               case msg_analogRead:  // analogRead
                  pin = readBuffer[idx++];
                  val = analogRead(pin);
                  server.write(0x04);    // could be (action)
                  server.write(pin);
                  server.write(val);
                  break;
               case msg_setAlwaysSendBit: // set always send bit
                  pin = readBuffer[idx++];
                  val = readBuffer[idx++];
                  reading[pin] = val;
                  break;

               // Serial API
               case msg_serialBegin:  // serial.begin
                  type = readBuffer[idx++];
                  speed = readBuffer[idx++];
                  if (type == 0) {
                     Serial.begin(SerialSpeed[speed]);
                  } else {
                     Serial1.begin(SerialSpeed[speed]);
                  }
                  break;
               case msg_serialEnd:  // serial.end
                  type = readBuffer[idx++];
                  if (type == 0) {
                     Serial.end();
                  } else {
                     Serial1.end();
                  }
                  break;
               case msg_serialPeek:  // serial.peek
                  type = readBuffer[idx++];
                  if (type == 0) {
                     val = Serial.peek();
                  } else {
                     val = Serial1.peek();
                  }
                  server.write(0x07);
                  server.write(type);
                  server.write(val);
                  break;
               case msg_serialAvailable:  // serial.available()
                  type = readBuffer[idx++];
                  if (type == 0) {
                     val = Serial.available();
                  } else {
                     val = Serial1.available();
                  }
                  server.write(0x07);
                  server.write(type);
                  server.write(val);
                  break;
               case msg_serialWrite:  // serial.write
                  type = readBuffer[idx++];
                  len = readBuffer[idx++];

                  if (idx + len < length)
                  {
                     for (i = 0; i < len; i++)
                        if (type == 0) {
                           Serial.write(readBuffer[idx++]);
                        } else {
                           Serial1.write(readBuffer[idx++]);
                        }
                  }
                  else
                  {
                     // fix up an incomplete message, putting it at the front
                     //    of the buffer:
                     // the first byte has to be the action value, then type
                     //    then len, and then the remaining bytes get copied.
                     // then bail.
                     readBuffer[0] = action;
                     readBuffer[1] = type;
                     readBuffer[2] = len;
                     memcpy (readBuffer+3, readBuffer+idx, length-idx);
                     idx = length - idx + 3;
                     return;
                  }
                  break;
               case msg_serialRead: // serial.read
                  type = readBuffer[idx++];
                  if (type == 0) {
                     val = Serial.read();
                  } else {
                     val = Serial1.read();
                  }
                  server.write(0x16);
                  server.write(type);
                  server.write(val);
                  break;
               case msg_serialFlush: // serial.flush
                  type = readBuffer[idx++];
                  if (type == 0) {
                     Serial.flush();
                  } else {
                     Serial1.flush();
                  }
                  break;

               // SPI API
               case msg_spiBegin:  // SPI.begin
                  SPI.begin();
                  break;
               case msg_spiEnd:  // SPI.end
                  SPI.end();
                  break;
               case msg_spiSetBitOrder:  // SPI.setBitOrder
                  type = readBuffer[idx++];
                  SPI.setBitOrder((type ? MSBFIRST : LSBFIRST));
                  break;
               case msg_spiSetClockDivider:  // SPI.setClockDivider
                  val = readBuffer[idx++];
                  if (val == 0) {
                     SPI.setClockDivider(SPI_CLOCK_DIV2);
                  } else if (val == 1) {
                     SPI.setClockDivider(SPI_CLOCK_DIV4);
                  } else if (val == 2) {
                     SPI.setClockDivider(SPI_CLOCK_DIV8);
                  } else if (val == 3) {
                     SPI.setClockDivider(SPI_CLOCK_DIV16);
                  } else if (val == 4) {
                     SPI.setClockDivider(SPI_CLOCK_DIV32);
                  } else if (val == 5) {
                     SPI.setClockDivider(SPI_CLOCK_DIV64);
                  } else if (val == 6) {
                     SPI.setClockDivider(SPI_CLOCK_DIV128);
                  } else if (val == 7) {
                     SPI.setClockDivider(SPI_CLOCK_DIV256);
                  }
                  break;

               case msg_spiSetDataMode:  // SPI.setDataMode
                  val = readBuffer[idx++];
                  if (val == 0) {
                     SPI.setDataMode(SPI_MODE0);
                  } else if (val == 1) {
                     SPI.setDataMode(SPI_MODE1);
                  } else if (val == 2) {
                     SPI.setDataMode(SPI_MODE2);
                  } else if (val == 3) {
                     SPI.setDataMode(SPI_MODE3);
                  }
                  break;

               case msg_spiTransfer:  // SPI.transfer
                  val = readBuffer[idx++];
                  val = SPI.transfer(val);
                  server.write(0x24);
                  server.write(val);
                  break;

               // Wire API
               case msg_wireBegin:  // Wire.begin
                  address = readBuffer[idx++];
                  if (address == 0) {
                     Wire.begin();
                  } else {
                     Wire.begin(address);
                  }
                  break;
               case msg_wireRequestFrom:  // Wire.requestFrom
                  address = readBuffer[idx++];
                  val = readBuffer[idx++];
                  stop = readBuffer[idx++];
                  Wire.requestFrom(address, val, stop);
                  break;
               case msg_wireBeginTransmission:  // Wire.beginTransmission
                  address = readBuffer[idx++];
                  Wire.beginTransmission(address);
                  break;
               case msg_wireEndTransmission:  // Wire.endTransmission
                  stop = readBuffer[idx++];
                  val = Wire.endTransmission(stop);
                  server.write(0x33);    // could be (action)
                  server.write(val);
                  break;
               case msg_wireWrite:  // Wire.write
                  len = readBuffer[idx++];
                  // uint8_t wireData[len];

                  if (idx + len < length)
                  {
                     // for (i = 0; i< len; i++) {
                        // wireData[i] = readBuffer[idx++];
                     // }
                     // val = Wire.write(wireData, len);

                     // note: byte and uint8_t are both typecast from unsigned char.
                     val = Wire.write((uint8_t *) (readBuffer+idx), len);
                     idx += len;
                     server.write(0x34);    // could be (action)
                     server.write(val);
                  }
                  else
                  {
                     // fix up an incomplete message, putting it at the front
                     //    of the buffer:
                     // the first byte has to be the action value, then the len,
                     //    and then remaining bytes get copied.
                     // then bail.
                     readBuffer[0] = action;
                     readBuffer[1] = len;
                     memcpy (readBuffer+2, readBuffer+idx, length-idx);
                     idx = length - idx + 2;
                     return;
                  }
                  break;
               case msg_wireAvailable:  // Wire.available
                  val = Wire.available();
                  server.write(0x35);    // could be (action)
                  server.write(val);
                  break;
               case msg_wireRead:  // Wire.read
                  val = Wire.read();
                  server.write(0x36);    // could be (action)
                  server.write(val);
                  break;

               case msg_servoAttach:
                  pin = readBuffer[idx++];
                  servos[pin].attach(pin);
                  break;
               case msg_servoWrite:
                  pin = readBuffer[idx++];
                  val = readBuffer[idx++];
                  servos[pin].write(val);
                  break;
               case msg_servoWriteMicroseconds:
                  pin = readBuffer[idx++];
                  val = readBuffer[idx++];
                  servos[pin].writeMicroseconds(val);
                  break;
               case msg_servoRead:
                  pin = readBuffer[idx++];
                  val = servos[pin].read();
                  server.write(0x43);    // could be (action)
                  server.write(pin);
                  server.write(val);
                  break;
               case msg_servoAttached:
                  pin = readBuffer[idx++];
                  val = servos[pin].attached();
                  server.write(0x44);    // could be (action)
                  server.write(pin);
                  server.write(val);
                  break;
               case msg_servoDetach:
                  pin = readBuffer[idx++];
                  servos[pin].detach();
                  break;

               default: // noop
                  break;

               } // <-- This is the end of the switch
            } // <-- This is the end of if (idx+msgMinLength[] < length)
            else
            {
               // fix up an incomplete message, putting it at the front of
               //    the buffer:
               // the first byte has to be the action value, then the
               //    remaining bytes get copied.
               // then bail.
               readBuffer[0] = action;
               memcpy (readBuffer+1, readBuffer+idx, length - idx);
               idx = length - idx + 1;
               return;
            }
         } // <-- This is the end of the valid action check
         // this is a serious problem, if action isn't valid.
         else
         {
            // action is bad.
            // move on to the next byte.
            idx++;
         }

      } // <-- This is the end of the while

      if (idx < length)
      {
         // fix up an incomplete message, putting it at the front of
         //    the buffer:
         // the first byte has to be the action value, then the
         //    remaining bytes get copied.
         readBuffer[0] = action;
         memcpy (readBuffer+1, readBuffer+idx, length - idx);
         idx = length - idx + 1;
      }

    } // <-- This is the end of the length check
  } else {
    // if no client is yet connected, check for a new connection
    client = server.available();
  }
}
<commit_msg>Reverting back.<commit_after>/**
  ******************************************************************************
  * @file    voodoospark.cpp
  * @author  Chris Williams
  * @version V2.0.0
  * @date    07-May-2014
  * @brief   Exposes the firmware level API through a TCP Connection intiated
  *          to the spark device
  ******************************************************************************
  Copyright (c) 2014 Chris Williams  All rights reserved.

  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.
  ******************************************************************************
  */

static const bool DEBUG = 0;

static const int PORT = 48879; // 0xbeef

// TCPClient client;
TCPServer server = TCPServer(PORT);
TCPClient client;
byte readBuffer[512];
byte reading[20];
byte previous[20];
Servo servos[20];

long SerialSpeed[] = { 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200 };

void reset() {
  for (int i = 0; i < 20; i++) {
    reading[i] = 0;
    previous[i] = 0;
  }
}

void send(int action, int pin, int value) {
  if (previous[pin] != value) {
    server.write(action);
    server.write(pin);
    server.write(value);
  }
  previous[pin] = value;
}

void report() {
  for (int i = 0; i < 20; i++) {
    if (reading[i]) {
      int dr = (reading[i] & 1);
      int ar = (reading[i] & 2);

      if (i < 10 && dr) {
        send(0x03, i, digitalRead(i));
      } else {
        if (dr) {
          send(0x03, i, digitalRead(i));
        } else {
          if (ar) {
            send(0x04, i, analogRead(i));
          }
        }
      }
    }
  }
}

char myIpString[32];

void setup() {
  server.begin();
  netapp_ipconfig(&ip_config);
  if (DEBUG) {
    Serial.begin(115200);
  }
  IPAddress myIp = Network.localIP();
  sprintf(myIpString, "%d.%d.%d.%d:%d", myIp[0], myIp[1], myIp[2], myIp[3], PORT);
  Spark.variable("endpoint", myIpString, STRING);

}

bool hasRead = false;

void loop() {
  if (client.connected()) {
    // report();
    int length = client.available();
    if (length) {
      int idx = 0;
      client.read(readBuffer, length);
    //   // parse and execute commands

      int action = readBuffer[idx++];
      if (DEBUG) {
        Serial.println("Action received: " + ('0' + action));
      }

      int pin, mode, val, type, speed, address, stop, len, i;
      switch (action) {
        case 0x00:  // pinMode
          pin = readBuffer[idx++];
          mode = readBuffer[idx++];
          // mode is modeled after Standard Firmata
          if (mode == 0x00) {
            pinMode(pin, INPUT);
          } else if (mode == 0x02) {
            pinMode(pin, INPUT_PULLUP);
          } else if (mode == 0x03) {
            pinMode(pin, INPUT_PULLDOWN);
          } else if (mode == 0x01) {
            pinMode(pin, OUTPUT);
          }
          break;
        case 0x01:  // digitalWrite
          pin = readBuffer[idx++];
          val = readBuffer[idx++];
          digitalWrite(pin, val);
          break;
        case 0x02:  // analogWrite
          pin = readBuffer[idx++];
          val = readBuffer[idx++];
          analogWrite(pin, val);
          break;
        case 0x03:  // digitalRead
          pin = readBuffer[idx++];
          val = digitalRead(pin);
          server.write(0x03);
          server.write(pin);
          server.write(val);
          break;
        case 0x04:  // analogRead
          pin = readBuffer[idx++];
          val = analogRead(pin);
          server.write(0x04);
          server.write(pin);
          server.write(val);
          break;
        case 0x05: // set always send bit
          pin = readBuffer[idx++];
          val = readBuffer[idx++];
          reading[pin] = val;
          break;

        // Serial API
        case 0x10:  // serial.begin
           type = readBuffer[idx++];
           speed = readBuffer[idx++];
          if (type == 0) {
            Serial.begin(SerialSpeed[speed]);
          } else {
            Serial1.begin(SerialSpeed[speed]);
          }
          break;
        case 0x11:  // serial.end
          type = readBuffer[idx++];
          if (type == 0) {
            Serial.end();
          } else {
            Serial1.end();
          }
          break;
        case 0x12:  // serial.peek
          type = readBuffer[idx++];
          if (type == 0) {
            val = Serial.peek();
          } else {
            val = Serial1.peek();
          }
          server.write(0x07);
          server.write(type);
          server.write(val);
          break;
        case 0x13:  // serial.available()
          type = readBuffer[idx++];
          if (type == 0) {
            val = Serial.available();
          } else {
            val = Serial1.available();
          }
          server.write(0x07);
          server.write(type);
          server.write(val);
          break;
        case 0x14:  // serial.write
          type = readBuffer[idx++];
          len = readBuffer[idx++];
          for (i = 0; i < len; i++) {
            if (type ==0) {
              Serial.write(readBuffer[idx++]);
            } else {
              Serial1.write(readBuffer[idx++]);
            }
          }
          break;
        case 0x15: // serial.read
          type = readBuffer[idx++];
          if (type == 0) {
            val = Serial.read();
          } else {
            val = Serial1.read();
          }
          server.write(0x16);
          server.write(type);
          server.write(val);
          break;
        case 0x16: // serial.flush
          type = readBuffer[idx++];
          if (type == 0) {
            Serial.flush();
          } else {
            Serial1.flush();
          }
          break;

        // SPI API
        case 0x20:  // SPI.begin
          SPI.begin();
          break;
        case 0x21:  // SPI.end
          SPI.end();
          break;
        case 0x22:  // SPI.setBitOrder
          type = readBuffer[idx++];
          SPI.setBitOrder((type ? MSBFIRST : LSBFIRST));
          break;
        case 0x23:  // SPI.setClockDivider
          val = readBuffer[idx++];
          if (val == 0) {
            SPI.setClockDivider(SPI_CLOCK_DIV2);
          } else if (val == 1) {
            SPI.setClockDivider(SPI_CLOCK_DIV4);
          } else if (val == 2) {
            SPI.setClockDivider(SPI_CLOCK_DIV8);
          } else if (val == 3) {
            SPI.setClockDivider(SPI_CLOCK_DIV16);
          } else if (val == 4) {
            SPI.setClockDivider(SPI_CLOCK_DIV32);
          } else if (val == 5) {
            SPI.setClockDivider(SPI_CLOCK_DIV64);
          } else if (val == 6) {
            SPI.setClockDivider(SPI_CLOCK_DIV128);
          } else if (val == 7) {
            SPI.setClockDivider(SPI_CLOCK_DIV256);
          }
          break;

        case 0x24:  // SPI.setDataMode
          val = readBuffer[idx++];
          if (val == 0) {
            SPI.setDataMode(SPI_MODE0);
          } else if (val == 1) {
            SPI.setDataMode(SPI_MODE1);
          } else if (val == 2) {
            SPI.setDataMode(SPI_MODE2);
          } else if (val == 3) {
            SPI.setDataMode(SPI_MODE3);
          }
          break;

        case 0x25:  // SPI.transfer
          val = readBuffer[idx++];
          val = SPI.transfer(val);
          server.write(0x24);
          server.write(val);
          break;

        // Wire API
        case 0x30:  // Wire.begin
          address = readBuffer[idx++];
          if (address == 0) {
            Wire.begin();
          } else {
            Wire.begin(address);
          }
          break;
        case 0x31:  // Wire.requestFrom
          address = readBuffer[idx++];
          val = readBuffer[idx++];
          stop = readBuffer[idx++];
          Wire.requestFrom(address, val, stop);
          break;
        case 0x32:  // Wire.beginTransmission
          address = readBuffer[idx++];
          Wire.beginTransmission(address);
          break;
        case 0x33:  // Wire.endTransmission
          stop = readBuffer[idx++];
          val = Wire.endTransmission(stop);
          server.write(0x33);
          server.write(val);
          break;
        case 0x34:  // Wire.write
          len = readBuffer[idx++];
          uint8_t wireData[len];
          for (i = 0; i< len; i++) {
            wireData[i] = readBuffer[idx++];
          }
          val = Wire.write(wireData, len);
          server.write(0x34);
          server.write(val);
          break;
        case 0x35:  // Wire.available
          val = Wire.available();
          server.write(0x35);
          server.write(val);
          break;
        case 0x36:  // Wire.read
          val = Wire.read();
          server.write(0x36);
          server.write(val);
          break;

        case 0x40:
          pin = readBuffer[idx++];
          servos[pin].attach(pin);
          break;
        case 0x41:
          pin = readBuffer[idx++];
          val = readBuffer[idx++];
          servos[pin].write(val);
          break;
        case 0x42:
          pin = readBuffer[idx++];
          val = readBuffer[idx++];
          servos[pin].writeMicroseconds(val);
          break;
        case 0x43:
          pin = readBuffer[idx++];
          val = servos[pin].read();
          server.write(0x43);
          server.write(pin);
          server.write(val);
          break;
        case 0x44:
          pin = readBuffer[idx++];
          val = servos[pin].attached();
          server.write(0x44);
          server.write(pin);
          server.write(val);
          break;
        case 0x45:
          pin = readBuffer[idx++];
          servos[pin].detach();
          break;

        default: // noop
          break;

      } // <-- This is the end of the switch
    } // <-- This is the end of the length check
  } else {
    // if no client is yet connected, check for a new connection
    client = server.available();
  }
}<|endoftext|>


<commit_before>#include <iostream>

#include "CodeGen_Posix.h"
#include "CodeGen_Internal.h"
#include "LLVM_Headers.h"
#include "IR.h"
#include "IROperator.h"
#include "Debug.h"
#include "IRPrinter.h"
#include "Simplify.h"

namespace Halide {
namespace Internal {

using std::vector;
using std::string;
using std::map;
using std::pair;
using std::make_pair;

using namespace llvm;

CodeGen_Posix::CodeGen_Posix(Target t) :
  CodeGen_LLVM(t) {
}

Value *CodeGen_Posix::codegen_allocation_size(const std::string &name, Type type, const std::vector<Expr> &extents) {
    // Compute size from list of extents checking for 32-bit signed overflow.
    // Math is done using 64-bit intergers as overflow checked 32-bit mutliply
    // does not work with NaCl at the moment.

    Expr no_overflow = const_true(1);
    Expr total_size = Expr((int64_t)(type.lanes() * type.bytes()));
    Expr max_size = cast<int64_t>(0x7fffffff);
    for (size_t i = 0; i < extents.size(); i++) {
        total_size *= extents[i];
        no_overflow = no_overflow && (total_size <= max_size);
    }

    // For constant-sized allocations this check should simplify away.
    no_overflow = simplify(no_overflow);
    if (!is_one(no_overflow)) {
        create_assertion(codegen(no_overflow),
                         Call::make(Int(32), "halide_error_buffer_allocation_too_large",
                                    {name, total_size, max_size}, Call::Extern));
    }

    total_size = simplify(cast<int32_t>(total_size));
    return codegen(total_size);
}

CodeGen_Posix::Allocation CodeGen_Posix::create_allocation(const std::string &name, Type type,
                                                           const std::vector<Expr> &extents, Expr condition,
                                                           Expr new_expr, std::string free_function) {
    Value *llvm_size = nullptr;
    int64_t stack_bytes = 0;
    int32_t constant_bytes = Allocate::constant_allocation_size(extents, name);
    if (constant_bytes > 0) {
        constant_bytes *= type.bytes();
        stack_bytes = constant_bytes;

        if (stack_bytes > ((int64_t(1) << 31) - 1)) {
            user_error << "Total size for allocation " << name << " is constant but exceeds 2^31 - 1.";
        } else if (!can_allocation_fit_on_stack(stack_bytes)) {
            stack_bytes = 0;
            llvm_size = codegen(Expr(constant_bytes));
        }
    } else {
        llvm_size = codegen_allocation_size(name, type, extents);
    }

    // Only allocate memory if the condition is true, otherwise 0.
    if (llvm_size != nullptr) {
        // We potentially load one scalar value past the end of the
        // buffer, so pad the allocation with an extra instance of the
        // scalar type. If the allocation is on the stack, we can just
        // read one past the top of the stack, so we only need this
        // for heap allocations.
        llvm_size = builder->CreateAdd(llvm_size,
                                       ConstantInt::get(llvm_size->getType(), type.bytes()));

        Value *llvm_condition = codegen(condition);
        llvm_size = builder->CreateSelect(llvm_condition,
                                          llvm_size,
                                          ConstantInt::get(llvm_size->getType(), 0));
    }

    Allocation allocation;
    allocation.constant_bytes = constant_bytes;
    allocation.stack_bytes = new_expr.defined() ? 0 : stack_bytes;
    allocation.type = type;
    allocation.ptr = nullptr;
    allocation.destructor = nullptr;
    allocation.destructor_function = nullptr;

    if (!new_expr.defined() && stack_bytes != 0) {
        // Try to find a free stack allocation we can use.
        vector<Allocation>::iterator free = free_stack_allocs.end();
        for (free = free_stack_allocs.begin(); free != free_stack_allocs.end(); ++free) {
            AllocaInst *alloca_inst = dyn_cast<AllocaInst>(free->ptr);
            llvm::Function *allocated_in = alloca_inst ? alloca_inst->getParent()->getParent() : nullptr;
            llvm::Function *current_func = builder->GetInsertBlock()->getParent();

            if (allocated_in == current_func &&
                free->type == type &&
                free->stack_bytes >= stack_bytes) {
                break;
            }
        }
        if (free != free_stack_allocs.end()) {
            debug(4) << "Reusing freed stack allocation of " << free->stack_bytes
                     << " bytes for allocation " << name
                     << " of " << stack_bytes << " bytes.\n";
            // Use a free alloc we found.
            allocation.ptr = free->ptr;
            allocation.stack_bytes = free->stack_bytes;

            // This allocation isn't free anymore.
            free_stack_allocs.erase(free);
        } else {
            debug(4) << "Allocating " << stack_bytes << " bytes on the stack for " << name << "\n";
            // We used to do the alloca locally and save and restore the
            // stack pointer, but this makes llvm generate streams of
            // spill/reloads.
            int64_t stack_size = (stack_bytes + type.bytes() - 1) / type.bytes();
            // Handles are stored as uint64s
            llvm::Type *t = llvm_type_of(type.is_handle() ? UInt(64, type.lanes()) : type);
            allocation.ptr = create_alloca_at_entry(t, stack_size, false, name);
            allocation.stack_bytes = stack_bytes;
        }
    } else {
        if (new_expr.defined()) {
            allocation.ptr = codegen(new_expr);
        } else {
            // call malloc
            llvm::Function *malloc_fn = module->getFunction("halide_malloc");
            internal_assert(malloc_fn) << "Could not find halide_malloc in module\n";
            malloc_fn->setDoesNotAlias(0);

            llvm::Function::arg_iterator arg_iter = malloc_fn->arg_begin();
            ++arg_iter;  // skip the user context *
            llvm_size = builder->CreateIntCast(llvm_size, arg_iter->getType(), false);

            debug(4) << "Creating call to halide_malloc for allocation " << name
                     << " of size " << type.bytes();
            for (Expr e : extents) {
                debug(4) << " x " << e;
            }
            debug(4) << "\n";
            Value *args[2] = { get_user_context(), llvm_size };

            CallInst *call = builder->CreateCall(malloc_fn, args);
            allocation.ptr = call;
        }

        // Assert that the allocation worked.
        Value *check = builder->CreateIsNotNull(allocation.ptr);
        if (!new_expr.defined()) { // Zero sized allocation if allowed for custom new...
            Value *zero_size = builder->CreateIsNull(llvm_size);
            check = builder->CreateOr(check, zero_size);
        }

        create_assertion(check, Call::make(Int(32), "halide_error_out_of_memory",
                                           std::vector<Expr>(), Call::Extern));

        // Register a destructor for this allocation.
        if (free_function.empty()) {
            free_function = "halide_free";
        }
        llvm::Function *free_fn = module->getFunction(free_function);
        internal_assert(free_fn) << "Could not find " << free_function << " in module.\n";
        allocation.destructor = register_destructor(free_fn, allocation.ptr, OnError);
        allocation.destructor_function = free_fn;
    }

    // Push the allocation base pointer onto the symbol table
    debug(3) << "Pushing allocation called " << name << ".host onto the symbol table\n";

    allocations.push(name, allocation);

    return allocation;
}

void CodeGen_Posix::visit(const Allocate *alloc) {
    if (sym_exists(alloc->name + ".host")) {
        user_error << "Can't have two different buffers with the same name: "
                   << alloc->name << "\n";
    }

    Allocation allocation = create_allocation(alloc->name, alloc->type,
                                              alloc->extents, alloc->condition,
                                              alloc->new_expr, alloc->free_function);
    sym_push(alloc->name + ".host", allocation.ptr);

    codegen(alloc->body);

    // Should have been freed
    internal_assert(!sym_exists(alloc->name + ".host"));
    internal_assert(!allocations.contains(alloc->name));
}

void CodeGen_Posix::visit(const Free *stmt) {
    Allocation alloc = allocations.get(stmt->name);

    if (alloc.stack_bytes) {
        // Remember this allocation so it can be re-used by a later allocation.
        free_stack_allocs.push_back(alloc);
    } else {
        internal_assert(alloc.destructor);
        trigger_destructor(alloc.destructor_function, alloc.destructor);
    }

    allocations.pop(stmt->name);
    sym_pop(stmt->name + ".host");
}

}}
<commit_msg>It's OK for new_expr to codegen to NULL...<commit_after>#include <iostream>

#include "CodeGen_Posix.h"
#include "CodeGen_Internal.h"
#include "LLVM_Headers.h"
#include "IR.h"
#include "IROperator.h"
#include "Debug.h"
#include "IRPrinter.h"
#include "Simplify.h"

namespace Halide {
namespace Internal {

using std::vector;
using std::string;
using std::map;
using std::pair;
using std::make_pair;

using namespace llvm;

CodeGen_Posix::CodeGen_Posix(Target t) :
  CodeGen_LLVM(t) {
}

Value *CodeGen_Posix::codegen_allocation_size(const std::string &name, Type type, const std::vector<Expr> &extents) {
    // Compute size from list of extents checking for 32-bit signed overflow.
    // Math is done using 64-bit intergers as overflow checked 32-bit mutliply
    // does not work with NaCl at the moment.

    Expr no_overflow = const_true(1);
    Expr total_size = Expr((int64_t)(type.lanes() * type.bytes()));
    Expr max_size = cast<int64_t>(0x7fffffff);
    for (size_t i = 0; i < extents.size(); i++) {
        total_size *= extents[i];
        no_overflow = no_overflow && (total_size <= max_size);
    }

    // For constant-sized allocations this check should simplify away.
    no_overflow = simplify(no_overflow);
    if (!is_one(no_overflow)) {
        create_assertion(codegen(no_overflow),
                         Call::make(Int(32), "halide_error_buffer_allocation_too_large",
                                    {name, total_size, max_size}, Call::Extern));
    }

    total_size = simplify(cast<int32_t>(total_size));
    return codegen(total_size);
}

CodeGen_Posix::Allocation CodeGen_Posix::create_allocation(const std::string &name, Type type,
                                                           const std::vector<Expr> &extents, Expr condition,
                                                           Expr new_expr, std::string free_function) {
    Value *llvm_size = nullptr;
    int64_t stack_bytes = 0;
    int32_t constant_bytes = Allocate::constant_allocation_size(extents, name);
    if (constant_bytes > 0) {
        constant_bytes *= type.bytes();
        stack_bytes = constant_bytes;

        if (stack_bytes > ((int64_t(1) << 31) - 1)) {
            user_error << "Total size for allocation " << name << " is constant but exceeds 2^31 - 1.";
        } else if (!can_allocation_fit_on_stack(stack_bytes)) {
            stack_bytes = 0;
            llvm_size = codegen(Expr(constant_bytes));
        }
    } else {
        llvm_size = codegen_allocation_size(name, type, extents);
    }

    // Only allocate memory if the condition is true, otherwise 0.
    Value *llvm_condition = codegen(condition);
    if (llvm_size != nullptr) {
        // We potentially load one scalar value past the end of the
        // buffer, so pad the allocation with an extra instance of the
        // scalar type. If the allocation is on the stack, we can just
        // read one past the top of the stack, so we only need this
        // for heap allocations.
        llvm_size = builder->CreateAdd(llvm_size,
                                       ConstantInt::get(llvm_size->getType(), type.bytes()));

        llvm_size = builder->CreateSelect(llvm_condition,
                                          llvm_size,
                                          ConstantInt::get(llvm_size->getType(), 0));
    }

    Allocation allocation;
    allocation.constant_bytes = constant_bytes;
    allocation.stack_bytes = new_expr.defined() ? 0 : stack_bytes;
    allocation.type = type;
    allocation.ptr = nullptr;
    allocation.destructor = nullptr;
    allocation.destructor_function = nullptr;

    if (!new_expr.defined() && stack_bytes != 0) {
        // Try to find a free stack allocation we can use.
        vector<Allocation>::iterator free = free_stack_allocs.end();
        for (free = free_stack_allocs.begin(); free != free_stack_allocs.end(); ++free) {
            AllocaInst *alloca_inst = dyn_cast<AllocaInst>(free->ptr);
            llvm::Function *allocated_in = alloca_inst ? alloca_inst->getParent()->getParent() : nullptr;
            llvm::Function *current_func = builder->GetInsertBlock()->getParent();

            if (allocated_in == current_func &&
                free->type == type &&
                free->stack_bytes >= stack_bytes) {
                break;
            }
        }
        if (free != free_stack_allocs.end()) {
            debug(4) << "Reusing freed stack allocation of " << free->stack_bytes
                     << " bytes for allocation " << name
                     << " of " << stack_bytes << " bytes.\n";
            // Use a free alloc we found.
            allocation.ptr = free->ptr;
            allocation.stack_bytes = free->stack_bytes;

            // This allocation isn't free anymore.
            free_stack_allocs.erase(free);
        } else {
            debug(4) << "Allocating " << stack_bytes << " bytes on the stack for " << name << "\n";
            // We used to do the alloca locally and save and restore the
            // stack pointer, but this makes llvm generate streams of
            // spill/reloads.
            int64_t stack_size = (stack_bytes + type.bytes() - 1) / type.bytes();
            // Handles are stored as uint64s
            llvm::Type *t = llvm_type_of(type.is_handle() ? UInt(64, type.lanes()) : type);
            allocation.ptr = create_alloca_at_entry(t, stack_size, false, name);
            allocation.stack_bytes = stack_bytes;
        }
    } else {
        if (new_expr.defined()) {
            allocation.ptr = codegen(new_expr);
        } else {
            // call malloc
            llvm::Function *malloc_fn = module->getFunction("halide_malloc");
            internal_assert(malloc_fn) << "Could not find halide_malloc in module\n";
            malloc_fn->setDoesNotAlias(0);

            llvm::Function::arg_iterator arg_iter = malloc_fn->arg_begin();
            ++arg_iter;  // skip the user context *
            llvm_size = builder->CreateIntCast(llvm_size, arg_iter->getType(), false);

            debug(4) << "Creating call to halide_malloc for allocation " << name
                     << " of size " << type.bytes();
            for (Expr e : extents) {
                debug(4) << " x " << e;
            }
            debug(4) << "\n";
            Value *args[2] = { get_user_context(), llvm_size };

            CallInst *call = builder->CreateCall(malloc_fn, args);
            allocation.ptr = call;
        }

        // Assert that the allocation worked.
        Value *check = builder->CreateIsNotNull(allocation.ptr);
        if (llvm_size) {
            Value *zero_size = builder->CreateIsNull(llvm_size);
            check = builder->CreateOr(check, zero_size);
        }
        if (!is_one(condition)) {
            // If the condition is false, it's OK for the new_expr to be null.
            Value *condition_is_false = builder->CreateIsNull(llvm_condition);
            check = builder->CreateOr(check, condition_is_false);
        }

        create_assertion(check, Call::make(Int(32), "halide_error_out_of_memory",
                                           std::vector<Expr>(), Call::Extern));

        // Register a destructor for this allocation.
        if (free_function.empty()) {
            free_function = "halide_free";
        }
        llvm::Function *free_fn = module->getFunction(free_function);
        internal_assert(free_fn) << "Could not find " << free_function << " in module.\n";
        allocation.destructor = register_destructor(free_fn, allocation.ptr, OnError);
        allocation.destructor_function = free_fn;
    }

    // Push the allocation base pointer onto the symbol table
    debug(3) << "Pushing allocation called " << name << ".host onto the symbol table\n";

    allocations.push(name, allocation);

    return allocation;
}

void CodeGen_Posix::visit(const Allocate *alloc) {
    if (sym_exists(alloc->name + ".host")) {
        user_error << "Can't have two different buffers with the same name: "
                   << alloc->name << "\n";
    }

    Allocation allocation = create_allocation(alloc->name, alloc->type,
                                              alloc->extents, alloc->condition,
                                              alloc->new_expr, alloc->free_function);
    sym_push(alloc->name + ".host", allocation.ptr);

    codegen(alloc->body);

    // Should have been freed
    internal_assert(!sym_exists(alloc->name + ".host"));
    internal_assert(!allocations.contains(alloc->name));
}

void CodeGen_Posix::visit(const Free *stmt) {
    Allocation alloc = allocations.get(stmt->name);

    if (alloc.stack_bytes) {
        // Remember this allocation so it can be re-used by a later allocation.
        free_stack_allocs.push_back(alloc);
    } else {
        internal_assert(alloc.destructor);
        trigger_destructor(alloc.destructor_function, alloc.destructor);
    }

    allocations.pop(stmt->name);
    sym_pop(stmt->name + ".host");
}

}}
<|endoftext|>