<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief V8 shell functions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "v8-shell.h"

#include "Basics/conversions.h"
#include "Basics/csv.h"
#include "Basics/logging.h"
#include "Basics/shell-colors.h"
#include "Basics/string-buffer.h"
#include "Basics/tri-strings.h"
#include "ShapedJson/shaped-json.h"

#include "V8/v8-globals.h"
#include "V8/v8-conv.h"
#include "V8/v8-json.h"
#include "V8/v8-utils.h"

using namespace std;

// -----------------------------------------------------------------------------
// --SECTION--                                                   IMPORT / EXPORT
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief begins a new CSV line
////////////////////////////////////////////////////////////////////////////////

static void ProcessCsvBegin (TRI_csv_parser_t* parser, size_t row) {
  v8::Handle<v8::Array>* array = reinterpret_cast<v8::Handle<v8::Array>*>(parser->_dataBegin);

  (*array) = v8::Array::New();
}

////////////////////////////////////////////////////////////////////////////////
/// @brief adds a new CSV field
////////////////////////////////////////////////////////////////////////////////

static void ProcessCsvAdd (TRI_csv_parser_t* parser, const char* field, size_t, size_t row, size_t column, bool escaped) {
  v8::Handle<v8::Array>* array = reinterpret_cast<v8::Handle<v8::Array>*>(parser->_dataBegin);

  (*array)->Set((uint32_t) column, v8::String::New(field));
}

////////////////////////////////////////////////////////////////////////////////
/// @brief ends a CSV line
////////////////////////////////////////////////////////////////////////////////

static void ProcessCsvEnd (TRI_csv_parser_t* parser, const char* field, size_t, size_t row, size_t column, bool escaped) {
  v8::Handle<v8::Array>* array = reinterpret_cast<v8::Handle<v8::Array>*>(parser->_dataBegin);

  (*array)->Set((uint32_t) column, v8::String::New(field));

  v8::Handle<v8::Function>* cb = reinterpret_cast<v8::Handle<v8::Function>*>(parser->_dataEnd);
  v8::Handle<v8::Number> r = v8::Integer::New((int) row);

  v8::Handle<v8::Value> args[] = { *array, r };
  (*cb)->Call(*cb, 2, args);
}

// -----------------------------------------------------------------------------
// --SECTION--                                                      JS functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief processes a CSV file
///
/// @FUN{processCsvFile(@FA{filename}, @FA{callback})}
///
/// Processes a CSV file. The @FA{callback} function is called for line in the
/// file. The seperator is @LIT{\,} and the quote is @LIT{"}.
///
/// Create the input file @LIT{csv.txt}
///
/// @verbinclude fluent48
///
/// If you use @FN{processCsvFile} on this file, you get
///
/// @verbinclude fluent47
///
/// @FUN{processCsvFile(@FA{filename}, @FA{callback}, @FA{options})}
///
/// Processes a CSV file. The @FA{callback} function is called for line in the
/// file. The @FA{options} argument must be an object. The value of
/// @LIT{seperator} sets the seperator character and @LIT{quote} the quote
/// character.
////////////////////////////////////////////////////////////////////////////////

static v8::Handle<v8::Value> JS_ProcessCsvFile (v8::Arguments const& argv) {
  v8::HandleScope scope;

  if (argv.Length() < 2) {
    TRI_V8_EXCEPTION_USAGE(scope, "processCsvFile(<filename>, <callback>[, <options>])");
  }

  // extract the filename
  TRI_Utf8ValueNFC filename(TRI_UNKNOWN_MEM_ZONE, argv[0]);

  if (*filename == 0) {
    TRI_V8_TYPE_ERROR(scope, "<filename> must be an UTF8 filename");
  }

  // extract the callback
  v8::Handle<v8::Function> cb = v8::Handle<v8::Function>::Cast(argv[1]);

  // extract the options
  v8::Handle<v8::String> separatorKey = v8::String::New("separator");
  v8::Handle<v8::String> quoteKey = v8::String::New("quote");

  string separator = ",";
  string quote = "\"";

  if (3 <= argv.Length()) {
    v8::Handle<v8::Object> options = argv[2]->ToObject();

    // separator
    if (options->Has(separatorKey)) {
      separator = TRI_ObjectToString(options->Get(separatorKey));

      if (separator.size() != 1) {
        TRI_V8_TYPE_ERROR(scope, "<options>.separator must be exactly one character");
      }
    }

    // quote
    if (options->Has(quoteKey)) {
      quote = TRI_ObjectToString(options->Get(quoteKey));

      if (quote.length() > 1) {
        TRI_V8_TYPE_ERROR(scope, "<options>.quote must be at most one character");
      }
    }
  }

  // read and convert
  int fd = TRI_OPEN(*filename, O_RDONLY);

  if (fd < 0) {
    TRI_V8_EXCEPTION_SYS(scope, "cannot open file");
  }

  TRI_csv_parser_t parser;

  TRI_InitCsvParser(&parser,
                    TRI_UNKNOWN_MEM_ZONE,
                    ProcessCsvBegin,
                    ProcessCsvAdd,
                    ProcessCsvEnd);

  TRI_SetSeparatorCsvParser(&parser, separator[0]);
  if (quote.length() > 0) {
    TRI_SetQuoteCsvParser(&parser, quote[0], true);
  }
  else {
    TRI_SetQuoteCsvParser(&parser, '\0', false);
  }

  parser._dataEnd = &cb;

  v8::Handle<v8::Array> array;
  parser._dataBegin = &array;

  char buffer[10240];

  while (true) {
    v8::HandleScope scope;

    ssize_t n = TRI_READ(fd, buffer, sizeof(buffer));

    if (n < 0) {
      TRI_DestroyCsvParser(&parser);
      TRI_CLOSE(fd);
      TRI_V8_EXCEPTION_SYS(scope, "cannot read file");
    }
    else if (n == 0) {
      TRI_DestroyCsvParser(&parser);
      break;
    }

    TRI_ParseCsvString2(&parser, buffer, n);
  }

  TRI_CLOSE(fd);

  return scope.Close(v8::Undefined());
}

////////////////////////////////////////////////////////////////////////////////
/// @brief processes a JSON file
///
/// @FUN{processJsonFile(@FA{filename}, @FA{callback})}
///
/// Processes a JSON file. The file must contain the JSON objects each on its
/// own line. The @FA{callback} function is called for each object.
///
/// Create the input file @LIT{json.txt}
///
/// @verbinclude fluent49
///
/// If you use @FN{processJsonFile} on this file, you get
///
/// @verbinclude fluent50
///
////////////////////////////////////////////////////////////////////////////////

static v8::Handle<v8::Value> JS_ProcessJsonFile (v8::Arguments const& argv) {
  v8::HandleScope scope;

  if (argv.Length() < 2) {
    TRI_V8_EXCEPTION_USAGE(scope, "processJsonFile(<filename>, <callback>)");
  }

  // extract the filename
  TRI_Utf8ValueNFC filename(TRI_UNKNOWN_MEM_ZONE, argv[0]);

  if (*filename == 0) {
    TRI_V8_TYPE_ERROR(scope, "<filename> must be an UTF8 filename");
  }

  // extract the callback
  v8::Handle<v8::Function> cb = v8::Handle<v8::Function>::Cast(argv[1]);

  // read and convert
  string line;
  ifstream file(*filename);

  if (file.is_open()) {
    size_t row = 0;

    while (file.good()) {
      v8::HandleScope scope;

      getline(file, line);

      const char* ptr = line.c_str();
      const char* end = ptr + line.length();

      while (ptr < end && (*ptr == ' ' || *ptr == '\t' || *ptr == '\r')) {
        ++ptr;
      }

      if (ptr == end) {
        continue;
      }

      char* error = 0;
      v8::Handle<v8::Value> object = TRI_FromJsonString(line.c_str(), &error);

      if (object->IsUndefined()) {
        if (error != 0) {
          string msg = error;
          TRI_FreeString(TRI_CORE_MEM_ZONE, error);
          TRI_V8_SYNTAX_ERROR(scope, msg.c_str());
        }
        else {
          TRI_V8_EXCEPTION(scope, TRI_ERROR_OUT_OF_MEMORY);
        }
      }

      if (error != 0) {
        TRI_FreeString(TRI_CORE_MEM_ZONE, error);
      }

      v8::Handle<v8::Number> r = v8::Integer::New((int) row);
      v8::Handle<v8::Value> args[] = { object, r };
      cb->Call(cb, 2, args);

      row++;
    }

    file.close();
  }
  else {
    TRI_V8_EXCEPTION_SYS(scope, "cannot open file");
  }

  return scope.Close(v8::Undefined());
}

// -----------------------------------------------------------------------------
// --SECTION--                                                           GENERAL
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                             module initialisation
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief stores the V8 shell functions inside the global variable
////////////////////////////////////////////////////////////////////////////////

