<commit_before>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Libmemcached library
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2006-2009 Brian Aker 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.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  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
 *  OWNER 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 <libmemcached/common.h>

inline static memcached_return_t _string_check(memcached_string_st *string, size_t need)
{
  if (need && need > (size_t)(string->current_size - (size_t)(string->end - string->string)))
  {
    size_t current_offset= (size_t) (string->end - string->string);

    /* This is the block multiplier. To keep it larger and surive division errors we must round it up */
    size_t adjust= (need - (size_t)(string->current_size - (size_t)(string->end - string->string))) / MEMCACHED_BLOCK_SIZE;
    adjust++;

    size_t new_size= sizeof(char) * (size_t)((adjust * MEMCACHED_BLOCK_SIZE) + string->current_size);
    /* Test for overflow */
    if (new_size < need)
    {
      char error_message[1024];
      int error_message_length= snprintf(error_message, sizeof(error_message),"Needed %ld, got %ld", (long)need, (long)new_size);
      return memcached_set_error(*string->root, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, error_message, error_message_length);
    }

    char *new_value= libmemcached_xrealloc(string->root, string->string, new_size, char);

    if (new_value == NULL)
    {
      return memcached_set_error(*string->root, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
    }

    string->string= new_value;
    string->end= string->string + current_offset;

    string->current_size+= (MEMCACHED_BLOCK_SIZE * adjust);
  }

  return MEMCACHED_SUCCESS;
}

static inline void _init_string(memcached_string_st *self)
{
  self->current_size= 0;
  self->end= self->string= NULL;
}

memcached_string_st *memcached_string_create(Memcached *memc, memcached_string_st *self, size_t initial_size)
{
  WATCHPOINT_ASSERT(memc);

  /* Saving malloc calls :) */
  if (self)
  {
    WATCHPOINT_ASSERT(self->options.is_initialized == false);

    memcached_set_allocated(self, false);
  }
  else
  {
    self= libmemcached_xmalloc(memc, memcached_string_st);

    if (self == NULL)
    {
      return NULL;
    }

    memcached_set_allocated(self, true);
  }
  self->root= memc;

  _init_string(self);

  if (memcached_failed(_string_check(self, initial_size)))
  {
    if (memcached_is_allocated(self))
    {
      libmemcached_free(memc, self);
    }

    return NULL;
  }

  memcached_set_initialized(self, true);

  WATCHPOINT_ASSERT(self->string == self->end);

  return self;
}

static memcached_return_t memcached_string_append_null(memcached_string_st& string)
{
  if (memcached_failed(_string_check(&string, 1)))
  {
    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
  }

  *string.end= 0;

  return MEMCACHED_SUCCESS;
}

static memcached_return_t memcached_string_append_null(memcached_string_st *string)
{
  if (memcached_failed(_string_check(string, 1)))
  {
    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
  }

  *string->end= 0;

  return MEMCACHED_SUCCESS;
}

memcached_return_t memcached_string_append_character(memcached_string_st *string,
                                                     char character)
{
  if (memcached_failed(_string_check(string, 1)))
  {
    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
  }

  *string->end= character;
  string->end++;

  return MEMCACHED_SUCCESS;
}

memcached_return_t memcached_string_append(memcached_string_st *string,
                                           const char *value, size_t length)
{
  if (memcached_failed(_string_check(string, length)))
  {
    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
  }

  WATCHPOINT_ASSERT(length <= string->current_size);
  WATCHPOINT_ASSERT(string->string);
  WATCHPOINT_ASSERT(string->end >= string->string);

  memcpy(string->end, value, length);
  string->end+= length;

  return MEMCACHED_SUCCESS;
}

char *memcached_string_c_copy(memcached_string_st *string)
{
  if (memcached_string_length(string) == 0)
  {
    return NULL;
  }

  char *c_ptr= static_cast<char *>(libmemcached_malloc(string->root, (memcached_string_length(string)+1) * sizeof(char)));

  if (c_ptr == NULL)
  {
    return NULL;
  }

  memcpy(c_ptr, memcached_string_value(string), memcached_string_length(string));
  c_ptr[memcached_string_length(string)]= 0;

  return c_ptr;
}

bool memcached_string_set(memcached_string_st& string, const char* value, size_t length)
{
  memcached_string_reset(&string);
  if (memcached_success(memcached_string_append(&string, value, length)))
  {
    memcached_string_append_null(string);
    return true;
  }

  return false;
}

void memcached_string_reset(memcached_string_st *string)
{
  string->end= string->string;
}

void memcached_string_free(memcached_string_st& ptr)
{
  memcached_string_free(&ptr);
}

void memcached_string_free(memcached_string_st *ptr)
{
  if (ptr == NULL)
  {
    return;
  }

  if (ptr->string)
  {
    libmemcached_free(ptr->root, ptr->string);
  }

  if (memcached_is_allocated(ptr))
  {
    libmemcached_free(ptr->root, ptr);
  }
  else
  {
    ptr->options.is_initialized= false;
  }
}

memcached_return_t memcached_string_check(memcached_string_st *string, size_t need)
{
  return _string_check(string, need);
}

bool memcached_string_resize(memcached_string_st& string, const size_t need)
{
  return memcached_success(_string_check(&string, need));
}

size_t memcached_string_length(const memcached_string_st *self)
{
  return size_t(self->end -self->string);
}

size_t memcached_string_length(const memcached_string_st& self)
{
  return size_t(self.end -self.string);
}

size_t memcached_string_size(const memcached_string_st *self)
{
  return self->current_size;
}

const char *memcached_string_value(const memcached_string_st *self)
{
  return self->string;
}

const char *memcached_string_value(const memcached_string_st& self)
{
  return self.string;
}

char *memcached_string_take_value(memcached_string_st *self)
{
  char* value= NULL;

  if (memcached_string_length(self))
  {
    assert_msg(self, "Invalid memcached_string_st");
    // If we fail at adding the null, we copy and move on
    if (memcached_success(memcached_string_append_null(self)))
    {
      return memcached_string_c_copy(self);
    }

    value= self->string;

    _init_string(self);
  }

  return value;
}

char *memcached_string_value_mutable(const memcached_string_st *self)
{
  return self->string;
}

char *memcached_string_c_str(memcached_string_st& self)
{
  return self.string;
}

void memcached_string_set_length(memcached_string_st *self, size_t length)
{
  self->end= self->string +length;
}

void memcached_string_set_length(memcached_string_st& self, const size_t length)
{
  assert(self.current_size >= length);
  size_t set_length= length;
  if (self.current_size > length)
  {
    if (memcached_failed(_string_check(&self, length)))
    {
      set_length= self.current_size;
    }
  }
  self.end= self.string +set_length;
}
<commit_msg>Fix bad if path<commit_after>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Libmemcached library
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2006-2009 Brian Aker 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.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  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
 *  OWNER 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 <libmemcached/common.h>

inline static memcached_return_t _string_check(memcached_string_st *string, size_t need)
{
  if (need && need > (size_t)(string->current_size - (size_t)(string->end - string->string)))
  {
    size_t current_offset= (size_t) (string->end - string->string);

    /* This is the block multiplier. To keep it larger and surive division errors we must round it up */
    size_t adjust= (need - (size_t)(string->current_size - (size_t)(string->end - string->string))) / MEMCACHED_BLOCK_SIZE;
    adjust++;

    size_t new_size= sizeof(char) * (size_t)((adjust * MEMCACHED_BLOCK_SIZE) + string->current_size);
    /* Test for overflow */
    if (new_size < need)
    {
      char error_message[1024];
      int error_message_length= snprintf(error_message, sizeof(error_message),"Needed %ld, got %ld", (long)need, (long)new_size);
      return memcached_set_error(*string->root, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, error_message, error_message_length);
    }

    char *new_value= libmemcached_xrealloc(string->root, string->string, new_size, char);

    if (new_value == NULL)
    {
      return memcached_set_error(*string->root, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
    }

    string->string= new_value;
    string->end= string->string + current_offset;

    string->current_size+= (MEMCACHED_BLOCK_SIZE * adjust);
  }

  return MEMCACHED_SUCCESS;
}

static inline void _init_string(memcached_string_st *self)
{
  self->current_size= 0;
  self->end= self->string= NULL;
}

memcached_string_st *memcached_string_create(Memcached *memc, memcached_string_st *self, size_t initial_size)
{
  WATCHPOINT_ASSERT(memc);

  /* Saving malloc calls :) */
  if (self)
  {
    WATCHPOINT_ASSERT(self->options.is_initialized == false);

    memcached_set_allocated(self, false);
  }
  else
  {
    self= libmemcached_xmalloc(memc, memcached_string_st);

    if (self == NULL)
    {
      return NULL;
    }

    memcached_set_allocated(self, true);
  }
  self->root= memc;

  _init_string(self);

  if (memcached_failed(_string_check(self, initial_size)))
  {
    if (memcached_is_allocated(self))
    {
      libmemcached_free(memc, self);
    }

    return NULL;
  }

  memcached_set_initialized(self, true);

  WATCHPOINT_ASSERT(self->string == self->end);

  return self;
}

static memcached_return_t memcached_string_append_null(memcached_string_st& string)
{
  if (memcached_failed(_string_check(&string, 1)))
  {
    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
  }

  *string.end= 0;

  return MEMCACHED_SUCCESS;
}

static memcached_return_t memcached_string_append_null(memcached_string_st *string)
{
  if (memcached_failed(_string_check(string, 1)))
  {
    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
  }

  *string->end= 0;

  return MEMCACHED_SUCCESS;
}

memcached_return_t memcached_string_append_character(memcached_string_st *string,
                                                     char character)
{
  if (memcached_failed(_string_check(string, 1)))
  {
    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
  }

  *string->end= character;
  string->end++;

  return MEMCACHED_SUCCESS;
}

memcached_return_t memcached_string_append(memcached_string_st *string,
                                           const char *value, size_t length)
{
  if (memcached_failed(_string_check(string, length)))
  {
    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
  }

  WATCHPOINT_ASSERT(length <= string->current_size);
  WATCHPOINT_ASSERT(string->string);
  WATCHPOINT_ASSERT(string->end >= string->string);

  memcpy(string->end, value, length);
  string->end+= length;

  return MEMCACHED_SUCCESS;
}

char *memcached_string_c_copy(memcached_string_st *string)
{
  if (memcached_string_length(string) == 0)
  {
    return NULL;
  }

  char *c_ptr= static_cast<char *>(libmemcached_malloc(string->root, (memcached_string_length(string)+1) * sizeof(char)));

  if (c_ptr == NULL)
  {
    return NULL;
  }

  memcpy(c_ptr, memcached_string_value(string), memcached_string_length(string));
  c_ptr[memcached_string_length(string)]= 0;

  return c_ptr;
}

bool memcached_string_set(memcached_string_st& string, const char* value, size_t length)
{
  memcached_string_reset(&string);
  if (memcached_success(memcached_string_append(&string, value, length)))
  {
    memcached_string_append_null(string);
    return true;
  }

  return false;
}

void memcached_string_reset(memcached_string_st *string)
{
  string->end= string->string;
}

void memcached_string_free(memcached_string_st& ptr)
{
  memcached_string_free(&ptr);
}

void memcached_string_free(memcached_string_st *ptr)
{
  if (ptr == NULL)
  {
    return;
  }

  if (ptr->string)
  {
    libmemcached_free(ptr->root, ptr->string);
  }

  if (memcached_is_allocated(ptr))
  {
    libmemcached_free(ptr->root, ptr);
  }
  else
  {
    ptr->options.is_initialized= false;
  }
}

memcached_return_t memcached_string_check(memcached_string_st *string, size_t need)
{
  return _string_check(string, need);
}

bool memcached_string_resize(memcached_string_st& string, const size_t need)
{
  return memcached_success(_string_check(&string, need));
}

size_t memcached_string_length(const memcached_string_st *self)
{
  return size_t(self->end -self->string);
}

size_t memcached_string_length(const memcached_string_st& self)
{
  return size_t(self.end -self.string);
}

size_t memcached_string_size(const memcached_string_st *self)
{
  return self->current_size;
}

const char *memcached_string_value(const memcached_string_st *self)
{
  return self->string;
}

const char *memcached_string_value(const memcached_string_st& self)
{
  return self.string;
}

char *memcached_string_take_value(memcached_string_st *self)
{
  char* value= NULL;

  assert_msg(self, "Invalid memcached_string_st");
  if (self)
  {
    if (memcached_string_length(self))
    {
      // If we fail at adding the null, we copy and move on
      if (memcached_failed(memcached_string_append_null(self)))
      {
        return NULL;
      }

      value= self->string;
      _init_string(self);
    }
  }

  return value;
}

char *memcached_string_value_mutable(const memcached_string_st *self)
{
  return self->string;
}

char *memcached_string_c_str(memcached_string_st& self)
{
  return self.string;
}

void memcached_string_set_length(memcached_string_st *self, size_t length)
{
  self->end= self->string +length;
}

void memcached_string_set_length(memcached_string_st& self, const size_t length)
{
  assert(self.current_size >= length);
  size_t set_length= length;
  if (self.current_size > length)
  {
    if (memcached_failed(_string_check(&self, length)))
    {
      set_length= self.current_size;
    }
  }
  self.end= self.string +set_length;
}
<|endoftext|>


<commit_before>#include "CppUnitTest.h"
#include <algorithm>
#include <sstream>
#include <cctype>
#include <string>
#include <vector>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace std;

namespace algo
{
    struct token
    {
        enum toktype { root_node, named_node, edge_name, horizontal_edge, ascending_edge_part, descending_edge_part, vertical_edge_part };
        toktype type;
        string name;
    };

    bool operator==(const token& lhs, const token& rhs)
    {
        return lhs.type == rhs.type
            && lhs.name == rhs.name;
    }

    struct ascii_tree
    {
        static vector<token> tokenize(const string& s)
        {
            vector<token> tokens;
            enum { none, open_square_brace, close_square_brace, asterisk, dash, name_char } prev = none;
            size_t marker = 0, marked_length = 0;

            for (size_t i = 0; i < s.size(); ++i)
            {
                auto ch = s[i];

                if (ch == '[')
                {
                    prev = open_square_brace;
                }
                else if (ch == ']')
                {
                    if (prev == asterisk)
                    {
                        tokens.emplace_back(token { token::root_node, "" });
                    }
                    else
                    {
                        tokens.emplace_back(token { token::named_node, s.substr(marker, marked_length) });
                    }

                    prev = close_square_brace;
                }
                else if (ch == '*')
                {
                    prev = asterisk;
                }
                else if (ch == '-')
                {
                    if (prev == name_char)
                    {
                        tokens.emplace_back(token { token::horizontal_edge, s.substr(marker, marked_length) });
                    }

                    prev = dash;
                }
                else if (ch == '/')
                {
                    tokens.emplace_back(token { token::ascending_edge_part, "" });
                }
                else if (ch == '\\')
                {
                    tokens.emplace_back(token { token::descending_edge_part, "" });
                }
                else if (ch == '|')
                {
                    tokens.emplace_back(token { token::vertical_edge_part, "" });
                }
                else if (isalnum(ch) || ch == '_')
                {
                    if (prev != name_char)
                    {
                        marker = i;
                        marked_length = 0;
                    }

                    prev = name_char;
                    ++marked_length;
                }
            }

            if (prev == name_char)
            {
                tokens.emplace_back(token { token::edge_name, s.substr(marker, marked_length) });
            }

            return tokens;
        }
    };
}

namespace Microsoft { namespace VisualStudio { namespace CppUnitTestFramework
{
    template<>
    wstring ToString<algo::token::toktype>(const algo::token::toktype& type)
    {
        switch (type)
        {
        case algo::token::root_node:
            return L"root_node";
        case algo::token::named_node:
            return L"named_node";
        case algo::token::edge_name:
            return L"edge_name";
        case algo::token::horizontal_edge:
            return L"horizontal_edge";
        case algo::token::ascending_edge_part:
            return L"ascending_edge_part";
        case algo::token::descending_edge_part:
            return L"descending_edge_part";
        case algo::token::vertical_edge_part:
            return L"vertical_edge_part";
        default:
            return L"unknown token";
        }
    }
}}}

namespace algo { namespace spec
{
	TEST_CLASS(can_recognize_ascii_tree_tokens)
	{
        void TokensShouldMatch_(std::initializer_list<token> expected, vector<token>& actual)
        {
            auto mismatch_pair = std::mismatch(expected.begin(), expected.end(), actual.begin());

            if (mismatch_pair.first != expected.end() || mismatch_pair.second != actual.end())
            {
                wstring expectedName(mismatch_pair.first->name.begin(), mismatch_pair.first->name.end());
                wstring actualName(mismatch_pair.second->name.begin(), mismatch_pair.second->name.end());

                wstring message = L"Expected: " + ToString(mismatch_pair.first->type) + L" \"" + expectedName + L"\" "
                    + L"Actual: " + ToString(mismatch_pair.second->type) + L" \"" + actualName + L"\"";

                Assert::Fail(message.c_str());
            }
        }

    public:

        TEST_METHOD(should_not_recognize_any_tokens_in_an_empty_string)
        {
            auto tokens = ascii_tree::tokenize("");
            Assert::IsTrue(tokens.empty());
        }

		TEST_METHOD(should_recognize_a_root_node)
		{
            auto tokens = ascii_tree::tokenize("[*]");
            Assert::AreEqual(token::root_node, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_root_node_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" [ * ]");
            Assert::AreEqual(token::root_node, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_named_node)
        {
            const string all_chars = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            auto tokens = ascii_tree::tokenize("[" + all_chars + "]");
            Assert::AreEqual(token::named_node, tokens.front().type);
            Assert::AreEqual(all_chars.c_str(), tokens.front().name.c_str());
        }

        TEST_METHOD(should_recognize_a_named_node_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" [ a ]");
            Assert::AreEqual(token::named_node, tokens.front().type);
            Assert::AreEqual("a", tokens.front().name.c_str());
        }

        TEST_METHOD(should_recognize_an_edge_name)
        {
            auto tokens = ascii_tree::tokenize("a");
            Assert::AreEqual(token::edge_name, tokens.front().type);
            Assert::AreEqual("a", tokens.front().name.c_str());
        }

        TEST_METHOD(should_recognize_an_edge_name_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" a ");
            Assert::AreEqual(token::edge_name, tokens.front().type);
            Assert::AreEqual("a", tokens.front().name.c_str());
        }

        TEST_METHOD(should_recognize_an_ascending_edge_part)
        {
            auto tokens = ascii_tree::tokenize("/");
            Assert::AreEqual(token::ascending_edge_part, tokens.front().type);
        }

        TEST_METHOD(should_recognize_an_ascending_edge_part_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" / ");
            Assert::AreEqual(token::ascending_edge_part, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_descending_edge_part)
        {
            auto tokens = ascii_tree::tokenize("\\");
            Assert::AreEqual(token::descending_edge_part, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_descending_edge_part_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" \\ ");
            Assert::AreEqual(token::descending_edge_part, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_vertical_edge_part)
        {
            auto tokens = ascii_tree::tokenize("|");
            Assert::AreEqual(token::vertical_edge_part, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_vertical_edge_part_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" | ");
            Assert::AreEqual(token::vertical_edge_part, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_horizontal_edge)
        {
            auto tokens = ascii_tree::tokenize("-a-");
            Assert::AreEqual(token::horizontal_edge, tokens.front().type);
            Assert::AreEqual("a", tokens.front().name.c_str());
        }

        TEST_METHOD(should_recognize_a_horizontal_edge_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" - a - ");
            Assert::AreEqual(token::horizontal_edge, tokens.front().type);
            Assert::AreEqual("a", tokens.front().name.c_str());
        }

        TEST_METHOD(should_recognize_a_root_node_next_to_a_named_node)
        {
            auto expected_tokens =
            {
                token { token::root_node, "" },
                token { token::named_node, "a" }
            };

            auto tokens = ascii_tree::tokenize("[*][a]");

            TokensShouldMatch_(expected_tokens, tokens);
        }

        TEST_METHOD(should_recognize_a_root_node_next_to_a_horizontal_edge)
        {
            auto expected_tokens =
            {
                token { token::root_node, "" },
                token { token::horizontal_edge, "a" }
            };

            auto tokens = ascii_tree::tokenize("[*]-a-");

            TokensShouldMatch_(expected_tokens, tokens);
        }

        TEST_METHOD(should_recognize_a_horizontal_edge_next_to_a_named_node)
        {
            auto expected_tokens =
            {
                token { token::horizontal_edge, "a" },
                token { token::named_node, "b" }
            };

            auto tokens = ascii_tree::tokenize("-a-[b]");

            TokensShouldMatch_(expected_tokens, tokens);
        }

    };
}}
<commit_msg>simplify tests<commit_after>#include "CppUnitTest.h"
#include <algorithm>
#include <sstream>
#include <cctype>
#include <string>
#include <vector>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace std;

namespace algo
{
    struct token
    {
        enum toktype { root_node, named_node, edge_name, horizontal_edge, ascending_edge_part, descending_edge_part, vertical_edge_part };
        toktype type;
        string name;
    };

    bool operator==(const token& lhs, const token& rhs)
    {
        return lhs.type == rhs.type
            && lhs.name == rhs.name;
    }

    struct ascii_tree
    {
        static vector<token> tokenize(const string& s)
        {
            vector<token> tokens;
            enum { none, open_square_brace, close_square_brace, asterisk, dash, name_char } prev = none;
            size_t marker = 0, marked_length = 0;

            for (size_t i = 0; i < s.size(); ++i)
            {
                auto ch = s[i];

                if (ch == '[')
                {
                    prev = open_square_brace;
                }
                else if (ch == ']')
                {
                    if (prev == asterisk)
                    {
                        tokens.emplace_back(token { token::root_node, "" });
                    }
                    else
                    {
                        tokens.emplace_back(token { token::named_node, s.substr(marker, marked_length) });
                    }

                    prev = close_square_brace;
                }
                else if (ch == '*')
                {
                    prev = asterisk;
                }
                else if (ch == '-')
                {
                    if (prev == name_char)
                    {
                        tokens.emplace_back(token { token::horizontal_edge, s.substr(marker, marked_length) });
                    }

                    prev = dash;
                }
                else if (ch == '/')
                {
                    tokens.emplace_back(token { token::ascending_edge_part, "" });
                }
                else if (ch == '\\')
                {
                    tokens.emplace_back(token { token::descending_edge_part, "" });
                }
                else if (ch == '|')
                {
                    tokens.emplace_back(token { token::vertical_edge_part, "" });
                }
                else if (isalnum(ch) || ch == '_')
                {
                    if (prev != name_char)
                    {
                        marker = i;
                        marked_length = 0;
                    }

                    prev = name_char;
                    ++marked_length;
                }
            }

            if (prev == name_char)
            {
                tokens.emplace_back(token { token::edge_name, s.substr(marker, marked_length) });
            }

            return tokens;
        }
    };
}

namespace Microsoft { namespace VisualStudio { namespace CppUnitTestFramework
{
    template<>
    wstring ToString<algo::token::toktype>(const algo::token::toktype& type)
    {
        switch (type)
        {
        case algo::token::root_node:
            return L"root_node";
        case algo::token::named_node:
            return L"named_node";
        case algo::token::edge_name:
            return L"edge_name";
        case algo::token::horizontal_edge:
            return L"horizontal_edge";
        case algo::token::ascending_edge_part:
            return L"ascending_edge_part";
        case algo::token::descending_edge_part:
            return L"descending_edge_part";
        case algo::token::vertical_edge_part:
            return L"vertical_edge_part";
        default:
            return L"unknown token";
        }
    }
}}}

namespace algo { namespace spec
{
	TEST_CLASS(can_recognize_ascii_tree_tokens)
	{
        void tokens_should_match_(std::initializer_list<token> expected, vector<token>& actual)
        {
            auto mismatch_pair = std::mismatch(expected.begin(), expected.end(), actual.begin());

            if (mismatch_pair.first != expected.end() || mismatch_pair.second != actual.end())
            {
                wstring expectedName(mismatch_pair.first->name.begin(), mismatch_pair.first->name.end());
                wstring actualName(mismatch_pair.second->name.begin(), mismatch_pair.second->name.end());

                wstring message = L"Expected: " + ToString(mismatch_pair.first->type) + L" \"" + expectedName + L"\" "
                    + L"Actual: " + ToString(mismatch_pair.second->type) + L" \"" + actualName + L"\"";

                Assert::Fail(message.c_str());
            }
        }

    public:

        TEST_METHOD(should_not_recognize_any_tokens_in_an_empty_string)
        {
            auto tokens = ascii_tree::tokenize("");
            Assert::IsTrue(tokens.empty());
        }

		TEST_METHOD(should_recognize_a_root_node)
		{
            auto tokens = ascii_tree::tokenize("[*]");
            Assert::AreEqual(token::root_node, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_root_node_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" [ * ]");
            Assert::AreEqual(token::root_node, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_named_node)
        {
            const string all_chars = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            auto tokens = ascii_tree::tokenize("[" + all_chars + "]");
            Assert::AreEqual(token::named_node, tokens.front().type);
            Assert::AreEqual(all_chars.c_str(), tokens.front().name.c_str());
        }

        TEST_METHOD(should_recognize_a_named_node_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" [ a ]");
            Assert::AreEqual(token::named_node, tokens.front().type);
            Assert::AreEqual("a", tokens.front().name.c_str());
        }

        TEST_METHOD(should_recognize_an_edge_name)
        {
            auto tokens = ascii_tree::tokenize("a");
            Assert::AreEqual(token::edge_name, tokens.front().type);
            Assert::AreEqual("a", tokens.front().name.c_str());
        }

        TEST_METHOD(should_recognize_an_edge_name_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" a ");
            Assert::AreEqual(token::edge_name, tokens.front().type);
            Assert::AreEqual("a", tokens.front().name.c_str());
        }

        TEST_METHOD(should_recognize_an_ascending_edge_part)
        {
            auto tokens = ascii_tree::tokenize("/");
            Assert::AreEqual(token::ascending_edge_part, tokens.front().type);
        }

        TEST_METHOD(should_recognize_an_ascending_edge_part_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" / ");
            Assert::AreEqual(token::ascending_edge_part, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_descending_edge_part)
        {
            auto tokens = ascii_tree::tokenize("\\");
            Assert::AreEqual(token::descending_edge_part, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_descending_edge_part_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" \\ ");
            Assert::AreEqual(token::descending_edge_part, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_vertical_edge_part)
        {
            auto tokens = ascii_tree::tokenize("|");
            Assert::AreEqual(token::vertical_edge_part, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_vertical_edge_part_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" | ");
            Assert::AreEqual(token::vertical_edge_part, tokens.front().type);
        }

        TEST_METHOD(should_recognize_a_horizontal_edge)
        {
            auto tokens = ascii_tree::tokenize("-a-");
            Assert::AreEqual(token::horizontal_edge, tokens.front().type);
            Assert::AreEqual("a", tokens.front().name.c_str());
        }

        TEST_METHOD(should_recognize_a_horizontal_edge_with_spaces)
        {
            auto tokens = ascii_tree::tokenize(" - a - ");
            Assert::AreEqual(token::horizontal_edge, tokens.front().type);
            Assert::AreEqual("a", tokens.front().name.c_str());
        }

        TEST_METHOD(should_recognize_a_root_node_next_to_a_named_node)
        {
            auto tokens = ascii_tree::tokenize("[*][a]");
            tokens_should_match_({ { token::root_node, "" }, { token::named_node, "a" } }, tokens);
        }

        TEST_METHOD(should_recognize_a_root_node_next_to_a_horizontal_edge)
        {
            auto tokens = ascii_tree::tokenize("[*]-a-");
            tokens_should_match_({ { token::root_node, "" }, { token::horizontal_edge, "a" } }, tokens);
        }

        TEST_METHOD(should_recognize_a_horizontal_edge_next_to_a_named_node)
        {
            auto tokens = ascii_tree::tokenize("-a-[b]");
            tokens_should_match_({ { token::horizontal_edge, "a" }, { token::named_node, "b" } }, tokens);
        }

    };
}}
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2012, Stuart W Baker
 * 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.
 *
 * \file HwInit.cxx
 * This file represents the hardware initialization for the TI Tiva MCU.
 *
 * @author Stuart W. Baker
 * @date 5 January 2013
 */

#include <new>
#include <cstdint>

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "inc/hw_gpio.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "os/OS.hxx"

#include "hardware.hxx"

#include "TivaDev.hxx"

#include "TivaEEPROMEmulation.hxx"
#include "TivaEEPROMBitSet.hxx"
#include "TivaGPIO.hxx"
#include "DummyGPIO.hxx"
#include "bootloader_hal.h"

struct Debug
{
    typedef DummyPin DccPacketDelay;
    typedef DummyPin DccDecodeInterrupts;
    typedef DummyPin CapTimerOverflow;
};

#include "TivaDCCDecoder.hxx"

/** override stdin */
const char *STDIN_DEVICE = "/dev/ser0";

/** override stdout */
const char *STDOUT_DEVICE = "/dev/ser0";

/** override stderr */
const char *STDERR_DEVICE = "/dev/ser0";

/** USB Device CDC serial driver instance */
static TivaCdc cdc0("/dev/serUSB0", INT_RESOLVE(INT_USB0_, 0));

/** UART 0 serial driver instance */
static TivaUart uart0("/dev/ser0", UART0_BASE, INT_RESOLVE(INT_UART0_, 0));

/** CAN 0 CAN driver instance */
static TivaCan can0("/dev/can0", CAN0_BASE, INT_RESOLVE(INT_CAN0_, 0));

const unsigned TivaEEPROMEmulation::FAMILY = TM4C123;
const size_t EEPROMEmulation::SECTOR_SIZE = (4*1024);

static TivaEEPROMEmulation eeprom("/dev/eeprom", 1500);

extern StoredBitSet* g_gpio_stored_bit_set;
StoredBitSet* g_gpio_stored_bit_set = nullptr;
constexpr unsigned EEPROM_BIT_COUNT = 84;
constexpr unsigned EEPROM_BITS_PER_CELL = 28;

extern "C" {
void hw_set_to_safe(void);

void enter_bootloader()
{
    extern void (* const __interrupt_vector[])(void);
    if (__interrupt_vector[1] == __interrupt_vector[13] ||
        __interrupt_vector[13] == nullptr) {
        // No bootloader detected.
        return;
    }
    hw_set_to_safe();
    __bootloader_magic_ptr = REQUEST_BOOTLOADER;
    /* Globally disables interrupts. */
    asm("cpsid i\n");
    extern char __flash_start;
    asm volatile(" mov   r3, %[flash_addr] \n"
                 :
                 : [flash_addr] "r"(&__flash_start));
    /* Loads SP and jumps to the reset vector. */
    asm volatile(
        " ldr r0, [r3]\n"
        " mov sp, r0\n"
        " ldr r0, [r3, #4]\n"
        " bx  r0\n");
}
}

struct DCCDecode
{
    static const auto TIMER_BASE = TIMER2_BASE;
    static const auto TIMER_PERIPH = SYSCTL_PERIPH_TIMER2;
    static const auto TIMER_INTERRUPT = INT_TIMER2B;
    static const auto TIMER = TIMER_B;
    static const auto CFG_TIM_CAPTURE =
        TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_CAP_TIME;
    static const auto CFG_RCOM_TIMER =
        TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC;

    // Interrupt bits.
    static const auto TIMER_CAP_EVENT = TIMER_CAPB_EVENT;
    static const auto TIMER_RCOM_MATCH = TIMER_TIMA_MATCH;

    // Sets the match register of TIMER to update immediately.
    static void clr_tim_mrsu() {
      HWREG(TIMER_BASE + TIMER_O_TAMR) &= ~(TIMER_TAMR_TAMRSU);
      HWREG(TIMER_BASE + TIMER_O_TAMR) |= (TIMER_TAMR_TAMIE);
    }

    static void cap_event_hook() {}

    static const auto RCOM_TIMER = TIMER_A;
    static const auto SAMPLE_PERIOD_CLOCKS = 60000;
    //static const auto SAMPLE_TIMER_TIMEOUT = TIMER_TIMA_TIMEOUT;
    static const auto RCOM_INTERRUPT = INT_TIMER2A;
    static const auto OS_INTERRUPT = INT_WTIMER2A;
    typedef DCC_IN_Pin NRZ_Pin;

    // 16-bit timer max + use 7 bits of prescaler.
    static const uint32_t TIMER_MAX_VALUE = 0x800000UL;
    static const uint32_t PS_MAX = 0x80;

    static_assert(SAMPLE_PERIOD_CLOCKS < TIMER_MAX_VALUE, "Cannot sample less often than the timer period");

    static const int Q_SIZE = 32;

    // after 5 overcurrent samples we get one occupancy sample
    static const uint32_t OCCUPANCY_SAMPLE_RATIO = 5;
    static inline void dcc_before_cutout_hook() {}
    static inline void dcc_packet_finished_hook() {}
    static inline void after_feedback_hook() {}
};

// Dummy implementation because we are not a railcom detector.
NoRailcomDriver railcom_driver;

/** The input pin for detecting the DCC signal. */
static TivaDccDecoder<DCCDecode> dcc_decoder0("/dev/dcc_decoder0", &railcom_driver);

extern "C" {
/** Blink LED */
uint32_t blinker_pattern = 0;
static volatile uint32_t rest_pattern = 0;

void hw_set_to_safe(void)
{
    GpioInit::hw_set_to_safe();
}

void resetblink(uint32_t pattern)
{
    blinker_pattern = pattern;
    /* make a timer event trigger immediately */
}

void setblink(uint32_t pattern)
{
    resetblink(pattern);
}

static uint32_t nsec_per_clock = 0;
/// Calculate partial timing information from the tick counter.
long long hw_get_partial_tick_time_nsec(void)
{
    volatile uint32_t * tick_current_reg = (volatile uint32_t *)0xe000e018;
    long long tick_val = *tick_current_reg;
    tick_val *= nsec_per_clock;
    long long elapsed = (1ULL << NSEC_TO_TICK_SHIFT) - tick_val;
    if (elapsed < 0) elapsed = 0;
    return elapsed;
}

void timer5a_interrupt_handler(void)
{
    //
    // Clear the timer interrupt.
    //
    MAP_TimerIntClear(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    // Set output LED.
    BLINKER_RAW_Pin::set((rest_pattern & 1));

    // Shift and maybe reset pattern.
    rest_pattern >>= 1;
    if (!rest_pattern)
        rest_pattern = blinker_pattern;
}

void diewith(uint32_t pattern)
{
    vPortClearInterruptMask(0x20);
    asm("cpsie i\n");

    resetblink(pattern);
    while (1)
        ;
}

void timer2b_interrupt_handler(void)
{
  dcc_decoder0.interrupt_handler();
}

void timer2a_interrupt_handler(void)
{
  dcc_decoder0.rcom_interrupt_handler();
}

void wide_timer2a_interrupt_handler(void)
{
  dcc_decoder0.os_interrupt_handler();
}

/** Initialize the processor hardware.
 */
void hw_preinit(void)
{
    /* Globally disables interrupts until the FreeRTOS scheduler is up. */
    asm("cpsid i\n");

    nsec_per_clock = 1000000000 / cm3_cpu_clock_hz;

    //
    // Unlock PF0 so we can change it to a GPIO input
    // Once we have enabled (unlocked) the commit register then re-lock it
    // to prevent further changes.  PF0 is muxed with NMI thus a special case.
    //
    MAP_SysCtlPeripheralEnable(SW2_Pin::GPIO_PERIPH);
    HWREG(SW2_Pin::GPIO_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(SW2_Pin::GPIO_BASE + GPIO_O_CR) |= 0x01;
    HWREG(SW2_Pin::GPIO_BASE + GPIO_O_LOCK) = 0;

    // Initializes all GPIO and hardware pins.
    GpioInit::hw_init();

    /* Setup the system clock. */
    MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);

    /* Blinker timer initialization. */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER5);
    MAP_TimerConfigure(TIMER5_BASE, TIMER_CFG_PERIODIC);
    MAP_TimerLoadSet(TIMER5_BASE, TIMER_A, MAP_SysCtlClockGet() / 8);
    MAP_IntEnable(INT_TIMER5A);

    /* This interrupt should hit even during kernel operations. */
    MAP_IntPrioritySet(INT_TIMER5A, 0);
    MAP_TimerIntEnable(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    MAP_TimerEnable(TIMER5_BASE, TIMER_A);

    /* USB interrupt priority */
    MAP_IntPrioritySet(INT_USB0, 0xff); // USB interrupt low priority

    /* Checks the SW1 pin at boot time in case we want to allow for a debugger
     * to connect. */
    asm volatile ("cpsie i\n");
    do {
      if (!SW2_Pin::get()) {
        blinker_pattern = 0xAAAA;
      } else {
        blinker_pattern = 0;
      }
    } while (blinker_pattern || rest_pattern);

    asm volatile ("cpsid i\n");

    g_gpio_stored_bit_set = new EEPROMStoredBitSet<TivaEEPROMHwDefs<EEPROM_BIT_COUNT, EEPROM_BITS_PER_CELL>>(2, 2);
}

} // extern "C"
<commit_msg>fix compilation error.<commit_after>/** \copyright
 * Copyright (c) 2012, Stuart W Baker
 * 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.
 *
 * \file HwInit.cxx
 * This file represents the hardware initialization for the TI Tiva MCU.
 *
 * @author Stuart W. Baker
 * @date 5 January 2013
 */

#include <new>
#include <cstdint>

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "inc/hw_gpio.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "os/OS.hxx"

#include "hardware.hxx"

#include "TivaDev.hxx"

#include "TivaEEPROMEmulation.hxx"
#include "TivaEEPROMBitSet.hxx"
#include "TivaGPIO.hxx"
#include "DummyGPIO.hxx"
#include "bootloader_hal.h"

struct Debug
{
    typedef DummyPin DccPacketDelay;
    typedef DummyPin DccDecodeInterrupts;
    typedef DummyPin DccPacketFinishedHook;
    typedef DummyPin CapTimerOverflow;
};

#include "TivaDCCDecoder.hxx"

/** override stdin */
const char *STDIN_DEVICE = "/dev/ser0";

/** override stdout */
const char *STDOUT_DEVICE = "/dev/ser0";

/** override stderr */
const char *STDERR_DEVICE = "/dev/ser0";

/** USB Device CDC serial driver instance */
static TivaCdc cdc0("/dev/serUSB0", INT_RESOLVE(INT_USB0_, 0));

/** UART 0 serial driver instance */
static TivaUart uart0("/dev/ser0", UART0_BASE, INT_RESOLVE(INT_UART0_, 0));

/** CAN 0 CAN driver instance */
static TivaCan can0("/dev/can0", CAN0_BASE, INT_RESOLVE(INT_CAN0_, 0));

const unsigned TivaEEPROMEmulation::FAMILY = TM4C123;
const size_t EEPROMEmulation::SECTOR_SIZE = (4*1024);

static TivaEEPROMEmulation eeprom("/dev/eeprom", 1500);

extern StoredBitSet* g_gpio_stored_bit_set;
StoredBitSet* g_gpio_stored_bit_set = nullptr;
constexpr unsigned EEPROM_BIT_COUNT = 84;
constexpr unsigned EEPROM_BITS_PER_CELL = 28;

extern "C" {
void hw_set_to_safe(void);

void enter_bootloader()
{
    extern void (* const __interrupt_vector[])(void);
    if (__interrupt_vector[1] == __interrupt_vector[13] ||
        __interrupt_vector[13] == nullptr) {
        // No bootloader detected.
        return;
    }
    hw_set_to_safe();
    __bootloader_magic_ptr = REQUEST_BOOTLOADER;
    /* Globally disables interrupts. */
    asm("cpsid i\n");
    extern char __flash_start;
    asm volatile(" mov   r3, %[flash_addr] \n"
                 :
                 : [flash_addr] "r"(&__flash_start));
    /* Loads SP and jumps to the reset vector. */
    asm volatile(
        " ldr r0, [r3]\n"
        " mov sp, r0\n"
        " ldr r0, [r3, #4]\n"
        " bx  r0\n");
}
}

struct DCCDecode
{
    static const auto TIMER_BASE = TIMER2_BASE;
    static const auto TIMER_PERIPH = SYSCTL_PERIPH_TIMER2;
    static const auto TIMER_INTERRUPT = INT_TIMER2B;
    static const auto TIMER = TIMER_B;
    static const auto CFG_TIM_CAPTURE =
        TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_CAP_TIME;
    static const auto CFG_RCOM_TIMER =
        TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC;

    // Interrupt bits.
    static const auto TIMER_CAP_EVENT = TIMER_CAPB_EVENT;
    static const auto TIMER_RCOM_MATCH = TIMER_TIMA_MATCH;

    // Sets the match register of TIMER to update immediately.
    static void clr_tim_mrsu() {
      HWREG(TIMER_BASE + TIMER_O_TAMR) &= ~(TIMER_TAMR_TAMRSU);
      HWREG(TIMER_BASE + TIMER_O_TAMR) |= (TIMER_TAMR_TAMIE);
    }

    static void cap_event_hook() {}

    static const auto RCOM_TIMER = TIMER_A;
    static const auto SAMPLE_PERIOD_CLOCKS = 60000;
    //static const auto SAMPLE_TIMER_TIMEOUT = TIMER_TIMA_TIMEOUT;
    static const auto RCOM_INTERRUPT = INT_TIMER2A;
    static const auto OS_INTERRUPT = INT_WTIMER2A;
    typedef DCC_IN_Pin NRZ_Pin;

    // 16-bit timer max + use 7 bits of prescaler.
    static const uint32_t TIMER_MAX_VALUE = 0x800000UL;
    static const uint32_t PS_MAX = 0x80;

    static_assert(SAMPLE_PERIOD_CLOCKS < TIMER_MAX_VALUE, "Cannot sample less often than the timer period");

    static const int Q_SIZE = 32;

    // after 5 overcurrent samples we get one occupancy sample
    static const uint32_t OCCUPANCY_SAMPLE_RATIO = 5;
    static inline void dcc_before_cutout_hook() {}
    static inline void dcc_packet_finished_hook() {}
    static inline void after_feedback_hook() {}
};

// Dummy implementation because we are not a railcom detector.
NoRailcomDriver railcom_driver;

/** The input pin for detecting the DCC signal. */
static TivaDccDecoder<DCCDecode> dcc_decoder0("/dev/dcc_decoder0", &railcom_driver);

extern "C" {
/** Blink LED */
uint32_t blinker_pattern = 0;
static volatile uint32_t rest_pattern = 0;

void hw_set_to_safe(void)
{
    GpioInit::hw_set_to_safe();
}

void resetblink(uint32_t pattern)
{
    blinker_pattern = pattern;
    /* make a timer event trigger immediately */
}

void setblink(uint32_t pattern)
{
    resetblink(pattern);
}

static uint32_t nsec_per_clock = 0;
/// Calculate partial timing information from the tick counter.
long long hw_get_partial_tick_time_nsec(void)
{
    volatile uint32_t * tick_current_reg = (volatile uint32_t *)0xe000e018;
    long long tick_val = *tick_current_reg;
    tick_val *= nsec_per_clock;
    long long elapsed = (1ULL << NSEC_TO_TICK_SHIFT) - tick_val;
    if (elapsed < 0) elapsed = 0;
    return elapsed;
}

void timer5a_interrupt_handler(void)
{
    //
    // Clear the timer interrupt.
    //
    MAP_TimerIntClear(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    // Set output LED.
    BLINKER_RAW_Pin::set((rest_pattern & 1));

    // Shift and maybe reset pattern.
    rest_pattern >>= 1;
    if (!rest_pattern)
        rest_pattern = blinker_pattern;
}

void diewith(uint32_t pattern)
{
    vPortClearInterruptMask(0x20);
    asm("cpsie i\n");

    resetblink(pattern);
    while (1)
        ;
}

void timer2b_interrupt_handler(void)
{
  dcc_decoder0.interrupt_handler();
}

void timer2a_interrupt_handler(void)
{
  dcc_decoder0.rcom_interrupt_handler();
}

void wide_timer2a_interrupt_handler(void)
{
  dcc_decoder0.os_interrupt_handler();
}

/** Initialize the processor hardware.
 */
void hw_preinit(void)
{
    /* Globally disables interrupts until the FreeRTOS scheduler is up. */
    asm("cpsid i\n");

    nsec_per_clock = 1000000000 / cm3_cpu_clock_hz;

    //
    // Unlock PF0 so we can change it to a GPIO input
    // Once we have enabled (unlocked) the commit register then re-lock it
    // to prevent further changes.  PF0 is muxed with NMI thus a special case.
    //
    MAP_SysCtlPeripheralEnable(SW2_Pin::GPIO_PERIPH);
    HWREG(SW2_Pin::GPIO_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(SW2_Pin::GPIO_BASE + GPIO_O_CR) |= 0x01;
    HWREG(SW2_Pin::GPIO_BASE + GPIO_O_LOCK) = 0;

    // Initializes all GPIO and hardware pins.
    GpioInit::hw_init();

    /* Setup the system clock. */
    MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);

    /* Blinker timer initialization. */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER5);
    MAP_TimerConfigure(TIMER5_BASE, TIMER_CFG_PERIODIC);
    MAP_TimerLoadSet(TIMER5_BASE, TIMER_A, MAP_SysCtlClockGet() / 8);
    MAP_IntEnable(INT_TIMER5A);

    /* This interrupt should hit even during kernel operations. */
    MAP_IntPrioritySet(INT_TIMER5A, 0);
    MAP_TimerIntEnable(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    MAP_TimerEnable(TIMER5_BASE, TIMER_A);

    /* USB interrupt priority */
    MAP_IntPrioritySet(INT_USB0, 0xff); // USB interrupt low priority

    /* Checks the SW1 pin at boot time in case we want to allow for a debugger
     * to connect. */
    asm volatile ("cpsie i\n");
    do {
      if (!SW2_Pin::get()) {
        blinker_pattern = 0xAAAA;
      } else {
        blinker_pattern = 0;
      }
    } while (blinker_pattern || rest_pattern);

    asm volatile ("cpsid i\n");

    g_gpio_stored_bit_set = new EEPROMStoredBitSet<TivaEEPROMHwDefs<EEPROM_BIT_COUNT, EEPROM_BITS_PER_CELL>>(2, 2);
}

} // extern "C"
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: salframe.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: pluby $ $Date: 2000-11-14 00:18:56 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <string.h>

#define _SV_SALFRAME_CXX

#ifndef _SV_SALDATA_HXX
#include <saldata.hxx>
#endif
#ifndef _SV_SALGDI_HXX
#include <salgdi.hxx>
#endif
#ifndef _SV_SALFRAME_HXX
#include <salframe.hxx>
#endif
#ifndef _SV_VCLWINDOW_H
#include <VCLWindow.h>
#endif
#ifndef _SV_VCLGRAPHICS_H
#include <VCLGraphics.h>
#endif

// =======================================================================

SalFrame::SalFrame()
{
    SalData* pSalData = GetSalData();

    maFrameData.mhWnd               = 0;
    maFrameData.mpGraphics          = NULL;
    maFrameData.mpInst              = NULL;
    maFrameData.mpProc              = NULL;
    maFrameData.mnInputLang         = 0;
    maFrameData.mnInputCodePage     = 0;
    maFrameData.mbGraphics          = FALSE;
    maFrameData.mbCaption           = FALSE;
    maFrameData.mbBorder            = FALSE;
    maFrameData.mbSizeBorder        = FALSE;
    maFrameData.mbFullScreen        = FALSE;
    maFrameData.mbPresentation      = FALSE;
    maFrameData.mbInShow            = FALSE;
    maFrameData.mbRestoreMaximize   = FALSE;
    maFrameData.mbInMoveMsg         = FALSE;
    maFrameData.mbInSizeMsg         = FALSE;
    maFrameData.mbFullScreenToolWin = FALSE;
    maFrameData.mbDefPos            = TRUE;
    maFrameData.mbOverwriteState    = TRUE;
    maFrameData.mbIME               = FALSE;
    maFrameData.mbHandleIME         = FALSE;
    maFrameData.mbSpezIME           = FALSE;
    maFrameData.mbAtCursorIME       = FALSE;
    maFrameData.mbCompositionMode   = FALSE;
    maFrameData.mbCandidateMode     = FALSE;
    memset( &maFrameData.maState, 0, sizeof( SalFrameState ) );
    maFrameData.maSysData.nSize     = sizeof( SystemEnvData );
}

// -----------------------------------------------------------------------

SalFrame::~SalFrame()
{
}

// -----------------------------------------------------------------------

SalGraphics* SalFrame::GetGraphics()
{
    if ( maFrameData.mbGraphics )
        return NULL;

    if ( !maFrameData.mpGraphics )
    {
        VCLVIEW hView = VCLWindow_contentView( maFrameData.mhWnd );
        if ( hView )
        {
            SalData* pSalData = GetSalData();
            maFrameData.mpGraphics = new SalGraphics;
            maFrameData.mpGraphics->maGraphicsData.mhDC      = hView;
            maFrameData.mpGraphics->maGraphicsData.mhWnd     = maFrameData.mhWnd;
            maFrameData.mpGraphics->maGraphicsData.mbPrinter = FALSE;
            maFrameData.mpGraphics->maGraphicsData.mbVirDev  = FALSE;
            maFrameData.mpGraphics->maGraphicsData.mbWindow  = TRUE;
            maFrameData.mpGraphics->maGraphicsData.mbScreen  = TRUE;
            maFrameData.mbGraphics = TRUE;
        }
    }
    else
        maFrameData.mbGraphics = TRUE;

    return maFrameData.mpGraphics;
}

// -----------------------------------------------------------------------

void SalFrame::ReleaseGraphics( SalGraphics* )
{
}

// -----------------------------------------------------------------------

BOOL SalFrame::PostEvent( void* pData )
{
    return FALSE;
}

// -----------------------------------------------------------------------

void SalFrame::SetTitle( const XubString& rTitle )
{

    ByteString aByteTitle( rTitle, gsl_getSystemTextEncoding() );
    char *pTitle = (char *)aByteTitle.GetBuffer();
    VCLWindow_setTitle(maFrameData.mhWnd, pTitle);

}

// -----------------------------------------------------------------------

void SalFrame::SetIcon( USHORT nIcon )
{
}

// -----------------------------------------------------------------------

void SalFrame::Show( BOOL bVisible )
{
    if ( bVisible )
        VCLWindow_makeKeyAndOrderFront( maFrameData.mhWnd );
    else
        VCLWindow_close( maFrameData.mhWnd );

    // This is temporary code for testing only and should be removed when
    // development of the SalObject class is complete. This code allows
    // us to test our SalGraphics drawing methods.

    // Get this window's cached handle to its native content view
    VCLVIEW hView = VCLWindow_contentView( maFrameData.mhWnd );

    // Draw a line on the native content view
    VCLGraphics_drawLine( hView, 0L, 0L, 1000L, 1000L );
}

// -----------------------------------------------------------------------

void SalFrame::Enable( BOOL bEnable )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetMinClientSize( long nWidth, long nHeight )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetClientSize( long nWidth, long nHeight )
{
}

// -----------------------------------------------------------------------

void SalFrame::GetClientSize( long& rWidth, long& rHeight )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetWindowState( const SalFrameState* pState )
{
}

// -----------------------------------------------------------------------

BOOL SalFrame::GetWindowState( SalFrameState* pState )
{
    return FALSE;
}

// -----------------------------------------------------------------------

void SalFrame::ShowFullScreen( BOOL bFullScreen )
{
}

// -----------------------------------------------------------------------

void SalFrame::StartPresentation( BOOL bStart )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetAlwaysOnTop( BOOL bOnTop )
{
}

// -----------------------------------------------------------------------

void SalFrame::ToTop( USHORT nFlags )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetPointer( PointerStyle ePointerStyle )
{
}

// -----------------------------------------------------------------------

void SalFrame::CaptureMouse( BOOL bCapture )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetPointerPos( long nX, long nY )
{
}

// -----------------------------------------------------------------------

void SalFrame::Flush()
{
}

// -----------------------------------------------------------------------

void SalFrame::Sync()
{
}

// -----------------------------------------------------------------------

void SalFrame::SetInputContext( SalInputContext* pContext )
{
}

// -----------------------------------------------------------------------

void SalFrame::UpdateExtTextInputArea()
{
}

// -----------------------------------------------------------------------

void SalFrame::EndExtTextInput( USHORT nFlags )
{
}

// -----------------------------------------------------------------------

XubString SalFrame::GetKeyName( USHORT nKeyCode )
{
    return XubString();
}

// -----------------------------------------------------------------------

XubString SalFrame::GetSymbolKeyName( const XubString&, USHORT nKeyCode )
{
    return GetKeyName( nKeyCode );
}

// -----------------------------------------------------------------------

void SalFrame::UpdateSettings( AllSettings& rSettings )
{
}

// -----------------------------------------------------------------------

const SystemEnvData* SalFrame::GetSystemData() const
{
    return NULL;
}

// -----------------------------------------------------------------------

void SalFrame::Beep( SoundType eSoundType )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetCallback( void* pInst, SALFRAMEPROC pProc )
{
}
<commit_msg>Added #if statement for SRC612 build<commit_after>/*************************************************************************
 *
 *  $RCSfile: salframe.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: pluby $ $Date: 2000-11-14 00:34:47 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <string.h>

#define _SV_SALFRAME_CXX

#ifndef _SV_SALDATA_HXX
#include <saldata.hxx>
#endif
#ifndef _SV_SALGDI_HXX
#include <salgdi.hxx>
#endif
#ifndef _SV_SALFRAME_HXX
#include <salframe.hxx>
#endif
#ifndef _SV_VCLWINDOW_H
#include <VCLWindow.h>
#endif
#ifndef _SV_VCLGRAPHICS_H
#include <VCLGraphics.h>
#endif

// =======================================================================

SalFrame::SalFrame()
{
    SalData* pSalData = GetSalData();

    maFrameData.mhWnd               = 0;
    maFrameData.mpGraphics          = NULL;
    maFrameData.mpInst              = NULL;
    maFrameData.mpProc              = NULL;
    maFrameData.mnInputLang         = 0;
    maFrameData.mnInputCodePage     = 0;
    maFrameData.mbGraphics          = FALSE;
    maFrameData.mbCaption           = FALSE;
    maFrameData.mbBorder            = FALSE;
    maFrameData.mbSizeBorder        = FALSE;
    maFrameData.mbFullScreen        = FALSE;
    maFrameData.mbPresentation      = FALSE;
    maFrameData.mbInShow            = FALSE;
    maFrameData.mbRestoreMaximize   = FALSE;
    maFrameData.mbInMoveMsg         = FALSE;
    maFrameData.mbInSizeMsg         = FALSE;
    maFrameData.mbFullScreenToolWin = FALSE;
    maFrameData.mbDefPos            = TRUE;
    maFrameData.mbOverwriteState    = TRUE;
    maFrameData.mbIME               = FALSE;
    maFrameData.mbHandleIME         = FALSE;
    maFrameData.mbSpezIME           = FALSE;
    maFrameData.mbAtCursorIME       = FALSE;
    maFrameData.mbCompositionMode   = FALSE;
    maFrameData.mbCandidateMode     = FALSE;
    memset( &maFrameData.maState, 0, sizeof( SalFrameState ) );
    maFrameData.maSysData.nSize     = sizeof( SystemEnvData );
}

// -----------------------------------------------------------------------

SalFrame::~SalFrame()
{
}

// -----------------------------------------------------------------------

SalGraphics* SalFrame::GetGraphics()
{
    if ( maFrameData.mbGraphics )
        return NULL;

    if ( !maFrameData.mpGraphics )
    {
        VCLVIEW hView = VCLWindow_contentView( maFrameData.mhWnd );
        if ( hView )
        {
            SalData* pSalData = GetSalData();
            maFrameData.mpGraphics = new SalGraphics;
            maFrameData.mpGraphics->maGraphicsData.mhDC      = hView;
            maFrameData.mpGraphics->maGraphicsData.mhWnd     = maFrameData.mhWnd;
            maFrameData.mpGraphics->maGraphicsData.mbPrinter = FALSE;
            maFrameData.mpGraphics->maGraphicsData.mbVirDev  = FALSE;
            maFrameData.mpGraphics->maGraphicsData.mbWindow  = TRUE;
            maFrameData.mpGraphics->maGraphicsData.mbScreen  = TRUE;
            maFrameData.mbGraphics = TRUE;
        }
    }
    else
        maFrameData.mbGraphics = TRUE;

    return maFrameData.mpGraphics;
}

// -----------------------------------------------------------------------

void SalFrame::ReleaseGraphics( SalGraphics* )
{
}

// -----------------------------------------------------------------------

BOOL SalFrame::PostEvent( void* pData )
{
    return FALSE;
}

// -----------------------------------------------------------------------

void SalFrame::SetTitle( const XubString& rTitle )
{

    ByteString aByteTitle( rTitle, gsl_getSystemTextEncoding() );
    char *pTitle = (char *)aByteTitle.GetBuffer();
    VCLWindow_setTitle(maFrameData.mhWnd, pTitle);

}

// -----------------------------------------------------------------------

void SalFrame::SetIcon( USHORT nIcon )
{
}

// -----------------------------------------------------------------------

void SalFrame::Show( BOOL bVisible )
{
    if ( bVisible )
        VCLWindow_makeKeyAndOrderFront( maFrameData.mhWnd );
    else
        VCLWindow_close( maFrameData.mhWnd );

    // This is temporary code for testing only and should be removed when
    // development of the SalObject class is complete. This code allows
    // us to test our SalGraphics drawing methods.

    // Get this window's cached handle to its native content view
    VCLVIEW hView = VCLWindow_contentView( maFrameData.mhWnd );

    // Draw a line on the native content view
    VCLGraphics_drawLine( hView, 0L, 0L, 1000L, 1000L );
}

// -----------------------------------------------------------------------

void SalFrame::Enable( BOOL bEnable )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetMinClientSize( long nWidth, long nHeight )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetClientSize( long nWidth, long nHeight )
{
}

// -----------------------------------------------------------------------

void SalFrame::GetClientSize( long& rWidth, long& rHeight )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetWindowState( const SalFrameState* pState )
{
}

// -----------------------------------------------------------------------

BOOL SalFrame::GetWindowState( SalFrameState* pState )
{
    return FALSE;
}

// -----------------------------------------------------------------------

void SalFrame::ShowFullScreen( BOOL bFullScreen )
{
}

// -----------------------------------------------------------------------

void SalFrame::StartPresentation( BOOL bStart )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetAlwaysOnTop( BOOL bOnTop )
{
}

// -----------------------------------------------------------------------

void SalFrame::ToTop( USHORT nFlags )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetPointer( PointerStyle ePointerStyle )
{
}

// -----------------------------------------------------------------------

void SalFrame::CaptureMouse( BOOL bCapture )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetPointerPos( long nX, long nY )
{
}

// -----------------------------------------------------------------------

void SalFrame::Flush()
{
}

// -----------------------------------------------------------------------

void SalFrame::Sync()
{
}

// -----------------------------------------------------------------------

void SalFrame::SetInputContext( SalInputContext* pContext )
{
}

// -----------------------------------------------------------------------

#if SUPD < 612
void SalFrame::UpdateExtTextInputArea()
{
}
#endif

// -----------------------------------------------------------------------

void SalFrame::EndExtTextInput( USHORT nFlags )
{
}

// -----------------------------------------------------------------------

XubString SalFrame::GetKeyName( USHORT nKeyCode )
{
    return XubString();
}

// -----------------------------------------------------------------------

XubString SalFrame::GetSymbolKeyName( const XubString&, USHORT nKeyCode )
{
    return GetKeyName( nKeyCode );
}

// -----------------------------------------------------------------------

void SalFrame::UpdateSettings( AllSettings& rSettings )
{
}

// -----------------------------------------------------------------------

const SystemEnvData* SalFrame::GetSystemData() const
{
    return NULL;
}

// -----------------------------------------------------------------------

void SalFrame::Beep( SoundType eSoundType )
{
}

// -----------------------------------------------------------------------

void SalFrame::SetCallback( void* pInst, SALFRAMEPROC pProc )
{
}
<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "bindings/core/v8/ScriptStreamer.h"

#include "bindings/core/v8/ScriptStreamerThread.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8ScriptRunner.h"
#include "core/dom/PendingScript.h"
#include "core/frame/Settings.h"
#include "platform/Task.h"
#include "public/platform/Platform.h"

#include <gtest/gtest.h>
#include <v8.h>

namespace blink {

namespace {

class ScriptStreamingTest : public testing::Test {
public:
    ScriptStreamingTest()
        : m_scope(v8::Isolate::GetCurrent())
        , m_settings(Settings::create())
        , m_resourceRequest("http://www.streaming-test.com/")
        , m_resource(new ScriptResource(m_resourceRequest, "text/utf-8"))
        , m_pendingScript(0, m_resource) // Takes ownership of m_resource.
    {
        m_settings->setV8ScriptStreamingEnabled(true);
        m_resource->setLoading(true);
    }

    ScriptState* scriptState() const { return m_scope.scriptState(); }
    v8::Isolate* isolate() const { return m_scope.isolate(); }

    void trace(Visitor* visitor)
    {
        visitor->trace(m_pendingScript);
    }

protected:
    void appendData(const char* data)
    {
        m_resource->appendData(data, strlen(data));
        // Yield control to the background thread, so that V8 gets a change to
        // process the data before the main thread adds more. Note that we
        // cannot fully control in what kind of chunks the data is passed to V8
        // (if the V8 is not requesting more data between two appendData calls,
        // V8 will get both chunks together).
        WTF::yield();
    }

    void appendPadding()
    {
        for (int i = 0; i < 10; ++i) {
            appendData(" /* this is padding to make the script long enough, so "
                "that V8's buffer gets filled and it starts processing "
                "the data */ ");
        }
    }

    void finish()
    {
        m_resource->finish();
        m_resource->setLoading(false);
    }

    void processTasksUntilStreamingComplete()
    {
        while (ScriptStreamerThread::shared()->isRunningTask()) {
            WebThread* currentThread = blink::Platform::current()->currentThread();
            currentThread->postTask(new Task(WTF::bind(&WebThread::exitRunLoop, currentThread)));
            currentThread->enterRunLoop();
        }
    }

    V8TestingScope m_scope;
    OwnPtr<Settings> m_settings;
    // The Resource and PendingScript where we stream from. These don't really
    // fetch any data outside the test; the test controls the data by calling
    // ScriptResource::appendData.
    ResourceRequest m_resourceRequest;
    ScriptResource* m_resource;
    PendingScript m_pendingScript;
};

class TestScriptResourceClient : public ScriptResourceClient {
public:
    TestScriptResourceClient()
        : m_finished(false) { }

    virtual void notifyFinished(Resource*) OVERRIDE { m_finished = true; }

    bool finished() const { return m_finished; }

private:
    bool m_finished;
};

TEST_F(ScriptStreamingTest, CompilingStreamedScript)
{
    // Test that we can successfully compile a streamed script.
    bool started = ScriptStreamer::startStreaming(m_pendingScript, m_settings.get(), m_scope.scriptState());
    TestScriptResourceClient client;
    m_pendingScript.watchForLoad(&client);
    EXPECT_TRUE(started);

    appendData("function foo() {");
    appendPadding();
    appendData("return 5; }");
    appendPadding();
    appendData("foo();");
    EXPECT_FALSE(client.finished());
    finish();

    // Process tasks on the main thread until the streaming background thread
    // has completed its tasks.
    processTasksUntilStreamingComplete();
    EXPECT_TRUE(client.finished());
    bool errorOccurred = false;
    ScriptSourceCode sourceCode = m_pendingScript.getSource(KURL(), errorOccurred);
    EXPECT_FALSE(errorOccurred);
    EXPECT_TRUE(sourceCode.streamer());
    v8::TryCatch tryCatch;
    v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, isolate());
    EXPECT_FALSE(script.IsEmpty());
    EXPECT_FALSE(tryCatch.HasCaught());
}

TEST_F(ScriptStreamingTest, CompilingStreamedScriptWithParseError)
{
    // Test that scripts with parse errors are handled properly. In those cases,
    // the V8 side typically finished before loading finishes: make sure we
    // handle it gracefully.
    bool started = ScriptStreamer::startStreaming(m_pendingScript, m_settings.get(), m_scope.scriptState());
    TestScriptResourceClient client;
    m_pendingScript.watchForLoad(&client);
    EXPECT_TRUE(started);
    appendData("function foo() {");
    appendData("this is the part which will be a parse error");
    // V8 won't realize the parse error until it actually starts parsing the
    // script, and this happens only when its buffer is filled.
    appendPadding();

    EXPECT_FALSE(client.finished());

    // Force the V8 side to finish before the loading.
    processTasksUntilStreamingComplete();
    EXPECT_FALSE(client.finished());

    finish();
    EXPECT_TRUE(client.finished());

    bool errorOccurred = false;
    ScriptSourceCode sourceCode = m_pendingScript.getSource(KURL(), errorOccurred);
    EXPECT_FALSE(errorOccurred);
    EXPECT_TRUE(sourceCode.streamer());
    v8::TryCatch tryCatch;
    v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, isolate());
    EXPECT_TRUE(script.IsEmpty());
    EXPECT_TRUE(tryCatch.HasCaught());
}

TEST_F(ScriptStreamingTest, CancellingStreaming)
{
    // Test that the upper layers (PendingScript and up) can be ramped down
    // while streaming is ongoing, and ScriptStreamer handles it gracefully.
    bool started = ScriptStreamer::startStreaming(m_pendingScript, m_settings.get(), m_scope.scriptState());
    TestScriptResourceClient client;
    m_pendingScript.watchForLoad(&client);
    EXPECT_TRUE(started);
    appendData("function foo() {");

    // In general, we cannot control what the background thread is doing
    // (whether it's parsing or waiting for more data). In this test, we have
    // given it so little data that it's surely waiting for more.

    // Simulate cancelling the network load (e.g., because the user navigated
    // away).
    EXPECT_FALSE(client.finished());
    m_pendingScript.stopWatchingForLoad(&client);
    m_pendingScript = PendingScript(); // This will destroy m_resource.
    m_resource = 0;

    // The V8 side will complete too. This should not crash. We don't receive
    // any results from the streaming and the client doesn't get notified.
    processTasksUntilStreamingComplete();
    EXPECT_FALSE(client.finished());
}

TEST_F(ScriptStreamingTest, SuppressingStreaming)
{
    // If we notice during streaming that there is a code cache, streaming
    // is suppressed (V8 doesn't parse while the script is loading), and the
    // upper layer (ScriptResourceClient) should get a notification when the
    // script is loaded.
    bool started = ScriptStreamer::startStreaming(m_pendingScript, m_settings.get(), m_scope.scriptState());
    TestScriptResourceClient client;
    m_pendingScript.watchForLoad(&client);
    EXPECT_TRUE(started);
    appendData("function foo() {");
    appendPadding();

    m_resource->setCachedMetadata(V8ScriptRunner::tagForCodeCache(), "X", 1, Resource::CacheLocally);

    appendPadding();
    finish();
    processTasksUntilStreamingComplete();
    EXPECT_TRUE(client.finished());

    bool errorOccurred = false;
    ScriptSourceCode sourceCode = m_pendingScript.getSource(KURL(), errorOccurred);
    EXPECT_FALSE(errorOccurred);
    // ScriptSourceCode doesn't refer to the streamer, since we have suppressed
    // the streaming and resumed the non-streaming code path for script
    // compilation.
    EXPECT_FALSE(sourceCode.streamer());
}

} // namespace

} // namespace blink
<commit_msg>Oilpan: have ScriptStreamingTest correctly trace its PendingScript.<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "bindings/core/v8/ScriptStreamer.h"

#include "bindings/core/v8/ScriptStreamerThread.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8ScriptRunner.h"
#include "core/dom/PendingScript.h"
#include "core/frame/Settings.h"
#include "platform/Task.h"
#include "platform/heap/Handle.h"
#include "public/platform/Platform.h"

#include <gtest/gtest.h>
#include <v8.h>

namespace blink {

namespace {

// For the benefit of Oilpan, put the part object PendingScript inside
// a wrapper that's on the Oilpan heap and hold a reference to that wrapper
// from ScriptStreamingTest.
class PendingScriptWrapper : public NoBaseWillBeGarbageCollectedFinalized<PendingScriptWrapper> {
public:
    static PassOwnPtrWillBeRawPtr<PendingScriptWrapper> create()
    {
        return adoptPtrWillBeNoop(new PendingScriptWrapper());
    }

    static PassOwnPtrWillBeRawPtr<PendingScriptWrapper> create(Element* element, ScriptResource* resource)
    {
        return adoptPtrWillBeNoop(new PendingScriptWrapper(element, resource));
    }

    PendingScript& get() { return m_pendingScript; }

    void trace(Visitor* visitor)
    {
        visitor->trace(m_pendingScript);
    }

private:
    PendingScriptWrapper()
    {
    }

    PendingScriptWrapper(Element* element, ScriptResource* resource)
        : m_pendingScript(PendingScript(element, resource))
    {
    }

    PendingScript m_pendingScript;
};

class ScriptStreamingTest : public testing::Test {
public:
    ScriptStreamingTest()
        : m_scope(v8::Isolate::GetCurrent())
        , m_settings(Settings::create())
        , m_resourceRequest("http://www.streaming-test.com/")
        , m_resource(new ScriptResource(m_resourceRequest, "text/utf-8"))
        , m_pendingScript(PendingScriptWrapper::create(0, m_resource)) // Takes ownership of m_resource.
    {
        m_settings->setV8ScriptStreamingEnabled(true);
        m_resource->setLoading(true);
    }

    ScriptState* scriptState() const { return m_scope.scriptState(); }
    v8::Isolate* isolate() const { return m_scope.isolate(); }

    PendingScript& pendingScript() const { return m_pendingScript->get(); }

protected:
    void appendData(const char* data)
    {
        m_resource->appendData(data, strlen(data));
        // Yield control to the background thread, so that V8 gets a change to
        // process the data before the main thread adds more. Note that we
        // cannot fully control in what kind of chunks the data is passed to V8
        // (if the V8 is not requesting more data between two appendData calls,
        // V8 will get both chunks together).
        WTF::yield();
    }

    void appendPadding()
    {
        for (int i = 0; i < 10; ++i) {
            appendData(" /* this is padding to make the script long enough, so "
                "that V8's buffer gets filled and it starts processing "
                "the data */ ");
        }
    }

    void finish()
    {
        m_resource->finish();
        m_resource->setLoading(false);
    }

    void processTasksUntilStreamingComplete()
    {
        while (ScriptStreamerThread::shared()->isRunningTask()) {
            WebThread* currentThread = blink::Platform::current()->currentThread();
            currentThread->postTask(new Task(WTF::bind(&WebThread::exitRunLoop, currentThread)));
            currentThread->enterRunLoop();
        }
    }

    V8TestingScope m_scope;
    OwnPtr<Settings> m_settings;
    // The Resource and PendingScript where we stream from. These don't really
    // fetch any data outside the test; the test controls the data by calling
    // ScriptResource::appendData.
    ResourceRequest m_resourceRequest;
    ScriptResource* m_resource;
    OwnPtrWillBePersistent<PendingScriptWrapper> m_pendingScript;
};

class TestScriptResourceClient : public ScriptResourceClient {
public:
    TestScriptResourceClient()
        : m_finished(false) { }

    virtual void notifyFinished(Resource*) OVERRIDE { m_finished = true; }

    bool finished() const { return m_finished; }

private:
    bool m_finished;
};

TEST_F(ScriptStreamingTest, CompilingStreamedScript)
{
    // Test that we can successfully compile a streamed script.
    bool started = ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.scriptState());
    TestScriptResourceClient client;
    pendingScript().watchForLoad(&client);
    EXPECT_TRUE(started);

    appendData("function foo() {");
    appendPadding();
    appendData("return 5; }");
    appendPadding();
    appendData("foo();");
    EXPECT_FALSE(client.finished());
    finish();

    // Process tasks on the main thread until the streaming background thread
    // has completed its tasks.
    processTasksUntilStreamingComplete();
    EXPECT_TRUE(client.finished());
    bool errorOccurred = false;
    ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurred);
    EXPECT_FALSE(errorOccurred);
    EXPECT_TRUE(sourceCode.streamer());
    v8::TryCatch tryCatch;
    v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, isolate());
    EXPECT_FALSE(script.IsEmpty());
    EXPECT_FALSE(tryCatch.HasCaught());
}

TEST_F(ScriptStreamingTest, CompilingStreamedScriptWithParseError)
{
    // Test that scripts with parse errors are handled properly. In those cases,
    // the V8 side typically finished before loading finishes: make sure we
    // handle it gracefully.
    bool started = ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.scriptState());
    TestScriptResourceClient client;
    pendingScript().watchForLoad(&client);
    EXPECT_TRUE(started);
    appendData("function foo() {");
    appendData("this is the part which will be a parse error");
    // V8 won't realize the parse error until it actually starts parsing the
    // script, and this happens only when its buffer is filled.
    appendPadding();

    EXPECT_FALSE(client.finished());

    // Force the V8 side to finish before the loading.
    processTasksUntilStreamingComplete();
    EXPECT_FALSE(client.finished());

    finish();
    EXPECT_TRUE(client.finished());

    bool errorOccurred = false;
    ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurred);
    EXPECT_FALSE(errorOccurred);
    EXPECT_TRUE(sourceCode.streamer());
    v8::TryCatch tryCatch;
    v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, isolate());
    EXPECT_TRUE(script.IsEmpty());
    EXPECT_TRUE(tryCatch.HasCaught());
}