void TRI_InitV8Shell (v8::Handle<v8::Context> context) {
  v8::HandleScope scope;

  // .............................................................................
  // create the global functions
  // .............................................................................

  TRI_AddGlobalFunctionVocbase(context, "SYS_PROCESS_CSV_FILE", JS_ProcessCsvFile);
  TRI_AddGlobalFunctionVocbase(context, "SYS_PROCESS_JSON_FILE", JS_ProcessJsonFile);

  bool isTty = (isatty(STDOUT_FILENO) != 0);

  // .............................................................................
  // create the global variables
  // .............................................................................

  v8::Handle<v8::Object> colors = v8::Object::New();

  colors->Set(TRI_V8_STRING("COLOR_RED"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_RED) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_RED"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_RED) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_GREEN"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_GREEN) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_GREEN"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_GREEN) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BLUE"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BLUE) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_BLUE"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_BLUE) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_YELLOW"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_YELLOW) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_YELLOW"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_YELLOW) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_WHITE"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_WHITE) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_WHITE"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_WHITE) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_CYAN"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_CYAN) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_CYAN"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_CYAN) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_MAGENTA"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_MAGENTA) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_MAGENTA"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_MAGENTA) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BLACK"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BLACK) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_BLACK"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_BLACK) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BLINK"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BLINK) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BRIGHT"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BRIGHT) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_RESET"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_RESET) : v8::String::Empty(),
              v8::ReadOnly);

  TRI_AddGlobalVariableVocbase(context, "COLORS", colors);
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<commit_msg>added comment<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief V8 shell functions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "v8-shell.h"

#include "Basics/conversions.h"
#include "Basics/csv.h"
#include "Basics/logging.h"
#include "Basics/shell-colors.h"
#include "Basics/string-buffer.h"
#include "Basics/tri-strings.h"
#include "ShapedJson/shaped-json.h"

#include "V8/v8-globals.h"
#include "V8/v8-conv.h"
#include "V8/v8-json.h"
#include "V8/v8-utils.h"

using namespace std;

// -----------------------------------------------------------------------------
// --SECTION--                                                   IMPORT / EXPORT
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief begins a new CSV line
////////////////////////////////////////////////////////////////////////////////

static void ProcessCsvBegin (TRI_csv_parser_t* parser, size_t row) {
  v8::Handle<v8::Array>* array = reinterpret_cast<v8::Handle<v8::Array>*>(parser->_dataBegin);

  (*array) = v8::Array::New();
}

////////////////////////////////////////////////////////////////////////////////
/// @brief adds a new CSV field
////////////////////////////////////////////////////////////////////////////////

static void ProcessCsvAdd (TRI_csv_parser_t* parser, const char* field, size_t, size_t row, size_t column, bool escaped) {
  v8::Handle<v8::Array>* array = reinterpret_cast<v8::Handle<v8::Array>*>(parser->_dataBegin);

  (*array)->Set((uint32_t) column, v8::String::New(field));
}

////////////////////////////////////////////////////////////////////////////////
/// @brief ends a CSV line
////////////////////////////////////////////////////////////////////////////////

static void ProcessCsvEnd (TRI_csv_parser_t* parser, const char* field, size_t, size_t row, size_t column, bool escaped) {
  v8::Handle<v8::Array>* array = reinterpret_cast<v8::Handle<v8::Array>*>(parser->_dataBegin);

  (*array)->Set((uint32_t) column, v8::String::New(field));

  v8::Handle<v8::Function>* cb = reinterpret_cast<v8::Handle<v8::Function>*>(parser->_dataEnd);
  v8::Handle<v8::Number> r = v8::Integer::New((int) row);

  v8::Handle<v8::Value> args[] = { *array, r };
  (*cb)->Call(*cb, 2, args);
}

// -----------------------------------------------------------------------------
// --SECTION--                                                      JS functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief processes a CSV file
///
/// @FUN{processCsvFile(@FA{filename}, @FA{callback})}
///
/// Processes a CSV file. The @FA{callback} function is called for line in the
/// file. The seperator is @LIT{\,} and the quote is @LIT{"}.
///
/// Create the input file @LIT{csv.txt}
///
/// @verbinclude fluent48
///
/// If you use @FN{processCsvFile} on this file, you get
///
/// @verbinclude fluent47
///
/// @FUN{processCsvFile(@FA{filename}, @FA{callback}, @FA{options})}
///
/// Processes a CSV file. The @FA{callback} function is called for line in the
/// file. The @FA{options} argument must be an object. The value of
/// @LIT{seperator} sets the seperator character and @LIT{quote} the quote
/// character.
////////////////////////////////////////////////////////////////////////////////

static v8::Handle<v8::Value> JS_ProcessCsvFile (v8::Arguments const& argv) {
  v8::HandleScope scope;

  if (argv.Length() < 2) {
    TRI_V8_EXCEPTION_USAGE(scope, "processCsvFile(<filename>, <callback>[, <options>])");
  }

  // extract the filename
  TRI_Utf8ValueNFC filename(TRI_UNKNOWN_MEM_ZONE, argv[0]);

  if (*filename == 0) {
    TRI_V8_TYPE_ERROR(scope, "<filename> must be an UTF8 filename");
  }

  // extract the callback
  v8::Handle<v8::Function> cb = v8::Handle<v8::Function>::Cast(argv[1]);

  // extract the options
  v8::Handle<v8::String> separatorKey = v8::String::New("separator");
  v8::Handle<v8::String> quoteKey = v8::String::New("quote");

  string separator = ",";
  string quote = "\"";

  if (3 <= argv.Length()) {
    v8::Handle<v8::Object> options = argv[2]->ToObject();

    // separator
    if (options->Has(separatorKey)) {
      separator = TRI_ObjectToString(options->Get(separatorKey));

      if (separator.size() != 1) {
        TRI_V8_TYPE_ERROR(scope, "<options>.separator must be exactly one character");
      }
    }

    // quote
    if (options->Has(quoteKey)) {
      quote = TRI_ObjectToString(options->Get(quoteKey));

      if (quote.length() > 1) {
        TRI_V8_TYPE_ERROR(scope, "<options>.quote must be at most one character");
      }
    }
  }

  // read and convert
  int fd = TRI_OPEN(*filename, O_RDONLY);

  if (fd < 0) {
    TRI_V8_EXCEPTION_SYS(scope, "cannot open file");
  }

  TRI_csv_parser_t parser;

  TRI_InitCsvParser(&parser,
                    TRI_UNKNOWN_MEM_ZONE,
                    ProcessCsvBegin,
                    ProcessCsvAdd,
                    ProcessCsvEnd);

  TRI_SetSeparatorCsvParser(&parser, separator[0]);
  if (quote.length() > 0) {
    TRI_SetQuoteCsvParser(&parser, quote[0], true);
  }
  else {
    TRI_SetQuoteCsvParser(&parser, '\0', false);
  }

  parser._dataEnd = &cb;

  v8::Handle<v8::Array> array;
  parser._dataBegin = &array;

  char buffer[10240];

  while (true) {
    v8::HandleScope scope;

    ssize_t n = TRI_READ(fd, buffer, sizeof(buffer));

    if (n < 0) {
      TRI_DestroyCsvParser(&parser);
      TRI_CLOSE(fd);
      TRI_V8_EXCEPTION_SYS(scope, "cannot read file");
    }
    else if (n == 0) {
      TRI_DestroyCsvParser(&parser);
      break;
    }

    TRI_ParseCsvString2(&parser, buffer, n);
  }

  TRI_CLOSE(fd);

  return scope.Close(v8::Undefined());
}

////////////////////////////////////////////////////////////////////////////////
/// @brief processes a JSON file
///
/// @FUN{processJsonFile(@FA{filename}, @FA{callback})}
///
/// Processes a JSON file. The file must contain the JSON objects each on its
/// own line. The @FA{callback} function is called for each object.
///
/// Create the input file @LIT{json.txt}
///
/// @verbinclude fluent49
///
/// If you use @FN{processJsonFile} on this file, you get
///
/// @verbinclude fluent50
///
////////////////////////////////////////////////////////////////////////////////

static v8::Handle<v8::Value> JS_ProcessJsonFile (v8::Arguments const& argv) {
  v8::HandleScope scope;

  if (argv.Length() < 2) {
    TRI_V8_EXCEPTION_USAGE(scope, "processJsonFile(<filename>, <callback>)");
  }

  // extract the filename
  TRI_Utf8ValueNFC filename(TRI_UNKNOWN_MEM_ZONE, argv[0]);

  if (*filename == 0) {
    TRI_V8_TYPE_ERROR(scope, "<filename> must be an UTF8 filename");
  }

  // extract the callback
  v8::Handle<v8::Function> cb = v8::Handle<v8::Function>::Cast(argv[1]);

  // read and convert
  string line;
  ifstream file(*filename);

  if (file.is_open()) {
    size_t row = 0;

    while (file.good()) {
      v8::HandleScope scope;

      getline(file, line);

      const char* ptr = line.c_str();
      const char* end = ptr + line.length();

      while (ptr < end && (*ptr == ' ' || *ptr == '\t' || *ptr == '\r')) {
        ++ptr;
      }

      if (ptr == end) {
        continue;
      }

      char* error = 0;
      v8::Handle<v8::Value> object = TRI_FromJsonString(line.c_str(), &error);

      if (object->IsUndefined()) {
        if (error != 0) {
          string msg = error;
          TRI_FreeString(TRI_CORE_MEM_ZONE, error);
          TRI_V8_SYNTAX_ERROR(scope, msg.c_str());
        }
        else {
          TRI_V8_EXCEPTION(scope, TRI_ERROR_OUT_OF_MEMORY);
        }
      }

      if (error != 0) {
        TRI_FreeString(TRI_CORE_MEM_ZONE, error);
      }

      v8::Handle<v8::Number> r = v8::Integer::New((int) row);
      v8::Handle<v8::Value> args[] = { object, r };
      cb->Call(cb, 2, args);

      row++;
    }

    file.close();
  }
  else {
    TRI_V8_EXCEPTION_SYS(scope, "cannot open file");
  }

  return scope.Close(v8::Undefined());
}

// -----------------------------------------------------------------------------
// --SECTION--                                                           GENERAL
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                             module initialisation
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief stores the V8 shell functions inside the global variable
////////////////////////////////////////////////////////////////////////////////

void TRI_InitV8Shell (v8::Handle<v8::Context> context) {
  v8::HandleScope scope;

  // .............................................................................
  // create the global functions
  // .............................................................................

  TRI_AddGlobalFunctionVocbase(context, "SYS_PROCESS_CSV_FILE", JS_ProcessCsvFile);
  TRI_AddGlobalFunctionVocbase(context, "SYS_PROCESS_JSON_FILE", JS_ProcessJsonFile);

  bool isTty = (isatty(STDOUT_FILENO) != 0);
  // on Linux, isatty() == 0 may also indicate an error. we can ignore this safely
  // because if isatty returns an error we should not assume we're printing on a
  // terminal

  // .............................................................................
  // create the global variables
  // .............................................................................

  v8::Handle<v8::Object> colors = v8::Object::New();

  colors->Set(TRI_V8_STRING("COLOR_RED"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_RED) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_RED"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_RED) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_GREEN"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_GREEN) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_GREEN"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_GREEN) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BLUE"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BLUE) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_BLUE"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_BLUE) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_YELLOW"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_YELLOW) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_YELLOW"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_YELLOW) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_WHITE"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_WHITE) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_WHITE"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_WHITE) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_CYAN"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_CYAN) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_CYAN"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_CYAN) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_MAGENTA"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_MAGENTA) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_MAGENTA"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_MAGENTA) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BLACK"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BLACK) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BOLD_BLACK"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BOLD_BLACK) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BLINK"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BLINK) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_BRIGHT"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_BRIGHT) : v8::String::Empty(),
              v8::ReadOnly);

  colors->Set(TRI_V8_STRING("COLOR_RESET"),
              isTty ? TRI_V8_STRING(TRI_SHELL_COLOR_RESET) : v8::String::Empty(),
              v8::ReadOnly);

  TRI_AddGlobalVariableVocbase(context, "COLORS", colors);
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<|endoftext|>


<commit_before>#ifndef TESTERDRIVER_H
#define TESTERDRIVER_H

#include <iostream>
#include <string.h>
using namespace std;
#include "wrapperregdriver.h"
#include "TesterWrapper.h"

// enable verbose reg read/writes and Chisel HW printfs
// remember to compile with -std=c++11 for Chisel HW printfs to work
#ifdef DEBUG
#warning "Compiling emulation with full debug support"
#define __TESTERDRIVER_DEBUG_PRINT(x) (cout << x << endl)
#define __TESTERDRIVER_DEBUG(x) (x)
#elif DEBUG_HW
#warning "Compiling emulation with Chisel printf support"
#define __TESTERDRIVER_DEBUG_PRINT(x) (0)
#define __TESTERDRIVER_DEBUG(x) (x)
#else
#define __TESTERDRIVER_DEBUG_PRINT(x) (0)
#define __TESTERDRIVER_DEBUG(x) (0)
#endif

// register driver for the Tester platform, using the Chisel-generated C++ model to
// interface with the accelerator model
// note that TesterWrapper.h must be generated for each new accelerator, it is the
// model header not just for the wrapper, but the entire system (wrapper+accel)

class TesterRegDriver : public WrapperRegDriver {
public:
  TesterRegDriver() {m_inst = 0; m_freePtr = 0;}

  virtual void attach(const char * name) {
    m_inst = new TesterWrapper_t();
    // get # words in the memory
    m_memWords = m_inst->TesterWrapper__mem.length();
    // initialize and reset the model
    m_inst->init();
    reset();
    m_regCount = m_inst->TesterWrapper__io_regFileIF_regCount.to_ulong();
  }

  virtual void detach() {
    if(m_inst) {
      delete m_inst;
      m_inst = 0;
    }
  }

  virtual void copyBufferHostToAccel(void * hostBuffer, void * accelBuffer, unsigned int numBytes) {
    uint64_t accelBufBase = (uint64_t) accelBuffer;
    __TESTERDRIVER_DEBUG_PRINT("host2accel(" << (uint64_t) hostBuffer << " -> " << accelBufBase << " : " << numBytes << " bytes)");

    if((numBytes % 8 == 0) && (accelBufBase % 8 == 0))
      alignedCopyBufferHostToAccel(hostBuffer, accelBuffer, numBytes);
    else {
      // align base and size
      uint64_t alignedBase = accelBufBase - (accelBufBase % 8);
      uint64_t startDiff = accelBufBase - alignedBase;
      unsigned int alignedSize = (startDiff + numBytes + 7) / 8 * 8;
      // copy containing block into host memory
      char * tmp = new char[alignedSize];
      alignedCopyBufferAccelToHost((void *)alignedBase, (void *) tmp, alignedSize);
      // do host-to-host unaligned copy
      memcpy((void *)&tmp[startDiff], hostBuffer, numBytes);
      // write containing block back to accel memory
      alignedCopyBufferHostToAccel((void *)tmp, (void *)alignedBase, alignedSize);
      delete [] tmp;
    }
  }

  virtual void copyBufferAccelToHost(void * accelBuffer, void * hostBuffer, unsigned int numBytes) {
    uint64_t accelBufBase = (uint64_t) accelBuffer;
    __TESTERDRIVER_DEBUG_PRINT("accel2host(" << accelBufBase << " -> " << (uint64_t) hostBuffer << " : " << numBytes << " bytes)");

    if((numBytes % 8 == 0) && (accelBufBase % 8 == 0))
      alignedCopyBufferAccelToHost(accelBuffer, hostBuffer, numBytes);
    else {
      // implement unaligned accel-to-host
      // align base and size
      uint64_t alignedBase = accelBufBase - (accelBufBase % 8);
      uint64_t startDiff = accelBufBase - alignedBase;
      unsigned int alignedSize = (startDiff + numBytes + 7) / 8 * 8;
      // copy containing block into host memory
      char * tmp = new char[alignedSize];
      alignedCopyBufferAccelToHost((void *)alignedBase, (void *) tmp, alignedSize);
      // do host-to-host unaligned copy
      memcpy(hostBuffer, (void *)&tmp[startDiff],numBytes);
      delete [] tmp;
    }
  }

  virtual void * allocAccelBuffer(unsigned int numBytes) {
    // all this assumes allocation and mem word size of 8 bytes
    // round requested size to nearest multiple of 8
    unsigned int actualAllocSize = (numBytes + 7) / 8 * 8;
    void * accelBuf = (void *) m_freePtr;
    // update free pointer and sanity check
    m_freePtr += actualAllocSize;
    if(m_freePtr > m_memWords * 8)
      throw "Not enough memory in allocAccelBuffer";
    __TESTERDRIVER_DEBUG_PRINT("allocAccelBuffer(" << numBytes << ", alloc " << actualAllocSize <<") = " << (uint64_t) accelBuf);

    return accelBuf;
  }

  // register access methods for the platform wrapper
  virtual void writeReg(unsigned int regInd, AccelReg regValue) {
    __TESTERDRIVER_DEBUG_PRINT("writeReg(" << regInd << ", " << regValue  << ") ");

    m_inst->TesterWrapper__io_regFileIF_cmd_bits_writeData = regValue;
    m_inst->TesterWrapper__io_regFileIF_cmd_bits_write  = 1;
    m_inst->TesterWrapper__io_regFileIF_cmd_bits_regID = regInd;
    m_inst->TesterWrapper__io_regFileIF_cmd_valid = 1;
    step();
    m_inst->TesterWrapper__io_regFileIF_cmd_valid = 0;
    m_inst->TesterWrapper__io_regFileIF_cmd_bits_write = 0;
    step(5);  // extra delay on write completion to be realistic
  }

  virtual AccelReg readReg(unsigned int regInd) {
    AccelReg ret;

    m_inst->TesterWrapper__io_regFileIF_cmd_bits_regID = regInd;
    m_inst->TesterWrapper__io_regFileIF_cmd_valid = 1;
    m_inst->TesterWrapper__io_regFileIF_cmd_bits_read = 1;
    step(); // don't actually need 1 cycle, regfile reads are combinational

    if(!m_inst->TesterWrapper__io_regFileIF_readData_valid.to_bool())
      throw "Could not read register";

    m_inst->TesterWrapper__io_regFileIF_cmd_valid = 0;
    m_inst->TesterWrapper__io_regFileIF_cmd_bits_read = 0;

    ret = m_inst->TesterWrapper__io_regFileIF_readData_bits.to_ulong();

    __TESTERDRIVER_DEBUG_PRINT("readReg(" << regInd << ") = " << ret);

    step(5);  // extra delay on read completion to be realistic

    return ret;
  }

  void printAllRegs() {
    for(unsigned int i = 0; i < m_regCount; i++)  {
        AccelReg val = readReg(i);
        cout << "Reg " << i << " = " << val << " (0x" << hex << val << dec << ")" << endl;
      }

  }

protected:
  TesterWrapper_t * m_inst;
  unsigned int m_memWords;
  unsigned int m_regCount;
  uint64_t m_freePtr;

  void reset() {
    m_inst->clock(1);
    m_inst->clock(0);
    // Chisel c++ backend requires this workaround to get out the correct values
    m_inst->clock_lo(0);
  }

  void step(int n = 1) {
    for(int i = 0; i < n; i++) {
      m_inst->clock(0);
      // Chisel c++ backend requires this workaround to get out the correct values
      m_inst->clock_lo(0);
      __TESTERDRIVER_DEBUG(m_inst->print(cout));
    }
  }