TEST_F(ScriptStreamingTest, CancellingStreaming)
{
    // Test that the upper layers (PendingScript and up) can be ramped down
    // while streaming is ongoing, and ScriptStreamer handles it gracefully.
    bool started = ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.scriptState());
    TestScriptResourceClient client;
    pendingScript().watchForLoad(&client);
    EXPECT_TRUE(started);
    appendData("function foo() {");

    // In general, we cannot control what the background thread is doing
    // (whether it's parsing or waiting for more data). In this test, we have
    // given it so little data that it's surely waiting for more.

    // Simulate cancelling the network load (e.g., because the user navigated
    // away).
    EXPECT_FALSE(client.finished());
    pendingScript().stopWatchingForLoad(&client);
    m_pendingScript = PendingScriptWrapper::create(); // This will destroy m_resource.
    m_resource = 0;

    // The V8 side will complete too. This should not crash. We don't receive
    // any results from the streaming and the client doesn't get notified.
    processTasksUntilStreamingComplete();
    EXPECT_FALSE(client.finished());
}

TEST_F(ScriptStreamingTest, SuppressingStreaming)
{
    // If we notice during streaming that there is a code cache, streaming
    // is suppressed (V8 doesn't parse while the script is loading), and the
    // upper layer (ScriptResourceClient) should get a notification when the
    // script is loaded.
    bool started = ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.scriptState());
    TestScriptResourceClient client;
    pendingScript().watchForLoad(&client);
    EXPECT_TRUE(started);
    appendData("function foo() {");
    appendPadding();

    m_resource->setCachedMetadata(V8ScriptRunner::tagForCodeCache(), "X", 1, Resource::CacheLocally);

    appendPadding();
    finish();
    processTasksUntilStreamingComplete();
    EXPECT_TRUE(client.finished());

    bool errorOccurred = false;
    ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurred);
    EXPECT_FALSE(errorOccurred);
    // ScriptSourceCode doesn't refer to the streamer, since we have suppressed
    // the streaming and resumed the non-streaming code path for script
    // compilation.
    EXPECT_FALSE(sourceCode.streamer());
}

} // namespace

} // namespace blink
<|endoftext|>