  void memWrite(uint64_t addr, uint64_t value) {
    m_inst->TesterWrapper__io_memAddr = addr;
    m_inst->TesterWrapper__io_memWriteData = value;
    m_inst->TesterWrapper__io_memWriteEn = 1;
    step();
    m_inst->TesterWrapper__io_memWriteEn = 0;
  }

  uint64_t memRead(uint64_t addr) {
    m_inst->TesterWrapper__io_memAddr = addr;
    step();
    uint64_t ret = m_inst->TesterWrapper__io_memReadData[0];
    return ret;
  }

  // "aligned" copy functions, where accel ptr start and size are guaranteed to be 8-aligned
  void alignedCopyBufferHostToAccel(void * hostBuffer, void * accelBuffer, unsigned int numBytes) {
    uint64_t * host_buf = (uint64_t *) hostBuffer;
    uint64_t accelBufBase = (uint64_t) accelBuffer;
    for(unsigned int i = 0; i < numBytes/8; i++)
        memWrite(accelBufBase + i*8, host_buf[i]);
  }

  void alignedCopyBufferAccelToHost(void * accelBuffer, void * hostBuffer, unsigned int numBytes) {
    uint64_t accelBufBase = (uint64_t) accelBuffer;
    uint64_t * readBuf = (uint64_t *) hostBuffer;
    for(unsigned int i = 0; i < numBytes/8; i++)
      readBuf[i] = memRead(accelBufBase + i*8);
  }
};

#endif
<commit_msg>return 64b-aligned mem in TesterWrapper<commit_after>#ifndef TESTERDRIVER_H
#define TESTERDRIVER_H

#include <iostream>
#include <string.h>
using namespace std;
#include "wrapperregdriver.h"
#include "TesterWrapper.h"

// enable verbose reg read/writes and Chisel HW printfs
// remember to compile with -std=c++11 for Chisel HW printfs to work
#ifdef DEBUG
#warning "Compiling emulation with full debug support"
#define __TESTERDRIVER_DEBUG_PRINT(x) (cout << x << endl)
#define __TESTERDRIVER_DEBUG(x) (x)
#elif DEBUG_HW
#warning "Compiling emulation with Chisel printf support"
#define __TESTERDRIVER_DEBUG_PRINT(x) (0)
#define __TESTERDRIVER_DEBUG(x) (x)
#else
#define __TESTERDRIVER_DEBUG_PRINT(x) (0)
#define __TESTERDRIVER_DEBUG(x) (0)
#endif

// register driver for the Tester platform, using the Chisel-generated C++ model to
// interface with the accelerator model
// note that TesterWrapper.h must be generated for each new accelerator, it is the
// model header not just for the wrapper, but the entire system (wrapper+accel)

class TesterRegDriver : public WrapperRegDriver {
public:
  TesterRegDriver() {m_inst = 0; m_freePtr = 0;}

  virtual void attach(const char * name) {
    m_inst = new TesterWrapper_t();
    // get # words in the memory
    m_memWords = m_inst->TesterWrapper__mem.length();
    // initialize and reset the model
    m_inst->init();
    reset();
    m_regCount = m_inst->TesterWrapper__io_regFileIF_regCount.to_ulong();
  }

  virtual void detach() {
    if(m_inst) {
      delete m_inst;
      m_inst = 0;
    }
  }

  virtual void copyBufferHostToAccel(void * hostBuffer, void * accelBuffer, unsigned int numBytes) {
    uint64_t accelBufBase = (uint64_t) accelBuffer;
    __TESTERDRIVER_DEBUG_PRINT("host2accel(" << (uint64_t) hostBuffer << " -> " << accelBufBase << " : " << numBytes << " bytes)");

    if((numBytes % 8 == 0) && (accelBufBase % 8 == 0))
      alignedCopyBufferHostToAccel(hostBuffer, accelBuffer, numBytes);
    else {
      // align base and size
      uint64_t alignedBase = accelBufBase - (accelBufBase % 8);
      uint64_t startDiff = accelBufBase - alignedBase;
      unsigned int alignedSize = (startDiff + numBytes + 7) / 8 * 8;
      // copy containing block into host memory
      char * tmp = new char[alignedSize];
      alignedCopyBufferAccelToHost((void *)alignedBase, (void *) tmp, alignedSize);
      // do host-to-host unaligned copy
      memcpy((void *)&tmp[startDiff], hostBuffer, numBytes);
      // write containing block back to accel memory
      alignedCopyBufferHostToAccel((void *)tmp, (void *)alignedBase, alignedSize);
      delete [] tmp;
    }
  }

  virtual void copyBufferAccelToHost(void * accelBuffer, void * hostBuffer, unsigned int numBytes) {
    uint64_t accelBufBase = (uint64_t) accelBuffer;
    __TESTERDRIVER_DEBUG_PRINT("accel2host(" << accelBufBase << " -> " << (uint64_t) hostBuffer << " : " << numBytes << " bytes)");

    if((numBytes % 8 == 0) && (accelBufBase % 8 == 0))
      alignedCopyBufferAccelToHost(accelBuffer, hostBuffer, numBytes);
    else {
      // implement unaligned accel-to-host
      // align base and size
      uint64_t alignedBase = accelBufBase - (accelBufBase % 8);
      uint64_t startDiff = accelBufBase - alignedBase;
      unsigned int alignedSize = (startDiff + numBytes + 7) / 8 * 8;
      // copy containing block into host memory
      char * tmp = new char[alignedSize];
      alignedCopyBufferAccelToHost((void *)alignedBase, (void *) tmp, alignedSize);
      // do host-to-host unaligned copy
      memcpy(hostBuffer, (void *)&tmp[startDiff],numBytes);
      delete [] tmp;
    }
  }

  virtual void * allocAccelBuffer(unsigned int numBytes) {
    // all this assumes allocation and mem word size of 64 bytes
    // round requested size to nearest multiple of 64
    unsigned int actualAllocSize = (numBytes + 63) / 64 * 64;
    void * accelBuf = (void *) m_freePtr;
    // update free pointer and sanity check
    m_freePtr += actualAllocSize;
    if(m_freePtr > m_memWords * 8)
      throw "Not enough memory in allocAccelBuffer";
    __TESTERDRIVER_DEBUG_PRINT("allocAccelBuffer(" << numBytes << ", alloc " << actualAllocSize <<") = " << (uint64_t) accelBuf);

    return accelBuf;
  }

  // register access methods for the platform wrapper
  virtual void writeReg(unsigned int regInd, AccelReg regValue) {
    __TESTERDRIVER_DEBUG_PRINT("writeReg(" << regInd << ", " << regValue  << ") ");

    m_inst->TesterWrapper__io_regFileIF_cmd_bits_writeData = regValue;
    m_inst->TesterWrapper__io_regFileIF_cmd_bits_write  = 1;
    m_inst->TesterWrapper__io_regFileIF_cmd_bits_regID = regInd;
    m_inst->TesterWrapper__io_regFileIF_cmd_valid = 1;
    step();
    m_inst->TesterWrapper__io_regFileIF_cmd_valid = 0;
    m_inst->TesterWrapper__io_regFileIF_cmd_bits_write = 0;
    step(5);  // extra delay on write completion to be realistic
  }

  virtual AccelReg readReg(unsigned int regInd) {
    AccelReg ret;

    m_inst->TesterWrapper__io_regFileIF_cmd_bits_regID = regInd;
    m_inst->TesterWrapper__io_regFileIF_cmd_valid = 1;
    m_inst->TesterWrapper__io_regFileIF_cmd_bits_read = 1;
    step(); // don't actually need 1 cycle, regfile reads are combinational

    if(!m_inst->TesterWrapper__io_regFileIF_readData_valid.to_bool())
      throw "Could not read register";

    m_inst->TesterWrapper__io_regFileIF_cmd_valid = 0;
    m_inst->TesterWrapper__io_regFileIF_cmd_bits_read = 0;

    ret = m_inst->TesterWrapper__io_regFileIF_readData_bits.to_ulong();

    __TESTERDRIVER_DEBUG_PRINT("readReg(" << regInd << ") = " << ret);

    step(5);  // extra delay on read completion to be realistic

    return ret;
  }

  void printAllRegs() {
    for(unsigned int i = 0; i < m_regCount; i++)  {
        AccelReg val = readReg(i);
        cout << "Reg " << i << " = " << val << " (0x" << hex << val << dec << ")" << endl;
      }

  }

protected:
  TesterWrapper_t * m_inst;
  unsigned int m_memWords;
  unsigned int m_regCount;
  uint64_t m_freePtr;

  void reset() {
    m_inst->clock(1);
    m_inst->clock(0);
    // Chisel c++ backend requires this workaround to get out the correct values
    m_inst->clock_lo(0);
  }

  void step(int n = 1) {
    for(int i = 0; i < n; i++) {
      m_inst->clock(0);
      // Chisel c++ backend requires this workaround to get out the correct values
      m_inst->clock_lo(0);
      __TESTERDRIVER_DEBUG(m_inst->print(cout));
    }
  }

  void memWrite(uint64_t addr, uint64_t value) {
    m_inst->TesterWrapper__io_memAddr = addr;
    m_inst->TesterWrapper__io_memWriteData = value;
    m_inst->TesterWrapper__io_memWriteEn = 1;
    step();
    m_inst->TesterWrapper__io_memWriteEn = 0;
  }

  uint64_t memRead(uint64_t addr) {
    m_inst->TesterWrapper__io_memAddr = addr;
    step();
    uint64_t ret = m_inst->TesterWrapper__io_memReadData[0];
    return ret;
  }

  // "aligned" copy functions, where accel ptr start and size are guaranteed to be 8-aligned
  void alignedCopyBufferHostToAccel(void * hostBuffer, void * accelBuffer, unsigned int numBytes) {
    uint64_t * host_buf = (uint64_t *) hostBuffer;
    uint64_t accelBufBase = (uint64_t) accelBuffer;
    for(unsigned int i = 0; i < numBytes/8; i++)
        memWrite(accelBufBase + i*8, host_buf[i]);
  }

  void alignedCopyBufferAccelToHost(void * accelBuffer, void * hostBuffer, unsigned int numBytes) {
    uint64_t accelBufBase = (uint64_t) accelBuffer;
    uint64_t * readBuf = (uint64_t *) hostBuffer;
    for(unsigned int i = 0; i < numBytes/8; i++)
      readBuf[i] = memRead(accelBufBase + i*8);
  }
};

#endif
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE 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 "../PreFlightCheck.hpp"

#include <ArmAuthorization.h>
#include <systemlib/mavlink_log.h>
#include <uORB/topics/vehicle_command_ack.h>

bool PreFlightCheck::preArmCheck(orb_advert_t *mavlink_log_pub, const vehicle_status_flags_s &status_flags,
				 const safety_s &safety, const arm_requirements_t &arm_requirements, const vehicle_status_s &status)
{
	bool prearm_ok = true;

	// USB not connected
	if (!status_flags.circuit_breaker_engaged_usb_check && status_flags.usb_connected) {
		mavlink_log_critical(mavlink_log_pub, "Arming denied! Flying with USB is not safe");

		prearm_ok = false;
	}

	// battery and system power status
	if (!status_flags.circuit_breaker_engaged_power_check) {

		// Fail transition if power is not good
		if (!status_flags.condition_power_input_valid) {
			mavlink_log_critical(mavlink_log_pub, "Arming denied! Connect power module");

			prearm_ok = false;
		}

		// main battery level
		if (!status_flags.condition_battery_healthy) {
			if (prearm_ok) {
				mavlink_log_critical(mavlink_log_pub, "Arming denied! Check battery");
			}

			prearm_ok = false;
		}
	}

	// Arm Requirements: mission
	if (arm_requirements.mission) {

		if (!status_flags.condition_auto_mission_available) {
			if (prearm_ok) {
				mavlink_log_critical(mavlink_log_pub, "Arming denied! No valid mission");
			}

			prearm_ok = false;
		}

		if (!status_flags.condition_global_position_valid) {
			if (prearm_ok) {
				mavlink_log_critical(mavlink_log_pub, "Arming denied! Missions require a global position");
			}

			prearm_ok = false;
		}
	}

	// Arm Requirements: global position
	if (arm_requirements.global_position) {

		if (!status_flags.condition_global_position_valid) {
			if (prearm_ok) {
				mavlink_log_critical(mavlink_log_pub, "Arming denied! Global position required");
			}

			prearm_ok = false;
		}
	}

	// safety button
	if (safety.safety_switch_available && !safety.safety_off) {
		// Fail transition if we need safety switch press
		if (prearm_ok) {
			mavlink_log_critical(mavlink_log_pub, "Arming denied! Press safety switch first");
		}

		prearm_ok = false;
	}

	if (status_flags.avoidance_system_required && !status_flags.avoidance_system_valid) {
		if (prearm_ok) {
			mavlink_log_critical(mavlink_log_pub, "Arming denied! Avoidance system not ready");
		}

		prearm_ok = false;

	}

	if (arm_requirements.esc_check && status_flags.condition_escs_error) {
		if (prearm_ok) {
			mavlink_log_critical(mavlink_log_pub, "Arming denied! One or more ESCs are offline");
			prearm_ok = false;
		}
	}

	if (status.is_vtol && status.in_transition_mode) {
		if (prearm_ok) {
			mavlink_log_critical(mavlink_log_pub, "Arming denied! Vehicle is in transition state");
			prearm_ok = false;
		}
	}

	if (!status_flags.circuit_breaker_vtol_fw_arming_check && status.is_vtol
	    && status.vehicle_type != vehicle_status_s::VEHICLE_TYPE_ROTARY_WING) {
		if (prearm_ok) {
			mavlink_log_critical(mavlink_log_pub, "Arming denied! Vehicle is not in multicopter mode");
			prearm_ok = false;
		}
	}

	// Arm Requirements: authorization
	// check last, and only if everything else has passed
	if (arm_requirements.arm_authorization && prearm_ok) {
		if (arm_auth_check() != vehicle_command_ack_s::VEHICLE_RESULT_ACCEPTED) {
			// feedback provided in arm_auth_check
			prearm_ok = false;
		}
	}

	return prearm_ok;
}
<commit_msg>prearmCheck: vtol cleanup<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE 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 "../PreFlightCheck.hpp"

#include <ArmAuthorization.h>
#include <systemlib/mavlink_log.h>
#include <uORB/topics/vehicle_command_ack.h>

bool PreFlightCheck::preArmCheck(orb_advert_t *mavlink_log_pub, const vehicle_status_flags_s &status_flags,
				 const safety_s &safety, const arm_requirements_t &arm_requirements, const vehicle_status_s &status)
{
	bool prearm_ok = true;

	// USB not connected
	if (!status_flags.circuit_breaker_engaged_usb_check && status_flags.usb_connected) {
		mavlink_log_critical(mavlink_log_pub, "Arming denied! Flying with USB is not safe");

		prearm_ok = false;
	}

	// battery and system power status
	if (!status_flags.circuit_breaker_engaged_power_check) {

		// Fail transition if power is not good
		if (!status_flags.condition_power_input_valid) {
			mavlink_log_critical(mavlink_log_pub, "Arming denied! Connect power module");

			prearm_ok = false;
		}

		// main battery level
		if (!status_flags.condition_battery_healthy) {
			if (prearm_ok) {
				mavlink_log_critical(mavlink_log_pub, "Arming denied! Check battery");
			}

			prearm_ok = false;
		}
	}

	// Arm Requirements: mission
	if (arm_requirements.mission) {

		if (!status_flags.condition_auto_mission_available) {
			if (prearm_ok) {
				mavlink_log_critical(mavlink_log_pub, "Arming denied! No valid mission");
			}

			prearm_ok = false;
		}

		if (!status_flags.condition_global_position_valid) {
			if (prearm_ok) {
				mavlink_log_critical(mavlink_log_pub, "Arming denied! Missions require a global position");
			}

			prearm_ok = false;
		}
	}

	// Arm Requirements: global position
	if (arm_requirements.global_position) {

		if (!status_flags.condition_global_position_valid) {
			if (prearm_ok) {
				mavlink_log_critical(mavlink_log_pub, "Arming denied! Global position required");
			}

			prearm_ok = false;
		}
	}

	// safety button
	if (safety.safety_switch_available && !safety.safety_off) {
		// Fail transition if we need safety switch press
		if (prearm_ok) {
			mavlink_log_critical(mavlink_log_pub, "Arming denied! Press safety switch first");
		}

		prearm_ok = false;
	}

	if (status_flags.avoidance_system_required && !status_flags.avoidance_system_valid) {
		if (prearm_ok) {
			mavlink_log_critical(mavlink_log_pub, "Arming denied! Avoidance system not ready");
		}

		prearm_ok = false;

	}

	if (arm_requirements.esc_check && status_flags.condition_escs_error) {
		if (prearm_ok) {
			mavlink_log_critical(mavlink_log_pub, "Arming denied! One or more ESCs are offline");
			prearm_ok = false;
		}
	}

	if (status.is_vtol) {

		if (status.in_transition_mode) {
			if (prearm_ok) {
				mavlink_log_critical(mavlink_log_pub, "Arming denied! Vehicle is in transition state");
				prearm_ok = false;
			}
		}

		if (!status_flags.circuit_breaker_vtol_fw_arming_check
		    && status.vehicle_type != vehicle_status_s::VEHICLE_TYPE_ROTARY_WING) {
			if (prearm_ok) {
				mavlink_log_critical(mavlink_log_pub, "Arming denied! Vehicle is not in multicopter mode");
				prearm_ok = false;
			}
		}
	}

	// Arm Requirements: authorization
	// check last, and only if everything else has passed
	if (arm_requirements.arm_authorization && prearm_ok) {
		if (arm_auth_check() != vehicle_command_ack_s::VEHICLE_RESULT_ACCEPTED) {
			// feedback provided in arm_auth_check
			prearm_ok = false;
		}
	}

	return prearm_ok;
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <compressor.h>
#include <core_io.h>
#include <core_memusage.h>
#include <policy/policy.h>
#include <pubkey.h>
#include <script/descriptor.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/signingprovider.h>
#include <script/standard.h>
#include <streams.h>
#include <test/fuzz/fuzz.h>
#include <univalue.h>
#include <util/memory.h>

void initialize()
{
    // Fuzzers using pubkey must hold an ECCVerifyHandle.
    static const auto verify_handle = MakeUnique<ECCVerifyHandle>();

    SelectParams(CBaseChainParams::REGTEST);
}

void test_one_input(const std::vector<uint8_t>& buffer)
{
    const CScript script(buffer.begin(), buffer.end());

    std::vector<unsigned char> compressed;
    if (CompressScript(script, compressed)) {
        const unsigned int size = compressed[0];
        compressed.erase(compressed.begin());
        assert(size >= 0 && size <= 5);
        CScript decompressed_script;
        const bool ok = DecompressScript(decompressed_script, size, compressed);
        assert(ok);
        assert(script == decompressed_script);
    }

    CTxDestination address;
    (void)ExtractDestination(script, address);

    txnouttype type_ret;
    std::vector<CTxDestination> addresses;
    int required_ret;
    (void)ExtractDestinations(script, type_ret, addresses, required_ret);

    (void)GetScriptForWitness(script);

    const FlatSigningProvider signing_provider;
    (void)InferDescriptor(script, signing_provider);

    (void)IsSegWitOutput(signing_provider, script);

    (void)IsSolvable(signing_provider, script);

    txnouttype which_type;
    (void)IsStandard(script, which_type);

    (void)RecursiveDynamicUsage(script);

    std::vector<std::vector<unsigned char>> solutions;
    (void)Solver(script, solutions);

    (void)script.HasValidOps();
    (void)script.IsPayToScriptHash();
    (void)script.IsPayToWitnessScriptHash();
    (void)script.IsPushOnly();
    (void)script.IsUnspendable();
    (void)script.GetSigOpCount(/* fAccurate= */ false);

    (void)FormatScript(script);
    (void)ScriptToAsmStr(script, false);
    (void)ScriptToAsmStr(script, true);

    UniValue o1(UniValue::VOBJ);
    ScriptPubKeyToUniv(script, o1, true);
    UniValue o2(UniValue::VOBJ);
    ScriptPubKeyToUniv(script, o2, false);
    UniValue o3(UniValue::VOBJ);
    ScriptToUniv(script, o3, true);
    UniValue o4(UniValue::VOBJ);
    ScriptToUniv(script, o4, false);
}
<commit_msg>tests: Increase fuzzing coverage of DecompressScript(...)<commit_after>// Copyright (c) 2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <compressor.h>
#include <core_io.h>
#include <core_memusage.h>
#include <policy/policy.h>
#include <pubkey.h>
#include <script/descriptor.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/signingprovider.h>
#include <script/standard.h>
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <univalue.h>
#include <util/memory.h>

void initialize()
{
    // Fuzzers using pubkey must hold an ECCVerifyHandle.
    static const auto verify_handle = MakeUnique<ECCVerifyHandle>();

    SelectParams(CBaseChainParams::REGTEST);
}

void test_one_input(const std::vector<uint8_t>& buffer)
{
    const CScript script(buffer.begin(), buffer.end());

    std::vector<unsigned char> compressed;
    if (CompressScript(script, compressed)) {
        const unsigned int size = compressed[0];
        compressed.erase(compressed.begin());
        assert(size >= 0 && size <= 5);
        CScript decompressed_script;
        const bool ok = DecompressScript(decompressed_script, size, compressed);
        assert(ok);
        assert(script == decompressed_script);
    }

    CTxDestination address;
    (void)ExtractDestination(script, address);

    txnouttype type_ret;
    std::vector<CTxDestination> addresses;
    int required_ret;
    (void)ExtractDestinations(script, type_ret, addresses, required_ret);

    (void)GetScriptForWitness(script);

    const FlatSigningProvider signing_provider;
    (void)InferDescriptor(script, signing_provider);

    (void)IsSegWitOutput(signing_provider, script);

    (void)IsSolvable(signing_provider, script);

    txnouttype which_type;
    (void)IsStandard(script, which_type);

    (void)RecursiveDynamicUsage(script);

    std::vector<std::vector<unsigned char>> solutions;
    (void)Solver(script, solutions);

    (void)script.HasValidOps();
    (void)script.IsPayToScriptHash();
    (void)script.IsPayToWitnessScriptHash();
    (void)script.IsPushOnly();
    (void)script.IsUnspendable();
    (void)script.GetSigOpCount(/* fAccurate= */ false);

    (void)FormatScript(script);
    (void)ScriptToAsmStr(script, false);
    (void)ScriptToAsmStr(script, true);

    UniValue o1(UniValue::VOBJ);
    ScriptPubKeyToUniv(script, o1, true);
    UniValue o2(UniValue::VOBJ);
    ScriptPubKeyToUniv(script, o2, false);
    UniValue o3(UniValue::VOBJ);
    ScriptToUniv(script, o3, true);
    UniValue o4(UniValue::VOBJ);
    ScriptToUniv(script, o4, false);

    {
        FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
        const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
        // DecompressScript(..., ..., bytes) is not guaranteed to be defined if bytes.size() <= 23.
        if (bytes.size() >= 24) {
            CScript decompressed_script;
            DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), bytes);
        }
    }
}
<|endoftext|>


<commit_before>/**
 *  \file
 *  \remark This file is part of VITA.
 *
 *  \copyright Copyright (C) 2013-2015 EOS di Manlio Morini.
 *
 *  \license
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this file,
 *  You can obtain one at http://mozilla.org/MPL/2.0/
 */

#include <algorithm>
#include <iostream>

#include "kernel/staging/small_vector.h"

#if !defined(MASTER_TEST_SET)
#define BOOST_TEST_MODULE small_vector_test
#include "boost/test/unit_test.hpp"

using namespace boost;
#endif

struct not_pod
{
  not_pod(int x = 10, double y = 3.1415) : a(x), b(y) {}

  bool operator!=(const not_pod &rhs) const
  {
    return a != rhs.a || std::fabs(b - rhs.b) > 0.00000001;
  }

  int    a;
  double b;
};

std::ostream &operator<<(std::ostream &o, const not_pod &x)
{
  return o << '(' << x.a << ", " << x.b << ')';
}

BOOST_AUTO_TEST_SUITE(small_vector)

BOOST_AUTO_TEST_CASE(t_push_back)
{
  vita::small_vector<double, 1> sv1;
  std::vector<double> v;

  for (unsigned i(0); i < 1000; ++i)
  {
    sv1.push_back(i);
    v.push_back(i);

    BOOST_CHECK_EQUAL_COLLECTIONS(sv1.begin(), sv1.end(), v.begin(), v.end());
  }

  vita::small_vector<int, 2> sv2;
  std::vector<int> v2;

  for (unsigned i(0); i < 1000; ++i)
  {
    sv2.push_back(static_cast<int>(i));
    v2.push_back(static_cast<int>(i));

    BOOST_CHECK_EQUAL_COLLECTIONS(sv2.begin(), sv2.end(), v2.begin(), v2.end());
  }

  assert(!std::is_pod<not_pod>::value);

  vita::small_vector<not_pod, 3> sv3;
  std::vector<not_pod> v3;

  for (unsigned i(0); i < 1000; ++i)
  {
    sv3.push_back(not_pod(static_cast<int>(i), i + 1));
    v3.push_back(not_pod(static_cast<int>(i), i + 1));

    BOOST_CHECK_EQUAL_COLLECTIONS(sv3.begin(), sv3.end(), v3.begin(), v3.end());
  }
}

BOOST_AUTO_TEST_CASE(t_insert)
{
  BOOST_TEST_CHECKPOINT("INSERT AT THE END (APPEND)");
  {
    std::vector<unsigned> src1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    vita::small_vector<unsigned, 1> sv1;
    std::vector<unsigned> v1;

    for (unsigned i(0); i < 200; ++i)
    {
      sv1.insert(sv1.end(), src1.begin(), src1.end());
      v1.insert(v1.end(), src1.begin(), src1.end());

      BOOST_CHECK_EQUAL_COLLECTIONS(sv1.begin(), sv1.end(),
                                    v1.begin(), v1.end());
    }
  }

  BOOST_TEST_CHECKPOINT("INSERT AT THE BEGINNING");
  {
    std::vector<short> src2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    vita::small_vector<short, 2> sv2;
    std::vector<short> v2;

    for (unsigned i(0); i < 200; ++i)
    {
      sv2.insert(sv2.begin(), src2.begin(), src2.end());
      v2.insert(v2.begin(), src2.begin(), src2.end());

      BOOST_CHECK_EQUAL_COLLECTIONS(sv2.begin(), sv2.end(),
                                    v2.begin(), v2.end());
    }
  }

  BOOST_TEST_CHECKPOINT("INSERT IN THE MIDDLE");
  {
    std::vector<not_pod> src3 = {not_pod(0, 1.0), not_pod(2, 3.0),
                                 not_pod(4, 5.0), not_pod(6, 7.0),
                                 not_pod(8, 9.0), not_pod(0, 0.0)};
    vita::small_vector<not_pod, 3> sv3;
    std::vector<not_pod> v3;

    for (unsigned i(0); i < 200; ++i)
    {
      const auto n(static_cast<std::ptrdiff_t>(v3.size() / 2));

      sv3.insert(std::next(sv3.begin(), n), src3.begin(), src3.end());
      v3.insert(std::next(v3.begin(), n), src3.begin(), src3.end());

      BOOST_CHECK_EQUAL_COLLECTIONS(sv3.begin(), sv3.end(),
                                    v3.begin(), v3.end());
    }
  }
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>[TEST] Improved unit test for small_vector class<commit_after>/**
 *  \file
 *  \remark This file is part of VITA.
 *
 *  \copyright Copyright (C) 2013-2015 EOS di Manlio Morini.
 *
 *  \license
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this file,
 *  You can obtain one at http://mozilla.org/MPL/2.0/
 */

#include <algorithm>
#include <iostream>

#include "kernel/staging/small_vector.h"

#if !defined(MASTER_TEST_SET)
#define BOOST_TEST_MODULE small_vector_test
#include "boost/test/unit_test.hpp"

using namespace boost;
#endif

struct not_pod
{
  not_pod(int x = 10, double y = 3.1415) : a(x), b(y) {}

  bool operator!=(const not_pod &rhs) const
  {
    return a != rhs.a || std::fabs(b - rhs.b) > 0.00000001;
  }

  int    a;
  double b;
};

std::ostream &operator<<(std::ostream &o, const not_pod &x)
{
  return o << '(' << x.a << ", " << x.b << ')';
}

BOOST_AUTO_TEST_SUITE(small_vector)

BOOST_AUTO_TEST_CASE(t_constructor_assignment)
{
  vita::small_vector<double, 1> sv1;
  vita::small_vector<double, 1> sv1_bis(1, 3.1415);
  vita::small_vector<double, 2> sv2{1.0, 2.0};
  vita::small_vector<double, 3> sv3(3);

  BOOST_REQUIRE(sv1.empty());
  BOOST_REQUIRE_EQUAL(sv1.size(), 0);
  BOOST_REQUIRE(!sv1_bis.empty());
  BOOST_REQUIRE_EQUAL(sv1_bis.size(), 1);
  BOOST_REQUIRE(!sv2.empty());
  BOOST_REQUIRE_EQUAL(sv2.size(), 2);
  BOOST_REQUIRE(!sv3.empty());
  BOOST_REQUIRE_EQUAL(sv3.size(), 3);

  sv1 = sv1_bis;
  BOOST_REQUIRE_EQUAL_COLLECTIONS(sv1.begin(), sv1.end(),
                                  sv1_bis.begin(), sv1_bis.end());

  sv1 = {1.0, 2.0};
  BOOST_REQUIRE_EQUAL_COLLECTIONS(sv1.begin(), sv1.end(), sv2.begin(), sv2.end());

  sv3 = {1.0, 2.0, 3.0};
  sv1 = {1.0, 2.0, 3.0};
  BOOST_REQUIRE_EQUAL_COLLECTIONS(sv1.begin(), sv1.end(), sv3.begin(), sv3.end());

  sv1_bis = sv1;
  BOOST_REQUIRE_EQUAL_COLLECTIONS(sv1.begin(), sv1.end(),
                                  sv1_bis.begin(), sv1_bis.end());
}

BOOST_AUTO_TEST_CASE(t_push_back)
{
  vita::small_vector<double, 1> sv1;
  std::vector<double> v;

  for (unsigned i(0); i < 1000; ++i)
  {
    sv1.push_back(i);
    v.push_back(i);

    BOOST_REQUIRE_EQUAL_COLLECTIONS(sv1.begin(), sv1.end(), v.begin(), v.end());
  }

  vita::small_vector<int, 2> sv2;
  std::vector<int> v2;

  for (unsigned i(0); i < 1000; ++i)
  {
    sv2.push_back(static_cast<int>(i));
    v2.push_back(static_cast<int>(i));

    BOOST_CHECK_EQUAL_COLLECTIONS(sv2.begin(), sv2.end(), v2.begin(), v2.end());
  }

  assert(!std::is_pod<not_pod>::value);

  vita::small_vector<not_pod, 3> sv3;
  std::vector<not_pod> v3;

  for (unsigned i(0); i < 1000; ++i)
  {
    sv3.push_back(not_pod(static_cast<int>(i), i + 1));
    v3.push_back(not_pod(static_cast<int>(i), i + 1));

    BOOST_CHECK_EQUAL_COLLECTIONS(sv3.begin(), sv3.end(), v3.begin(), v3.end());
  }
}

BOOST_AUTO_TEST_CASE(t_insert)
{
  BOOST_TEST_CHECKPOINT("INSERT AT THE END (APPEND)");
  {
    std::vector<unsigned> src1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    vita::small_vector<unsigned, 1> sv1;
    std::vector<unsigned> v1;

    for (unsigned i(0); i < 200; ++i)
    {
      sv1.insert(sv1.end(), src1.begin(), src1.end());
      v1.insert(v1.end(), src1.begin(), src1.end());

      BOOST_CHECK_EQUAL_COLLECTIONS(sv1.begin(), sv1.end(),
                                    v1.begin(), v1.end());
    }
  }

  BOOST_TEST_CHECKPOINT("INSERT AT THE BEGINNING");
  {
    std::vector<short> src2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    vita::small_vector<short, 2> sv2;
    std::vector<short> v2;

    for (unsigned i(0); i < 200; ++i)
    {
      sv2.insert(sv2.begin(), src2.begin(), src2.end());
      v2.insert(v2.begin(), src2.begin(), src2.end());

      BOOST_CHECK_EQUAL_COLLECTIONS(sv2.begin(), sv2.end(),
                                    v2.begin(), v2.end());
    }
  }

  BOOST_TEST_CHECKPOINT("INSERT IN THE MIDDLE");
  {
    std::vector<not_pod> src3 = {not_pod(0, 1.0), not_pod(2, 3.0),
                                 not_pod(4, 5.0), not_pod(6, 7.0),
                                 not_pod(8, 9.0), not_pod(0, 0.0)};
    vita::small_vector<not_pod, 3> sv3;
    std::vector<not_pod> v3;

    for (unsigned i(0); i < 200; ++i)
    {
      const auto n(static_cast<std::ptrdiff_t>(v3.size() / 2));

      sv3.insert(std::next(sv3.begin(), n), src3.begin(), src3.end());
      v3.insert(std::next(v3.begin(), n), src3.begin(), src3.end());

      BOOST_CHECK_EQUAL_COLLECTIONS(sv3.begin(), sv3.end(),
                                    v3.begin(), v3.end());
    }
  }
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// 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 co
// pies 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 al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER 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 "content/nw/src/nw_package.h"

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/json/json_file_value_serializer.h"
#include "base/logging.h"
#include "base/scoped_temp_dir.h"
#include "base/string_util.h"
#include "base/string16.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "content/nw/src/common/shell_switches.h"
#include "content/nw/src/common/zip.h"
#include "googleurl/src/gurl.h"

namespace nw {

namespace {

bool MakePathAbsolute(FilePath* file_path) {
  DCHECK(file_path);

  FilePath current_directory;
  if (!file_util::GetCurrentDirectory(&current_directory))
    return false;

  if (file_path->IsAbsolute())
    return true;

  if (current_directory.empty())
    return file_util::AbsolutePath(file_path);

  if (!current_directory.IsAbsolute())
    return false;

  *file_path = current_directory.Append(*file_path);
  return true;
}

FilePath GetPathFromCommandLine(bool* self_extract) {
  FilePath path;
  CommandLine* command_line = CommandLine::ForCurrentProcess();
  const CommandLine::StringVector& args = command_line->GetArgs();

  if (args.size() == 0) {
    *self_extract = true;
#if defined(OS_MACOSX)
    // Find if we have node-webkit.app/Resources/app.nw.
    path = path.DirName().DirName().Append("Resources").Append("app.nw");
#else
    // See itself as a package (allowing standalone).
    path = FilePath(command_line->GetProgram());
#endif
  } else {
    *self_extract = false;
    // Get first argument.
    path = FilePath(args[0]);
  }

  return path;
}

void RelativePathToURI(FilePath root, base::DictionaryValue* manifest) {
  std::string old;
  if (!manifest->GetString(switches::kmMain, &old))
    return;

  // Don't append path if there is already a prefix
  if (MatchPattern(old, "*://*"))
    return;

  FilePath main_path = root.Append(FilePath::FromUTF8Unsafe(old));
  manifest->SetString(switches::kmMain,
                      std::string("file://") + main_path.AsUTF8Unsafe());
}

bool ExtractPackage(const FilePath& zip_file, FilePath* where) {
  // Auto clean our temporary directory
  static scoped_ptr<ScopedTempDir> scoped_temp_dir;

#if defined(OS_WIN)
  if (!file_util::CreateNewTempDirectory(L"nw", where)) {
#else
  if (!file_util::CreateNewTempDirectory("nw", where)) {
#endif
    LOG(ERROR) << "Unable to create temporary directory.";
    return false;
  }

  scoped_temp_dir.reset(new ScopedTempDir());
  if (!scoped_temp_dir->Set(*where)) {
    LOG(ERROR) << "Unable to set temporary directory.";
    return false;
  }

  return zip::Unzip(zip_file, *where);
}

}  // namespace

Package::Package()
    : path_(GetPathFromCommandLine(&self_extract_)) {
  if (!InitFromPath())
    InitWithDefault();
}

Package::Package(FilePath path)
    : path_(path),
      self_extract_(false) {
  if (!InitFromPath())
    InitWithDefault();
}

Package::~Package() {
}

GURL Package::GetStartupURL() {
  std::string url;
  // Specify URL in --url
  CommandLine* command_line = CommandLine::ForCurrentProcess();
  if (command_line->HasSwitch(switches::kUrl)) {
    url = command_line->GetSwitchValueASCII(switches::kUrl);
    GURL gurl(url);
    if (!gurl.has_scheme())
      return GURL(std::string("http://") + url);

    return gurl;
  }

  // Read from manifest
  if (root()->GetString(switches::kmMain, &url))
    return GURL(url);
  else
    return GURL("nw:blank");
}

bool Package::GetUseNode() {
  bool use_node = true;
  root()->GetBoolean(switches::kmNodejs, &use_node);
  return use_node;
}

base::DictionaryValue* Package::window() {
  base::DictionaryValue* window;
  root()->GetDictionaryWithoutPathExpansion(switches::kmWindow, &window);
  return window;
}

bool Package::InitFromPath() {
  base::ThreadRestrictions::SetIOAllowed(true);

  if (!ExtractPath(&path_))
    return false;

  file_util::SetCurrentDirectory(path_);

  // path_/package.json
  FilePath manifest_path = path_.AppendASCII("package.json");
  if (!file_util::PathExists(manifest_path)) {
    if (!self_extract())
      LOG(ERROR) << "No 'package.json' in package.";
    return false;
  }

  // Parse file.
  std::string error;
  JSONFileValueSerializer serializer(manifest_path);
  scoped_ptr<Value> root(serializer.Deserialize(NULL, &error));
  if (!root.get()) {
    if (error.empty())
      LOG(ERROR) << "It's not able to read the manifest file.";
    else
      LOG(ERROR) << "Manifest parsing error: " << error;
    return false;
  } else if (!root->IsType(Value::TYPE_DICTIONARY)) {
    LOG(ERROR) << "Manifest file is invalid, we need a dictionary type";
    return false;
  }

  // Save result in global
  root_.reset(static_cast<DictionaryValue*>(root.release()));

  // Check fields
  const char* required_fields[] = {
    switches::kmMain,
    switches::kmName
  };
  for (unsigned i = 0; i < arraysize(required_fields); i++)
    if (!root_->HasKey(required_fields[i])) {
      LOG(ERROR) << "'" << required_fields[i] << "' field is required.";
      return false;
    }

  // Force window field no empty.
  if (!root_->HasKey(switches::kmWindow)) {
    base::DictionaryValue* window = new base::DictionaryValue();
    window->SetString(switches::kmPosition, "center");
    root_->Set(switches::kmWindow, window);
  }

  RelativePathToURI(path_, this->root());
  return true;
}

void Package::InitWithDefault() {
  root_.reset(new base::DictionaryValue());
  root()->SetString(switches::kmName, "node-webkit");
  root()->SetString(switches::kmMain, "nw:blank");
  base::DictionaryValue* window = new base::DictionaryValue();
  root()->Set(switches::kmWindow, window);

  // Hide toolbar if specifed in the command line.
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoToolbar))
    window->SetBoolean(switches::kmToolbar, false);

  // Window should show in center by default.
  window->SetString(switches::kmPosition, "center");
}

bool Package::ExtractPath(FilePath* path) {
  // Convert to absoulute path.
  if (!MakePathAbsolute(&path_)) {
    LOG(ERROR) << "Cannot make absolute path from " << path_.value();
    return false;
  }

  // If it's a file then try to extract from it.
  if (!file_util::DirectoryExists(path_)) {
    DLOG(INFO) << "Extracting packaging...";
    FilePath extracted_path;
    if (ExtractPackage(path_, &extracted_path)) {
      path_ = extracted_path;
    } else if (!self_extract()) {
      LOG(ERROR) << "Unable to extract package.";
      return false;
    }
  }

  return true;
}

}  // namespace nw
<commit_msg>[Mac] Fix self extract package. Fixes #79.<commit_after>// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// 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 co
// pies 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 al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER 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 "content/nw/src/nw_package.h"

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/json/json_file_value_serializer.h"
#include "base/logging.h"
#include "base/scoped_temp_dir.h"
#include "base/string_util.h"
#include "base/string16.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "content/nw/src/common/shell_switches.h"
#include "content/nw/src/common/zip.h"
#include "googleurl/src/gurl.h"

namespace nw {

namespace {

bool MakePathAbsolute(FilePath* file_path) {
  DCHECK(file_path);

  FilePath current_directory;
  if (!file_util::GetCurrentDirectory(&current_directory))
    return false;

  if (file_path->IsAbsolute())
    return true;

  if (current_directory.empty())
    return file_util::AbsolutePath(file_path);

  if (!current_directory.IsAbsolute())
    return false;

  *file_path = current_directory.Append(*file_path);
  return true;
}

FilePath GetPathFromCommandLine(bool* self_extract) {
  FilePath path;
  CommandLine* command_line = CommandLine::ForCurrentProcess();
  const CommandLine::StringVector& args = command_line->GetArgs();

  if (args.size() == 0) {
    *self_extract = true;
    // See itself as a package (allowing standalone).
    path = FilePath(command_line->GetProgram());
#if defined(OS_MACOSX)
    // Find if we have node-webkit.app/Resources/app.nw.
    path = path.DirName().DirName().Append("Resources").Append("app.nw");
#endif
  } else {
    *self_extract = false;
    // Get first argument.
    path = FilePath(args[0]);
  }

  return path;
}

void RelativePathToURI(FilePath root, base::DictionaryValue* manifest) {
  std::string old;
  if (!manifest->GetString(switches::kmMain, &old))
    return;

  // Don't append path if there is already a prefix
  if (MatchPattern(old, "*://*"))
    return;

  FilePath main_path = root.Append(FilePath::FromUTF8Unsafe(old));
  manifest->SetString(switches::kmMain,
                      std::string("file://") + main_path.AsUTF8Unsafe());
}

bool ExtractPackage(const FilePath& zip_file, FilePath* where) {
  // Auto clean our temporary directory
  static scoped_ptr<ScopedTempDir> scoped_temp_dir;

#if defined(OS_WIN)
  if (!file_util::CreateNewTempDirectory(L"nw", where)) {
#else
  if (!file_util::CreateNewTempDirectory("nw", where)) {
#endif
    LOG(ERROR) << "Unable to create temporary directory.";
    return false;
  }

  scoped_temp_dir.reset(new ScopedTempDir());
  if (!scoped_temp_dir->Set(*where)) {
    LOG(ERROR) << "Unable to set temporary directory.";
    return false;
  }

  return zip::Unzip(zip_file, *where);
}

}  // namespace

Package::Package()
    : path_(GetPathFromCommandLine(&self_extract_)) {
  if (!InitFromPath())
    InitWithDefault();
}

Package::Package(FilePath path)
    : path_(path),
      self_extract_(false) {
  if (!InitFromPath())
    InitWithDefault();
}

Package::~Package() {
}

GURL Package::GetStartupURL() {
  std::string url;
  // Specify URL in --url
  CommandLine* command_line = CommandLine::ForCurrentProcess();
  if (command_line->HasSwitch(switches::kUrl)) {
    url = command_line->GetSwitchValueASCII(switches::kUrl);
    GURL gurl(url);
    if (!gurl.has_scheme())
      return GURL(std::string("http://") + url);

    return gurl;
  }

  // Read from manifest
  if (root()->GetString(switches::kmMain, &url))
    return GURL(url);
  else
    return GURL("nw:blank");
}

bool Package::GetUseNode() {
  bool use_node = true;
  root()->GetBoolean(switches::kmNodejs, &use_node);
  return use_node;
}

base::DictionaryValue* Package::window() {
  base::DictionaryValue* window;
  root()->GetDictionaryWithoutPathExpansion(switches::kmWindow, &window);
  return window;
}

bool Package::InitFromPath() {
  base::ThreadRestrictions::SetIOAllowed(true);

  if (!ExtractPath(&path_))
    return false;

  file_util::SetCurrentDirectory(path_);

  // path_/package.json
  FilePath manifest_path = path_.AppendASCII("package.json");
  if (!file_util::PathExists(manifest_path)) {
    if (!self_extract())
      LOG(ERROR) << "No 'package.json' in package.";
    return false;
  }

  // Parse file.
  std::string error;
  JSONFileValueSerializer serializer(manifest_path);
  scoped_ptr<Value> root(serializer.Deserialize(NULL, &error));
  if (!root.get()) {
    if (error.empty())
      LOG(ERROR) << "It's not able to read the manifest file.";
    else
      LOG(ERROR) << "Manifest parsing error: " << error;
    return false;
  } else if (!root->IsType(Value::TYPE_DICTIONARY)) {
    LOG(ERROR) << "Manifest file is invalid, we need a dictionary type";
    return false;
  }

  // Save result in global
  root_.reset(static_cast<DictionaryValue*>(root.release()));

  // Check fields
  const char* required_fields[] = {
    switches::kmMain,
    switches::kmName
  };
  for (unsigned i = 0; i < arraysize(required_fields); i++)
    if (!root_->HasKey(required_fields[i])) {
      LOG(ERROR) << "'" << required_fields[i] << "' field is required.";
      return false;
    }

  // Force window field no empty.
  if (!root_->HasKey(switches::kmWindow)) {
    base::DictionaryValue* window = new base::DictionaryValue();
    window->SetString(switches::kmPosition, "center");
    root_->Set(switches::kmWindow, window);
  }

  RelativePathToURI(path_, this->root());
  return true;
}

void Package::InitWithDefault() {
  root_.reset(new base::DictionaryValue());
  root()->SetString(switches::kmName, "node-webkit");
  root()->SetString(switches::kmMain, "nw:blank");
  base::DictionaryValue* window = new base::DictionaryValue();
  root()->Set(switches::kmWindow, window);

  // Hide toolbar if specifed in the command line.
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoToolbar))
    window->SetBoolean(switches::kmToolbar, false);

  // Window should show in center by default.
  window->SetString(switches::kmPosition, "center");
}

bool Package::ExtractPath(FilePath* path) {
  // Convert to absoulute path.
  if (!MakePathAbsolute(&path_)) {
    LOG(ERROR) << "Cannot make absolute path from " << path_.value();
    return false;
  }

  // If it's a file then try to extract from it.
  if (!file_util::DirectoryExists(path_)) {
    DLOG(INFO) << "Extracting packaging...";
    FilePath extracted_path;
    if (ExtractPackage(path_, &extracted_path)) {
      path_ = extracted_path;
    } else if (!self_extract()) {
      LOG(ERROR) << "Unable to extract package.";
      return false;
    }
  }

  return true;
}

}  // namespace nw
<|endoftext|>