<commit_before>#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif

#include "sass_interface.h"
#include "context.hpp"
#include "inspect.hpp"

#ifndef SASS_ERROR_HANDLING
#include "error_handling.hpp"
#endif

#include <iostream>
#include <sstream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>

extern "C" {
  using namespace std;

  sass_context* sass_new_context()
  { return (sass_context*) calloc(1, sizeof(sass_context)); }

  void free_string_array(char ** arr, int num) {
    if(!arr)
        return;

    for(int i = 0; i < num; i++) {
      free(arr[i]);
    }

    free(arr);
  }

  void sass_free_context(sass_context* ctx)
  {
    if (ctx->output_string)     free(ctx->output_string);
    if (ctx->source_map_string) free(ctx->source_map_string);
    if (ctx->error_message)     free(ctx->error_message);
    if (ctx->c_functions)       free(ctx->c_functions);

    free_string_array(ctx->included_files, ctx->num_included_files);

    free(ctx);
  }

  sass_file_context* sass_new_file_context()
  { return (sass_file_context*) calloc(1, sizeof(sass_file_context)); }

  void sass_free_file_context(sass_file_context* ctx)
  {
    if (ctx->output_string)     free(ctx->output_string);
    if (ctx->source_map_string) free(ctx->source_map_string);
    if (ctx->error_message)     free(ctx->error_message);
    if (ctx->c_functions)       free(ctx->c_functions);

    free_string_array(ctx->included_files, ctx->num_included_files);

    free(ctx);
  }

  sass_folder_context* sass_new_folder_context()
  { return (sass_folder_context*) calloc(1, sizeof(sass_folder_context)); }

  void sass_free_folder_context(sass_folder_context* ctx)
  {
    free_string_array(ctx->included_files, ctx->num_included_files);
    free(ctx);
  }

  void copy_strings(const std::vector<std::string>& strings, char*** array, int* n, int skip = 0) {
    int num = static_cast<int>(strings.size());
    char** arr = (char**) malloc(sizeof(char*)* num);

    for(int i = skip; i < num; i++) {
      arr[i-skip] = (char*) malloc(sizeof(char) * strings[i].size() + 1);
      std::copy(strings[i].begin(), strings[i].end(), arr[i-skip]);
      arr[i-skip][strings[i].size()] = '\0';
    }

    *array = arr;
    *n = num - skip;
  }

  // helper for safe access to c_ctx
  const char* safe_str (const char* str) {
    return str == NULL ? "" : str;
  }

  int sass_compile(sass_context* c_ctx)
  {
    using namespace Sass;
    try {
      string input_path = safe_str(c_ctx->input_path);
      int lastindex = static_cast<int>(input_path.find_last_of("."));
      string output_path;
      if (!c_ctx->output_path) {
        if (input_path != "") {
          output_path = (lastindex > -1 ? input_path.substr(0, lastindex) : input_path) + ".css";
        }
      }
      else {
          output_path = c_ctx->output_path;
      }
      Context cpp_ctx(
        Context::Data().source_c_str(c_ctx->source_string)
                       .output_path(output_path)
                       .output_style((Output_Style) c_ctx->options.output_style)
                       .is_indented_syntax_src(c_ctx->options.is_indented_syntax_src)
                       .source_comments(c_ctx->options.source_comments)
                       .source_map_file(safe_str(c_ctx->options.source_map_file))
                       .omit_source_map_url(c_ctx->options.omit_source_map_url)
                       .image_path(safe_str(c_ctx->options.image_path))
                       .include_paths_c_str(c_ctx->options.include_paths)
                       .include_paths_array(0)
                       .include_paths(vector<string>())
                       .precision(c_ctx->options.precision ? c_ctx->options.precision : 5)
      );
      if (c_ctx->c_functions) {
        struct Sass_C_Function_Descriptor* this_func_data = c_ctx->c_functions;
        while (this_func_data->signature && this_func_data->function) {
          cpp_ctx.c_functions.push_back(*this_func_data);
          ++this_func_data;
        }
      }
      // by checking c_ctx->input_path, implementors can pass in an empty string
      c_ctx->output_string = c_ctx->input_path ? cpp_ctx.compile_string(input_path) :
                                                 cpp_ctx.compile_string();
      c_ctx->source_map_string = cpp_ctx.generate_source_map();
      c_ctx->error_message = 0;
      c_ctx->error_status = 0;

      copy_strings(cpp_ctx.get_included_files(), &c_ctx->included_files, &c_ctx->num_included_files, 1);
    }
    catch (Error& e) {
      stringstream msg_stream;
      msg_stream << e.path << ":" << e.position.line << ": " << e.message << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch(bad_alloc& ba) {
      stringstream msg_stream;
      msg_stream << "Unable to allocate memory: " << ba.what() << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch (std::exception& e) {
      stringstream msg_stream;
      msg_stream << "Error: " << e.what() << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch (string& e) {
      stringstream msg_stream;
      msg_stream << "Error: " << e << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch (...) {
      // couldn't find the specified file in the include paths; report an error
      stringstream msg_stream;
      msg_stream << "Unknown error occurred" << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    return 0;
  }

  int sass_compile_file(sass_file_context* c_ctx)
  {
    using namespace Sass;
    try {
      string input_path = safe_str(c_ctx->input_path);
      int lastindex = static_cast<int>(input_path.find_last_of("."));
      string output_path;
      if (!c_ctx->output_path) {
          output_path = (lastindex > -1 ? input_path.substr(0, lastindex) : input_path) + ".css";
      }
      else {
          output_path = c_ctx->output_path;
      }
      Context cpp_ctx(
        Context::Data().entry_point(input_path)
                       .output_path(output_path)
                       .output_style((Output_Style) c_ctx->options.output_style)
                       .source_comments(c_ctx->options.source_comments)
                       .source_map_file(safe_str(c_ctx->options.source_map_file))
                       .source_map_embed(c_ctx->options.source_map_embed)
                       .source_map_contents(c_ctx->options.source_map_contents)
                       .omit_source_map_url(c_ctx->options.omit_source_map_url)
                       .image_path(safe_str(c_ctx->options.image_path))
                       .include_paths_c_str(c_ctx->options.include_paths)
                       .include_paths_array(0)
                       .include_paths(vector<string>())
                       .precision(c_ctx->options.precision ? c_ctx->options.precision : 5)
      );
      if (c_ctx->c_functions) {
        struct Sass_C_Function_Descriptor* this_func_data = c_ctx->c_functions;
        while (this_func_data->signature && this_func_data->function) {
          cpp_ctx.c_functions.push_back(*this_func_data);
          ++this_func_data;
        }
      }
      c_ctx->output_string = cpp_ctx.compile_file();
      c_ctx->source_map_string = cpp_ctx.generate_source_map();
      c_ctx->error_message = 0;
      c_ctx->error_status = 0;

      copy_strings(cpp_ctx.get_included_files(), &c_ctx->included_files, &c_ctx->num_included_files);
    }
    catch (Error& e) {
      stringstream msg_stream;
      msg_stream << e.path << ":" << e.position.line << ": " << e.message << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch(bad_alloc& ba) {
      stringstream msg_stream;
      msg_stream << "Unable to allocate memory: " << ba.what() << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch (std::exception& e) {
      stringstream msg_stream;
      msg_stream << "Error: " << e.what() << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch (string& e) {
      stringstream msg_stream;
      msg_stream << "Error: " << e << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch (...) {
      // couldn't find the specified file in the include paths; report an error
      stringstream msg_stream;
      msg_stream << "Unknown error occurred" << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    return 0;
  }

  int sass_compile_folder(sass_folder_context* c_ctx)
  {
    return 1;
  }

  // caller must free the returned memory
  char* quote (const char *str, const char quotemark) {
    string quoted = Sass::quote(str, quotemark);
    char *cstr = (char*) malloc(quoted.length() + 1);
    std::strcpy(cstr, quoted.c_str());
    return cstr;
  }

  // caller must free the returned memory
  char* unquote (const char *str) {
    string unquoted = Sass::unquote(str);
    char *cstr = (char*) malloc(unquoted.length() + 1);
    std::strcpy(cstr, unquoted.c_str());
    return cstr;
  }

}
<commit_msg>Adds missing options on sass_interfaces<commit_after>#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif

#include "sass_interface.h"
#include "context.hpp"
#include "inspect.hpp"

#ifndef SASS_ERROR_HANDLING
#include "error_handling.hpp"
#endif

#include <iostream>
#include <sstream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>

extern "C" {
  using namespace std;

  sass_context* sass_new_context()
  { return (sass_context*) calloc(1, sizeof(sass_context)); }

  void free_string_array(char ** arr, int num) {
    if(!arr)
        return;

    for(int i = 0; i < num; i++) {
      free(arr[i]);
    }

    free(arr);
  }

  void sass_free_context(sass_context* ctx)
  {
    if (ctx->output_string)     free(ctx->output_string);
    if (ctx->source_map_string) free(ctx->source_map_string);
    if (ctx->error_message)     free(ctx->error_message);
    if (ctx->c_functions)       free(ctx->c_functions);

    free_string_array(ctx->included_files, ctx->num_included_files);

    free(ctx);
  }

  sass_file_context* sass_new_file_context()
  { return (sass_file_context*) calloc(1, sizeof(sass_file_context)); }

  void sass_free_file_context(sass_file_context* ctx)
  {
    if (ctx->output_string)     free(ctx->output_string);
    if (ctx->source_map_string) free(ctx->source_map_string);
    if (ctx->error_message)     free(ctx->error_message);
    if (ctx->c_functions)       free(ctx->c_functions);

    free_string_array(ctx->included_files, ctx->num_included_files);

    free(ctx);
  }

  sass_folder_context* sass_new_folder_context()
  { return (sass_folder_context*) calloc(1, sizeof(sass_folder_context)); }

  void sass_free_folder_context(sass_folder_context* ctx)
  {
    free_string_array(ctx->included_files, ctx->num_included_files);
    free(ctx);
  }

  void copy_strings(const std::vector<std::string>& strings, char*** array, int* n, int skip = 0) {
    int num = static_cast<int>(strings.size());
    char** arr = (char**) malloc(sizeof(char*)* num);

    for(int i = skip; i < num; i++) {
      arr[i-skip] = (char*) malloc(sizeof(char) * strings[i].size() + 1);
      std::copy(strings[i].begin(), strings[i].end(), arr[i-skip]);
      arr[i-skip][strings[i].size()] = '\0';
    }

    *array = arr;
    *n = num - skip;
  }

  // helper for safe access to c_ctx
  const char* safe_str (const char* str) {
    return str == NULL ? "" : str;
  }

  int sass_compile(sass_context* c_ctx)
  {
    using namespace Sass;
    try {
      string input_path = safe_str(c_ctx->input_path);
      int lastindex = static_cast<int>(input_path.find_last_of("."));
      string output_path;
      if (!c_ctx->output_path) {
        if (input_path != "") {
          output_path = (lastindex > -1 ? input_path.substr(0, lastindex) : input_path) + ".css";
        }
      }
      else {
          output_path = c_ctx->output_path;
      }
      Context cpp_ctx(
        Context::Data().source_c_str(c_ctx->source_string)
                       .output_path(output_path)
                       .output_style((Output_Style) c_ctx->options.output_style)
                       .is_indented_syntax_src(c_ctx->options.is_indented_syntax_src)
                       .source_comments(c_ctx->options.source_comments)
                       .source_map_file(safe_str(c_ctx->options.source_map_file))
                       .source_map_embed(c_ctx->options.source_map_embed)
                       .source_map_contents(c_ctx->options.source_map_contents)
                       .omit_source_map_url(c_ctx->options.omit_source_map_url)
                       .image_path(safe_str(c_ctx->options.image_path))
                       .include_paths_c_str(c_ctx->options.include_paths)
                       .include_paths_array(0)
                       .include_paths(vector<string>())
                       .precision(c_ctx->options.precision ? c_ctx->options.precision : 5)
      );
      if (c_ctx->c_functions) {
        struct Sass_C_Function_Descriptor* this_func_data = c_ctx->c_functions;
        while (this_func_data->signature && this_func_data->function) {
          cpp_ctx.c_functions.push_back(*this_func_data);
          ++this_func_data;
        }
      }
      // by checking c_ctx->input_path, implementors can pass in an empty string
      c_ctx->output_string = c_ctx->input_path ? cpp_ctx.compile_string(input_path) :
                                                 cpp_ctx.compile_string();
      c_ctx->source_map_string = cpp_ctx.generate_source_map();
      c_ctx->error_message = 0;
      c_ctx->error_status = 0;

      copy_strings(cpp_ctx.get_included_files(), &c_ctx->included_files, &c_ctx->num_included_files, 1);
    }
    catch (Error& e) {
      stringstream msg_stream;
      msg_stream << e.path << ":" << e.position.line << ": " << e.message << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch(bad_alloc& ba) {
      stringstream msg_stream;
      msg_stream << "Unable to allocate memory: " << ba.what() << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch (std::exception& e) {
      stringstream msg_stream;
      msg_stream << "Error: " << e.what() << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch (string& e) {
      stringstream msg_stream;
      msg_stream << "Error: " << e << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch (...) {
      // couldn't find the specified file in the include paths; report an error
      stringstream msg_stream;
      msg_stream << "Unknown error occurred" << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    return 0;
  }

  int sass_compile_file(sass_file_context* c_ctx)
  {
    using namespace Sass;
    try {
      string input_path = safe_str(c_ctx->input_path);
      int lastindex = static_cast<int>(input_path.find_last_of("."));
      string output_path;
      if (!c_ctx->output_path) {
          output_path = (lastindex > -1 ? input_path.substr(0, lastindex) : input_path) + ".css";
      }
      else {
          output_path = c_ctx->output_path;
      }
      Context cpp_ctx(
        Context::Data().entry_point(input_path)
                       .output_path(output_path)
                       .output_style((Output_Style) c_ctx->options.output_style)
                       .is_indented_syntax_src(c_ctx->options.is_indented_syntax_src)
                       .source_comments(c_ctx->options.source_comments)
                       .source_map_file(safe_str(c_ctx->options.source_map_file))
                       .source_map_embed(c_ctx->options.source_map_embed)
                       .source_map_contents(c_ctx->options.source_map_contents)
                       .omit_source_map_url(c_ctx->options.omit_source_map_url)
                       .image_path(safe_str(c_ctx->options.image_path))
                       .include_paths_c_str(c_ctx->options.include_paths)
                       .include_paths_array(0)
                       .include_paths(vector<string>())
                       .precision(c_ctx->options.precision ? c_ctx->options.precision : 5)
      );
      if (c_ctx->c_functions) {
        struct Sass_C_Function_Descriptor* this_func_data = c_ctx->c_functions;
        while (this_func_data->signature && this_func_data->function) {
          cpp_ctx.c_functions.push_back(*this_func_data);
          ++this_func_data;
        }
      }
      c_ctx->output_string = cpp_ctx.compile_file();
      c_ctx->source_map_string = cpp_ctx.generate_source_map();
      c_ctx->error_message = 0;
      c_ctx->error_status = 0;

      copy_strings(cpp_ctx.get_included_files(), &c_ctx->included_files, &c_ctx->num_included_files);
    }
    catch (Error& e) {
      stringstream msg_stream;
      msg_stream << e.path << ":" << e.position.line << ": " << e.message << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch(bad_alloc& ba) {
      stringstream msg_stream;
      msg_stream << "Unable to allocate memory: " << ba.what() << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch (std::exception& e) {
      stringstream msg_stream;
      msg_stream << "Error: " << e.what() << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch (string& e) {
      stringstream msg_stream;
      msg_stream << "Error: " << e << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    catch (...) {
      // couldn't find the specified file in the include paths; report an error
      stringstream msg_stream;
      msg_stream << "Unknown error occurred" << endl;
      c_ctx->error_message = strdup(msg_stream.str().c_str());
      c_ctx->error_status = 1;
      c_ctx->output_string = 0;
      c_ctx->source_map_string = 0;
    }
    return 0;
  }

  int sass_compile_folder(sass_folder_context* c_ctx)
  {
    return 1;
  }

  // caller must free the returned memory
  char* quote (const char *str, const char quotemark) {
    string quoted = Sass::quote(str, quotemark);
    char *cstr = (char*) malloc(quoted.length() + 1);
    std::strcpy(cstr, quoted.c_str());
    return cstr;
  }

  // caller must free the returned memory
  char* unquote (const char *str) {
    string unquoted = Sass::unquote(str);
    char *cstr = (char*) malloc(unquoted.length() + 1);
    std::strcpy(cstr, unquoted.c_str());
    return cstr;
  }

}
<|endoftext|>


<commit_before>#include <Function.h>
#include <algorithm>
#include <iostream>
#include <list>
#include <string>

Function::Function() {
  _head = NULL;
  _end = NULL;
  BB_computed = false;
  BB_pred_succ = false;
  dom_computed = false;
}

Function::~Function() {}

void Function::set_head(Line *head) { _head = head; }

void Function::set_end(Line *end) { _end = end; }

Line *Function::get_head() { return _head; }

Basic_block *Function::get_firstBB() { return _myBB.front(); }

Line *Function::get_end() { return _end; }
void Function::display() {
  cout << "Begin Function" << endl;
  Line *element = _head;

  if (element == _end)
    cout << _head->get_content() << endl;

  while (element != _end) {
    cout << element->get_content() << endl;

    if (element->get_next() == _end) {
      cout << element->get_next()->get_content() << endl;
      break;
    } else
      element = element->get_next();
  }
  cout << "End Function\n\n" << endl;
}

int Function::size() {
  Line *element = _head;
  int lenght = 0;
  while (element != _end) {
    lenght++;
    if (element->get_next() == _end)
      break;
    else
      element = element->get_next();
  }
  return lenght;
}

void Function::restitution(string const filename) {

  Line *element = _head;
  ofstream monflux(filename.c_str(), ios::app);

  if (monflux) {
    monflux << "Begin" << endl;
    if (element == _end)
      monflux << _head->get_content() << endl;
    while (element != _end) {
      if (element->isInst() || element->isDirective())
        monflux << "\t";

      monflux << element->get_content();

      if (element->get_content().compare("nop"))
        monflux << endl;

      if (element->get_next() == _end) {
        if (element->get_next()->isInst() || element->get_next()->isDirective())
          monflux << "\t";
        monflux << element->get_next()->get_content() << endl;
        break;
      } else
        element = element->get_next();
    }
    monflux << "End\n\n" << endl;

  }

  else {
    cout << "Error cannot open the file" << endl;
  }

  monflux.close();
}

void Function::comput_label() {
  Line *element = _head;

  if (element == _end && element->isLabel())
    _list_lab.push_back(getLabel(element));
  while (element != _end) {

    if (element->isLabel())
      _list_lab.push_back(getLabel(element));

    if (element->get_next() == _end) {
      if (element->isLabel())
        _list_lab.push_back(getLabel(element));
      break;
    } else
      element = element->get_next();
  }
}

int Function::nbr_label() { return _list_lab.size(); }

Label *Function::get_label(int index) {

  list<Label *>::iterator it;
  it = _list_lab.begin();

  int size = (int)_list_lab.size();
  if (index < size) {
    for (int i = 0; i < index; i++)
      it++;
    return *it;
  } else
    cout << "Error get_label : index is bigger than the size of the list"
      << endl;

  return _list_lab.back();
}

Basic_block *Function::find_label_BB(OPLabel *label) {
  // Basic_block *BB = new Basic_block();
  int size = (int)_myBB.size();
  string str;
  for (int i = 0; i < size; i++) {
    if (get_BB(i)->is_labeled()) {

      str = get_BB(i)->get_head()->get_content();
      if (!str.compare(0, (str.size() - 1), label->get_op())) {
        return get_BB(i);
      }
    }
  }
  return NULL;
}

/* ajoute nouveau BB à la liste de BB de la fonction en le creant */

void Function::add_BB(Line *debut, Line *fin, Line *br, int index) {
  Basic_block *b = new Basic_block();
  b->set_head(debut);
  b->set_end(fin);
  b->set_index(index);
  b->set_branch(br);
  _myBB.push_back(b);
}

// Calcule la liste des blocs de base : il faut d�limiter les BB, en parcourant
// la liste des lignes/instructions � partir de la premiere, il faut s'arreter �
// chaque branchement (et prendre en compte le delayed slot qui appartient au
// meme BB, c'est l'instruction qui suit tout branchement) ou � chaque label (on
// estime que tout label est utilis� par un saut et donc correspond bien � une
// entete de BB).

void Function::comput_basic_block() {
  Line *debut, *current, *prev;
  bool verbose = true;
  current = _head;
  debut = NULL;
  prev = NULL;
  int ind = 0;
  string str;
  Line *l = NULL;
  Instruction *i = NULL;
  Line *b;

  cout << "comput BB" << endl;
  if (verbose) {
    cout << "head :" << _head->get_content() << endl;
    cout << "tail :" << _end->get_content() << endl;
  }
  if (BB_computed)
    return; // NE PAS TOUCHER

  while (current != _end) {

    if(current->isLabel()) {
      if (debut == NULL) {
        debut = current;
      } else {
        add_BB(debut, current->get_prev(), NULL, ind);
        debut = current;
        ind++;
      }
    }
    if(current->isInst()) {
      if (debut == NULL) {
        debut = current;
      }
      i = getInst(current);

      if (i->is_branch()) {
        add_BB(debut, current->get_next(), current, ind);
        current = current->get_next();
        debut = NULL;
        ind++;
      }
      prev = current;
    }
    current = current->get_next();
  }

  if(debut != NULL) {
    add_BB(debut, prev, NULL, ind);
  }

  if (verbose)
    cout << "end comput Basic Block" << endl;

  BB_computed = true;
  return;
}

int Function::nbr_BB() { return _myBB.size(); }

Basic_block *Function::get_BB(int index) {

  list<Basic_block *>::iterator it;
  it = _myBB.begin();
  int size = (int)_myBB.size();

  if (index < size) {
    for (int i = 0; i < index; i++)
      it++;
    return *it;
  } else
    return NULL;
}

list<Basic_block *>::iterator Function::bb_list_begin() {
  return _myBB.begin();
}

list<Basic_block *>::iterator Function::bb_list_end() { return _myBB.end(); }

/* comput_pred_succ calcule les successeurs et prédécesseur des BB, pour cela il
 * faut commencer par les successeurs */
/* et itérer sur tous les BB d'une fonction */
/* il faut determiner si un BB a un ou deux successeurs : dépend de la présence
 * d'un saut présent ou non à la fin */
/* pas de saut ou saut incontionnel ou appel de fonction : 1 successeur (lequel
 * ?)*/
/* branchement conditionnel : 2 successeurs */
/* le dernier bloc n'a pas de successeurs - celui qui se termine par jr R31 */
/* les sauts indirects n'ont pas de successeur */

void Function::comput_succ_pred_BB() {

  list<Basic_block *>::iterator it, it2;
  Basic_block *current;
  Instruction *instr;
  Basic_block *succ = NULL;
  Line *line = NULL;
  if (BB_pred_succ)
    return;

  // A REMPLIR TODO
  for (it = bb_list_begin(); it != bb_list_end(); it++) {

    current = *it;
    line = current->get_branch();

    if (line != NULL) {
      instr = getInst(line);

      if (instr->is_indirect_branch()) {
        // Add next block
        current->set_link_succ_pred(*it++);
      }
      if (instr->is_call()) {
        // Add next block
        current->set_link_succ_pred(*it++);

      } else if (instr->is_cond_branch()) {
        // Add branch block and rest
        succ = find_label_BB(instr->get_op_label());
        current->set_link_succ_pred(succ);
        current->set_link_succ_pred(*it++);
      }
    }
  }
  // ne pas toucher ci-dessous
  BB_pred_succ = true;
  return;
}

vector<bool> intersection(vector<bool> &v1, vector<bool> &v2) {
  vector<bool> v3;
  for(int i = 0; i < v1.size(); i++) {
    if(v1[i] && v2[i]) {
      v3.push_back(false);
    } else {
      v3.push_back(true);
    }
  }
  return v3;
}

void Function::compute_dom() {
  list<Basic_block *>::iterator it, it2;
  list<Basic_block *> workinglist;
  Basic_block *current, *bb, *pred;
  bool change = true;
  int size = _myBB.size();
  if (dom_computed)
    return;
  comput_succ_pred_BB();

  /* A REMPLIR */
  vector<bool> setT;
  vector<bool> setD;
  Basic_block *succ;
  workinglist.push_back(*(_myBB.begin()));      /* init list BB */

  while (workinglist.size() != 0) {
    change = false;
    current = workinglist.front();
    workinglist.pop_front();

    setT = {};
    it = _myBB.begin();
    int tmp = 0;
    int index = 0;
    for (int i = 0; i < size; i++) {  // TODO: check if T = N good
      if (current == *it) {
        index = tmp;                  //Get index
      }
      bb = *it;
      setT.push_back(false);
      tmp++;
      it++;
    }

    for (int i = 0; i < current->get_nb_pred(); i++) {
      pred = bb->get_predecessor(i);
      setT = intersection(setT, pred->Domin);
    }

    setD = setT;
    setD[index] = true; //Add himself

    if (setD != current->Domin) {
      current->Domin = setD;
      change = true;
    }

    if (change) {
      for (int i = 0; i < current->get_nb_succ(); i++) {
        succ = bb->get_successor1();
        if(succ) {
          workinglist.push_back(succ);
        }
        succ = bb->get_successor2();
        if(succ) {
          workinglist.push_back(succ);
        }
      }
    }
  }

  // affichage du resultat
  it = _myBB.begin();

  for (int j = 0; j < size; j++) {
    current = *it;
    cout << "Dominants pour BB" << current->get_index() << " : ";
    for (int i = 0; i < nbr_BB(); i++) {
      if (current->Domin[i])
        cout << " BB" << i;
    }
    cout << endl;
    it++;
  }
  dom_computed = true;
  return;
}

void Function::compute_live_var() {
  list<Basic_block *>::iterator it, it2;
  list<Basic_block *> workinglist;
  Basic_block *current, *bb, *pred;
  bool change = true;
  int size = (int)_myBB.size();
  it = _myBB.begin();

  /* A REMPLIR avec algo vu en cours et en TD*/
  /* algorithme itératif qui part des blocs sans successeur, ne pas oublier
   * que
   * lorsque l'on sort d'une fonction le registre $2 contient le résultat (il
   * est donc vivant), le registre pointeur de pile ($29) est aussi vivant !
   */

  // Affichage du resultat
  it2 = _myBB.begin();
  for (int j = 0; j < size; j++) {
    bb = *it2;
    cout << "********* bb " << bb->get_index() << "***********" << endl;
    cout << "LIVE_OUT : ";
    for (int i = 0; i < NB_REG; i++) {
      if (bb->LiveOut[i]) {
        cout << "$" << i << " ";
      }
    }
    cout << endl;
    cout << "LIVE_IN :  ";
    for (int i = 0; i < NB_REG; i++) {
      if (bb->LiveIn[i]) {
        cout << "$" << i << " ";
      }
    }
    cout << endl;
    it2++;
  }
  return;
}

/* en implementant la fonction test de la classe BB, permet de tester des
 * choses
 * sur tous les blocs de base d'une fonction par exemple l'affichage de tous
 * les
 * BB d'une fonction ou l'affichage des succ/pred des BBs comme c'est le cas
 * --
 * voir la classe Basic_block et la méthode test */

void Function::test() {
  int size = (int)_myBB.size();
  for (int i = 0; i < size; i++) {
    get_BB(i)->test();
  }
  return;
}
<commit_msg>searching bug in Function<commit_after>#include <Function.h>
#include <algorithm>
#include <iostream>
#include <list>
#include <string>

Function::Function() {
  _head = NULL;
  _end = NULL;
  BB_computed = false;
  BB_pred_succ = false;
  dom_computed = false;
}

Function::~Function() {}

void Function::set_head(Line *head) { _head = head; }

void Function::set_end(Line *end) { _end = end; }

Line *Function::get_head() { return _head; }

Basic_block *Function::get_firstBB() { return _myBB.front(); }

Line *Function::get_end() { return _end; }
void Function::display() {
  cout << "Begin Function" << endl;
  Line *element = _head;

  if (element == _end)
    cout << _head->get_content() << endl;

  while (element != _end) {
    cout << element->get_content() << endl;

    if (element->get_next() == _end) {
      cout << element->get_next()->get_content() << endl;
      break;
    } else
      element = element->get_next();
  }
  cout << "End Function\n\n" << endl;
}

int Function::size() {
  Line *element = _head;
  int lenght = 0;
  while (element != _end) {
    lenght++;
    if (element->get_next() == _end)
      break;
    else
      element = element->get_next();
  }
  return lenght;
}

void Function::restitution(string const filename) {

  Line *element = _head;
  ofstream monflux(filename.c_str(), ios::app);

  if (monflux) {
    monflux << "Begin" << endl;
    if (element == _end)
      monflux << _head->get_content() << endl;
    while (element != _end) {
      if (element->isInst() || element->isDirective())
        monflux << "\t";

      monflux << element->get_content();

      if (element->get_content().compare("nop"))
        monflux << endl;

      if (element->get_next() == _end) {
        if (element->get_next()->isInst() || element->get_next()->isDirective())
          monflux << "\t";
        monflux << element->get_next()->get_content() << endl;
        break;
      } else
        element = element->get_next();
    }
    monflux << "End\n\n" << endl;

  }

  else {
    cout << "Error cannot open the file" << endl;
  }

  monflux.close();
}

void Function::comput_label() {
  Line *element = _head;

  if (element == _end && element->isLabel())
    _list_lab.push_back(getLabel(element));
  while (element != _end) {

    if (element->isLabel())
      _list_lab.push_back(getLabel(element));

    if (element->get_next() == _end) {
      if (element->isLabel())
        _list_lab.push_back(getLabel(element));
      break;
    } else
      element = element->get_next();
  }
}

int Function::nbr_label() { return _list_lab.size(); }

Label *Function::get_label(int index) {

  list<Label *>::iterator it;
  it = _list_lab.begin();

  int size = (int)_list_lab.size();
  if (index < size) {
    for (int i = 0; i < index; i++)
      it++;
    return *it;
  } else
    cout << "Error get_label : index is bigger than the size of the list"
      << endl;

  return _list_lab.back();
}

Basic_block *Function::find_label_BB(OPLabel *label) {
  // Basic_block *BB = new Basic_block();
  int size = (int)_myBB.size();
  string str;
  for (int i = 0; i < size; i++) {
    if (get_BB(i)->is_labeled()) {

      str = get_BB(i)->get_head()->get_content();
      if (!str.compare(0, (str.size() - 1), label->get_op())) {
        return get_BB(i);
      }
    }
  }
  return NULL;
}

/* ajoute nouveau BB à la liste de BB de la fonction en le creant */

void Function::add_BB(Line *debut, Line *fin, Line *br, int index) {
  Basic_block *b = new Basic_block();
  b->set_head(debut);
  b->set_end(fin);
  b->set_index(index);
  b->set_branch(br);
  _myBB.push_back(b);
}

// Calcule la liste des blocs de base : il faut d�limiter les BB, en parcourant
// la liste des lignes/instructions � partir de la premiere, il faut s'arreter �
// chaque branchement (et prendre en compte le delayed slot qui appartient au
// meme BB, c'est l'instruction qui suit tout branchement) ou � chaque label (on
// estime que tout label est utilis� par un saut et donc correspond bien � une
// entete de BB).

void Function::comput_basic_block() {
  Line *debut, *current, *prev;
  bool verbose = true;
  current = _head;
  debut = NULL;
  prev = NULL;
  int ind = 0;
  string str;
  Line *l = NULL;
  Instruction *i = NULL;
  Line *b;

  cout << "comput BB" << endl;
  if (verbose) {
    cout << "head :" << _head->get_content() << endl;
    cout << "tail :" << _end->get_content() << endl;
  }
  if (BB_computed)
    return; // NE PAS TOUCHER

  while (current != _end) {

    if(current->isLabel()) {
      if (debut == NULL) {
        debut = current;
      } else {
        add_BB(debut, current->get_prev(), NULL, ind);
        debut = current;
        ind++;
      }
    }
    if(current->isInst()) {
      if (debut == NULL) {
        debut = current;
      }
      i = getInst(current);

      if (i->is_branch()) {
        add_BB(debut, current->get_next(), current, ind);
        current = current->get_next();
        debut = NULL;
        ind++;
      }
      prev = current;
    }
    current = current->get_next();
  }

  if(debut != NULL) {
    cout << "basic_block.debut != null" << endl;
    add_BB(debut, prev, NULL, ind);
  }

  if (verbose)
    cout << "end comput Basic Block" << endl;

  BB_computed = true;
  return;
}

int Function::nbr_BB() { return _myBB.size(); }

Basic_block *Function::get_BB(int index) {

  list<Basic_block *>::iterator it;
  it = _myBB.begin();
  int size = (int)_myBB.size();

  if (index < size) {
    for (int i = 0; i < index; i++)
      it++;
    return *it;
  } else
    return NULL;
}

list<Basic_block *>::iterator Function::bb_list_begin() {
  return _myBB.begin();
}

list<Basic_block *>::iterator Function::bb_list_end() { return _myBB.end(); }

/* comput_pred_succ calcule les successeurs et prédécesseur des BB, pour cela il
 * faut commencer par les successeurs */
/* et itérer sur tous les BB d'une fonction */
/* il faut determiner si un BB a un ou deux successeurs : dépend de la présence
 * d'un saut présent ou non à la fin */
/* pas de saut ou saut incontionnel ou appel de fonction : 1 successeur (lequel
 * ?)*/
/* branchement conditionnel : 2 successeurs */
/* le dernier bloc n'a pas de successeurs - celui qui se termine par jr R31 */
/* les sauts indirects n'ont pas de successeur */

void Function::comput_succ_pred_BB() {

  list<Basic_block *>::iterator it, it2;
  Basic_block *current;
  Instruction *instr;
  Basic_block *succ = NULL;
  Line *line = NULL;
  if (BB_pred_succ)
    return;

  // A REMPLIR TODO
  //for (it = bb_list_begin(); it != bb_list_end(); it++) {
  //current = *it;
  for (int index = 0; (current = get_BB(index)); index++) {
    cout << index << endl;

    line = current->get_branch();
    cout << "Pass line" << endl;

    if (line != NULL) {
      cout << line->to_string() << endl;
      instr = getInst(line);
      cout << "Pass getInst" << endl;

//TODO: debug here
      if (instr->is_indirect_branch()) {
        // Add next block
        cout << "Pass startind" << endl;
        current->set_link_succ_pred(get_BB(index+1));
        cout << "Pass endind" << endl;
      }
      if (instr->is_call()) {
        // Add next block
        cout << "Pass startcall" << endl;
        current->set_link_succ_pred(get_BB(index+1));
        cout << "Pass endcall" << endl;

      } else if (instr->is_cond_branch()) {
        // Add branch block and rest
        cout << "Pass startbranch" << endl;
        succ = find_label_BB(instr->get_op_label());
        cout << "Pass find_label" << endl;
        current->set_link_succ_pred(succ);
        current->set_link_succ_pred(get_BB(index+1));
        cout << "Pass endbranch" << endl;
      }
    }
    cout << "Pass loop" << endl;
  }
  // ne pas toucher ci-dessous
  BB_pred_succ = true;
  return;
}

vector<bool> intersection(vector<bool> &v1, vector<bool> &v2) {
  vector<bool> v3;
  for(int i = 0; i < v1.size(); i++) {
    if(v1[i] && v2[i]) {
      v3.push_back(false);
    } else {
      v3.push_back(true);
    }
  }
  return v3;
}

void Function::compute_dom() {
  list<Basic_block *>::iterator it, it2;
  list<Basic_block *> workinglist;
  Basic_block *current, *bb, *pred;
  bool change = true;
  int size = _myBB.size();
  if (dom_computed)
    return;
  comput_succ_pred_BB();

  /* A REMPLIR */
  vector<bool> setT;
  vector<bool> setD;
  Basic_block *succ;
  workinglist.push_back(*(_myBB.begin()));      /* init list BB */

  while (workinglist.size() != 0) {
    change = false;
    current = workinglist.front();
    workinglist.pop_front();

    setT = {};
    it = _myBB.begin();
    int tmp = 0;
    int index = 0;
    for (int i = 0; i < size; i++) {  // TODO: check if T = N good
      if (current == *it) {
        index = tmp;                  //Get index
      }
      bb = *it;
      setT.push_back(false);
      tmp++;
      it++;
    }

    for (int i = 0; i < current->get_nb_pred(); i++) {
      pred = bb->get_predecessor(i);
      setT = intersection(setT, pred->Domin);
    }

    setD = setT;
    setD[index] = true; //Add himself

    if (setD != current->Domin) {
      current->Domin = setD;
      change = true;
    }

    if (change) {
      for (int i = 0; i < current->get_nb_succ(); i++) {
        succ = bb->get_successor1();
        if(succ) {
          workinglist.push_back(succ);
        }
        succ = bb->get_successor2();
        if(succ) {
          workinglist.push_back(succ);
        }
      }
    }
  }

  // affichage du resultat
  it = _myBB.begin();

  for (int j = 0; j < size; j++) {
    current = *it;
    cout << "Dominants pour BB" << current->get_index() << " : ";
    for (int i = 0; i < nbr_BB(); i++) {
      if (current->Domin[i])
        cout << " BB" << i;
    }
    cout << endl;
    it++;
  }
  dom_computed = true;
  return;
}

void Function::compute_live_var() {
  list<Basic_block *>::iterator it, it2;
  list<Basic_block *> workinglist;
  Basic_block *current, *bb, *pred;
  bool change = true;
  int size = (int)_myBB.size();
  it = _myBB.begin();

  /* A REMPLIR avec algo vu en cours et en TD*/
  /* algorithme itératif qui part des blocs sans successeur, ne pas oublier
   * que
   * lorsque l'on sort d'une fonction le registre $2 contient le résultat (il
   * est donc vivant), le registre pointeur de pile ($29) est aussi vivant !
   */

  // Affichage du resultat
  it2 = _myBB.begin();
  for (int j = 0; j < size; j++) {
    bb = *it2;
    cout << "********* bb " << bb->get_index() << "***********" << endl;
    cout << "LIVE_OUT : ";
    for (int i = 0; i < NB_REG; i++) {
      if (bb->LiveOut[i]) {
        cout << "$" << i << " ";
      }
    }
    cout << endl;
    cout << "LIVE_IN :  ";
    for (int i = 0; i < NB_REG; i++) {
      if (bb->LiveIn[i]) {
        cout << "$" << i << " ";
      }
    }
    cout << endl;
    it2++;
  }
  return;
}

/* en implementant la fonction test de la classe BB, permet de tester des
 * choses
 * sur tous les blocs de base d'une fonction par exemple l'affichage de tous
 * les
 * BB d'une fonction ou l'affichage des succ/pred des BBs comme c'est le cas
 * --
 * voir la classe Basic_block et la méthode test */

void Function::test() {
  int size = (int)_myBB.size();
  for (int i = 0; i < size; i++) {
    get_BB(i)->test();
  }
  return;
}
<|endoftext|>


<commit_before><commit_msg>limit the number of sheets again to 10000<commit_after><|endoftext|>


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

#include <batchedlogger.h>
#include <logging.h>

CBatchedLogger::CBatchedLogger(uint64_t _category, const std::string& _header) :
    accept(LogAcceptCategory(_category)), header(_header)
{
}

CBatchedLogger::~CBatchedLogger()
{
    Flush();
}

void CBatchedLogger::Flush()
{
    if (!accept || msg.empty()) {
        return;
    }
    LogPrintStr(strprintf("%s:\n%s", header, msg));
    msg.clear();
}
<commit_msg>fix logprintstr<commit_after>// Copyright (c) 2018-2019 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <batchedlogger.h>
#include <logging.h>

CBatchedLogger::CBatchedLogger(uint64_t _category, const std::string& _header) :
    accept(LogAcceptCategory(_category)), header(_header)
{
}

CBatchedLogger::~CBatchedLogger()
{
    Flush();
}

void CBatchedLogger::Flush()
{
    if (!accept || msg.empty()) {
        return;
    }
    LogInstance().LogPrintStr(strprintf("%s:\n%s", header, msg));
    msg.clear();
}
<|endoftext|>


<commit_before>//
// PROJECT:         Aspia Remote Desktop
// FILE:            host/desktop_session_launcher.cc
// LICENSE:         See top-level directory
// PROGRAMMERS:     Dmitry Chapyshev (dmitry@aspia.ru)
//

#include "host/desktop_session_launcher.h"

#include <userenv.h>
#include <wtsapi32.h>
#include <string>

#include "base/version_helpers.h"
#include "base/process_helpers.h"
#include "base/service_manager.h"
#include "base/scoped_object.h"
#include "base/scoped_wts_memory.h"
#include "base/scoped_impersonator.h"
#include "base/object_watcher.h"
#include "base/unicode.h"
#include "base/path.h"
#include "base/process.h"
#include "base/logging.h"

namespace aspia {

static const WCHAR kServiceShortName[] = L"aspia-desktop-session-launcher";
static const WCHAR kServiceFullName[] = L"Aspia Desktop Session Launcher";

// Name of the default session desktop.
static WCHAR kDefaultDesktopName[] = L"winsta0\\default";

DesktopSessionLauncher::DesktopSessionLauncher(const std::wstring& service_id) :
    Service(ServiceManager::CreateUniqueServiceName(kServiceShortName, service_id))
{
    // Nothing
}

static bool CopyProcessToken(DWORD desired_access, ScopedHandle* token_out)
{
    ScopedHandle process_token;

    if (!OpenProcessToken(GetCurrentProcess(),
                          TOKEN_DUPLICATE | desired_access,
                          process_token.Recieve()))
    {
        LOG(ERROR) << "OpenProcessToken() failed: " << GetLastError();
        return false;
    }

    if (!DuplicateTokenEx(process_token,
                          desired_access,
                          nullptr,
                          SecurityImpersonation,
                          TokenPrimary,
                          token_out->Recieve()))
    {
        LOG(ERROR) << "DuplicateTokenEx() failed: " << GetLastError();
        return false;
    }

    return true;
}

// Creates a copy of the current process with SE_TCB_NAME privilege enabled.
static bool CreatePrivilegedToken(ScopedHandle* token_out)
{
    ScopedHandle privileged_token;
    DWORD desired_access = TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE |
        TOKEN_DUPLICATE | TOKEN_QUERY;

    if (!CopyProcessToken(desired_access, &privileged_token))
        return false;

    // Get the LUID for the SE_TCB_NAME privilege.
    TOKEN_PRIVILEGES state;
    state.PrivilegeCount = 1;
    state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!LookupPrivilegeValueW(nullptr, SE_TCB_NAME, &state.Privileges[0].Luid))
    {
        LOG(ERROR) << "LookupPrivilegeValueW() failed: " << GetLastError();
        return false;
    }

    // Enable the SE_TCB_NAME privilege.
    if (!AdjustTokenPrivileges(privileged_token, FALSE, &state, 0, nullptr, 0))
    {
        LOG(ERROR) << "AdjustTokenPrivileges() failed: " << GetLastError();
        return false;
    }

    token_out->Reset(privileged_token.Release());
    return true;
}

// Creates a copy of the current process token for the given |session_id| so
// it can be used to launch a process in that session.
static bool CreateSessionToken(uint32_t session_id, ScopedHandle* token_out)
{
    ScopedHandle session_token;
    DWORD desired_access = TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID |
        TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY;

    if (!CopyProcessToken(desired_access, &session_token))
        return false;

    ScopedHandle privileged_token;

    if (!CreatePrivilegedToken(&privileged_token))
        return false;

    {
        ScopedImpersonator impersonator;

        if (!impersonator.ImpersonateLoggedOnUser(privileged_token))
            return false;

        // Change the session ID of the token.
        DWORD new_session_id = session_id;
        if (!SetTokenInformation(session_token,
                                 TokenSessionId,
                                 &new_session_id,
                                 sizeof(new_session_id)))
        {
            LOG(ERROR) << "SetTokenInformation() failed: " << GetLastError();
            return false;
        }
    }

    token_out->Reset(session_token.Release());
    return true;
}

static bool CreateProcessWithToken(HANDLE user_token, const std::wstring& command_line)
{
    PROCESS_INFORMATION process_info = { 0 };
    STARTUPINFOW startup_info = { 0 };

    startup_info.cb = sizeof(startup_info);
    startup_info.lpDesktop = kDefaultDesktopName;

    if (!CreateProcessAsUserW(user_token,
                              nullptr,
                              const_cast<LPWSTR>(command_line.c_str()),
                              nullptr,
                              nullptr,
                              FALSE,
                              0,
                              nullptr,
                              nullptr,
                              &startup_info,
                              &process_info))
    {
        LOG(ERROR) << "CreateProcessAsUserW() failed: " << GetLastError();
        return false;
    }

    CloseHandle(process_info.hThread);
    CloseHandle(process_info.hProcess);

    return true;
}

static bool LaunchProcessInSession(uint32_t session_id,
                                   const std::wstring& input_channel_id,
                                   const std::wstring& output_channel_id)
{
    std::wstring command_line;

    if (!GetPathW(PathKey::FILE_EXE, command_line))
        return false;

    command_line.append(L" --run_mode=");

    command_line.append(kDesktopSessionSwitch);

    command_line.append(L" --input_channel_id=");
    command_line.append(input_channel_id);
    command_line.append(L" --output_channel_id=");
    command_line.append(output_channel_id);

    ScopedHandle session_token;

    if (!CreateSessionToken(session_id, &session_token))
        return false;

    return CreateProcessWithToken(session_token, command_line);
}

void DesktopSessionLauncher::Worker()
{
    LaunchProcessInSession(session_id_, input_channel_id_, output_channel_id_);
}

void DesktopSessionLauncher::OnStop()
{
    // Nothing
}

void DesktopSessionLauncher::ExecuteService(uint32_t session_id,
                                            const std::wstring& input_channel_id,
                                            const std::wstring& output_channel_id)
{
    session_id_ = session_id;
    input_channel_id_ = input_channel_id;
    output_channel_id_ = output_channel_id;

    Run();

    ServiceManager(ServiceName()).Remove();
}

// static
bool DesktopSessionLauncher::LaunchSession(uint32_t session_id,
                                           const std::wstring& input_channel_id,
                                           const std::wstring& output_channel_id)
{
    std::wstring command_line;

    if (!GetPathW(PathKey::FILE_EXE, command_line))
        return false;

    command_line.append(L" --input_channel_id=");
    command_line.append(input_channel_id);
    command_line.append(L" --output_channel_id=");
    command_line.append(output_channel_id);

    if (!IsCallerHasAdminRights())
    {
        command_line.append(L" --run_mode=");
        command_line.append(kDesktopSessionSwitch);

        ScopedHandle token;

        if (!CopyProcessToken(TOKEN_ALL_ACCESS, &token))
            return false;

        return CreateProcessWithToken(token, command_line);
    }
    else
    {
        typedef BOOL(WINAPI *ProcessIdToSessionIdFn)(DWORD, DWORD*);

        HMODULE kernel32_module = GetModuleHandleW(L"kernel32.dll");
        CHECK(kernel32_module);

        ProcessIdToSessionIdFn process_id_to_session_id =
            reinterpret_cast<ProcessIdToSessionIdFn>(
                GetProcAddress(kernel32_module, "ProcessIdToSessionId"));
        CHECK(process_id_to_session_id);

        DWORD current_process_session_id;

        if (!process_id_to_session_id(GetCurrentProcessId(), &current_process_session_id))
        {
            LOG(WARNING) << "ProcessIdToSessionId() failed: " << GetLastError();
            return false;
        }

        // If the current process is started not in session 0 (not as a service),
        // then we create a service to start the process in the required session.
        if (!IsWindowsVistaOrGreater() || current_process_session_id != 0)
        {
            std::wstring service_id =
                ServiceManager::GenerateUniqueServiceId();

            std::wstring unique_name =
                ServiceManager::CreateUniqueServiceName(kServiceShortName, service_id);

            command_line.append(L" --run_mode=");
            command_line.append(kDesktopSessionLauncherSwitch);
            command_line.append(L" --session_id=");
            command_line.append(std::to_wstring(session_id));

            command_line.append(L" --service_id=");
            command_line.append(service_id);

            // Install the service in the system.
            ServiceManager manager(ServiceManager::Create(command_line,
                                                          kServiceFullName,
                                                          unique_name));

            // If the service was not installed.
            if (!manager.IsValid())
                return false;

            return manager.Start();
        }
        else // The code is executed from the service.
        {
            // Start the process directly.
            return LaunchProcessInSession(session_id, input_channel_id, output_channel_id);
        }
    }
}

} // namespace aspia
<commit_msg>- Using referenses instead pointers<commit_after>//
// PROJECT:         Aspia Remote Desktop
// FILE:            host/desktop_session_launcher.cc
// LICENSE:         See top-level directory
// PROGRAMMERS:     Dmitry Chapyshev (dmitry@aspia.ru)
//

#include "host/desktop_session_launcher.h"

#include <userenv.h>
#include <wtsapi32.h>
#include <string>

#include "base/version_helpers.h"
#include "base/process_helpers.h"
#include "base/service_manager.h"
#include "base/scoped_object.h"
#include "base/scoped_wts_memory.h"
#include "base/scoped_impersonator.h"
#include "base/object_watcher.h"
#include "base/unicode.h"
#include "base/path.h"
#include "base/process.h"
#include "base/logging.h"

namespace aspia {

static const WCHAR kServiceShortName[] = L"aspia-desktop-session-launcher";
static const WCHAR kServiceFullName[] = L"Aspia Desktop Session Launcher";

// Name of the default session desktop.
static WCHAR kDefaultDesktopName[] = L"winsta0\\default";

DesktopSessionLauncher::DesktopSessionLauncher(const std::wstring& service_id) :
    Service(ServiceManager::CreateUniqueServiceName(kServiceShortName, service_id))
{
    // Nothing
}

static bool CopyProcessToken(DWORD desired_access, ScopedHandle& token_out)
{
    ScopedHandle process_token;

    if (!OpenProcessToken(GetCurrentProcess(),
                          TOKEN_DUPLICATE | desired_access,
                          process_token.Recieve()))
    {
        LOG(ERROR) << "OpenProcessToken() failed: " << GetLastError();
        return false;
    }

    if (!DuplicateTokenEx(process_token,
                          desired_access,
                          nullptr,
                          SecurityImpersonation,
                          TokenPrimary,
                          token_out.Recieve()))
    {
        LOG(ERROR) << "DuplicateTokenEx() failed: " << GetLastError();
        return false;
    }

    return true;
}

// Creates a copy of the current process with SE_TCB_NAME privilege enabled.
static bool CreatePrivilegedToken(ScopedHandle& token_out)
{
    ScopedHandle privileged_token;
    DWORD desired_access = TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE |
        TOKEN_DUPLICATE | TOKEN_QUERY;

    if (!CopyProcessToken(desired_access, privileged_token))
        return false;

    // Get the LUID for the SE_TCB_NAME privilege.
    TOKEN_PRIVILEGES state;
    state.PrivilegeCount = 1;
    state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!LookupPrivilegeValueW(nullptr, SE_TCB_NAME, &state.Privileges[0].Luid))
    {
        LOG(ERROR) << "LookupPrivilegeValueW() failed: " << GetLastError();
        return false;
    }

    // Enable the SE_TCB_NAME privilege.
    if (!AdjustTokenPrivileges(privileged_token, FALSE, &state, 0, nullptr, 0))
    {
        LOG(ERROR) << "AdjustTokenPrivileges() failed: " << GetLastError();
        return false;
    }

    token_out.Reset(privileged_token.Release());
    return true;
}

// Creates a copy of the current process token for the given |session_id| so
// it can be used to launch a process in that session.
static bool CreateSessionToken(uint32_t session_id, ScopedHandle& token_out)
{
    ScopedHandle session_token;
    DWORD desired_access = TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID |
        TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY;

    if (!CopyProcessToken(desired_access, session_token))
        return false;

    ScopedHandle privileged_token;

    if (!CreatePrivilegedToken(privileged_token))
        return false;

    {
        ScopedImpersonator impersonator;

        if (!impersonator.ImpersonateLoggedOnUser(privileged_token))
            return false;

        // Change the session ID of the token.
        DWORD new_session_id = session_id;
        if (!SetTokenInformation(session_token,
                                 TokenSessionId,
                                 &new_session_id,
                                 sizeof(new_session_id)))
        {
            LOG(ERROR) << "SetTokenInformation() failed: " << GetLastError();
            return false;
        }
    }

    token_out.Reset(session_token.Release());
    return true;
}

static bool CreateProcessWithToken(HANDLE user_token, const std::wstring& command_line)
{
    PROCESS_INFORMATION process_info = { 0 };
    STARTUPINFOW startup_info = { 0 };

    startup_info.cb = sizeof(startup_info);
    startup_info.lpDesktop = kDefaultDesktopName;

    if (!CreateProcessAsUserW(user_token,
                              nullptr,
                              const_cast<LPWSTR>(command_line.c_str()),
                              nullptr,
                              nullptr,
                              FALSE,
                              0,
                              nullptr,
                              nullptr,
                              &startup_info,
                              &process_info))
    {
        LOG(ERROR) << "CreateProcessAsUserW() failed: " << GetLastError();
        return false;
    }

    CloseHandle(process_info.hThread);
    CloseHandle(process_info.hProcess);

    return true;
}

static bool LaunchProcessInSession(uint32_t session_id,
                                   const std::wstring& input_channel_id,
                                   const std::wstring& output_channel_id)
{
    std::wstring command_line;

    if (!GetPathW(PathKey::FILE_EXE, command_line))
        return false;

    command_line.append(L" --run_mode=");

    command_line.append(kDesktopSessionSwitch);

    command_line.append(L" --input_channel_id=");
    command_line.append(input_channel_id);
    command_line.append(L" --output_channel_id=");
    command_line.append(output_channel_id);

    ScopedHandle session_token;

    if (!CreateSessionToken(session_id, session_token))
        return false;

    return CreateProcessWithToken(session_token, command_line);
}

void DesktopSessionLauncher::Worker()
{
    LaunchProcessInSession(session_id_, input_channel_id_, output_channel_id_);
}

void DesktopSessionLauncher::OnStop()
{
    // Nothing
}

void DesktopSessionLauncher::ExecuteService(uint32_t session_id,
                                            const std::wstring& input_channel_id,
                                            const std::wstring& output_channel_id)
{
    session_id_ = session_id;
    input_channel_id_ = input_channel_id;
    output_channel_id_ = output_channel_id;

    Run();

    ServiceManager(ServiceName()).Remove();
}

// static
bool DesktopSessionLauncher::LaunchSession(uint32_t session_id,
                                           const std::wstring& input_channel_id,
                                           const std::wstring& output_channel_id)
{
    std::wstring command_line;

    if (!GetPathW(PathKey::FILE_EXE, command_line))
        return false;

    command_line.append(L" --input_channel_id=");
    command_line.append(input_channel_id);
    command_line.append(L" --output_channel_id=");
    command_line.append(output_channel_id);

    if (!IsCallerHasAdminRights())
    {
        command_line.append(L" --run_mode=");
        command_line.append(kDesktopSessionSwitch);

        ScopedHandle token;

        if (!CopyProcessToken(TOKEN_ALL_ACCESS, token))
            return false;

        return CreateProcessWithToken(token, command_line);
    }
    else
    {
        typedef BOOL(WINAPI *ProcessIdToSessionIdFn)(DWORD, DWORD*);

        HMODULE kernel32_module = GetModuleHandleW(L"kernel32.dll");
        CHECK(kernel32_module);

        ProcessIdToSessionIdFn process_id_to_session_id =
            reinterpret_cast<ProcessIdToSessionIdFn>(
                GetProcAddress(kernel32_module, "ProcessIdToSessionId"));
        CHECK(process_id_to_session_id);

        DWORD current_process_session_id;

        if (!process_id_to_session_id(GetCurrentProcessId(), &current_process_session_id))
        {
            LOG(WARNING) << "ProcessIdToSessionId() failed: " << GetLastError();
            return false;
        }

        // If the current process is started not in session 0 (not as a service),
        // then we create a service to start the process in the required session.
        if (!IsWindowsVistaOrGreater() || current_process_session_id != 0)
        {
            std::wstring service_id =
                ServiceManager::GenerateUniqueServiceId();

            std::wstring unique_name =
                ServiceManager::CreateUniqueServiceName(kServiceShortName, service_id);

            command_line.append(L" --run_mode=");
            command_line.append(kDesktopSessionLauncherSwitch);
            command_line.append(L" --session_id=");
            command_line.append(std::to_wstring(session_id));

            command_line.append(L" --service_id=");
            command_line.append(service_id);

            // Install the service in the system.
            ServiceManager manager(ServiceManager::Create(command_line,
                                                          kServiceFullName,
                                                          unique_name));

            // If the service was not installed.
            if (!manager.IsValid())
                return false;

            return manager.Start();
        }
        else // The code is executed from the service.
        {
            // Start the process directly.
            return LaunchProcessInSession(session_id, input_channel_id, output_channel_id);
        }
    }
}

} // namespace aspia
<|endoftext|>


<commit_before>//
//
// MIT License
//
// Copyright (c) 2017 Stellacore Corporation.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//

/*! \file
\brief  This file contains unit test for prob::mean
*/

#include "libprob/mean.h"

#include "libdat/compare.h"
#include "libdat/info.h"
#include "libdat/validity.h"
#include "libio/stream.h"

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

namespace
{

//! Check for common functions
std::string
prob_mean_test0
	()
{
	std::ostringstream oss;
	/*
	prob::mean const aNull(dat::nullValue<prob::mean>());
	if (dat::isValid(aNull))
	{
		oss << "Failure of null value test" << std::endl;
		oss << "infoString: " << dat::infoString(aNull) << std::endl;
	}
	*/
	return oss.str();
}

//! Check error cases (involving negative numbers)
std::string
prob_mean_test1
	()
{
	std::ostringstream oss;

	// only arithmetic mean is defined if non positive values
	std::vector<double> const mix{ 2., 1., -2., 3. };
	double const expAri{ 1. };
	double const expGeo{ dat::nullValue<double>() };
	double const expHar{ dat::nullValue<double>() };
	double const gotAri{ prob::mean::arithmetic(mix.begin(), mix.end()) };
	double const gotGeo{ prob::mean::geometric(mix.begin(), mix.end()) };
	double const gotHar{ prob::mean::harmonic(mix.begin(), mix.end()) };
	if (! dat::nearlyEquals(gotAri, expAri))
	{
		oss << "Failure of arithmetic mean mixed data test" << std::endl;
		oss << dat::infoString(expAri, "expAri") << std::endl;
		oss << dat::infoString(gotAri, "gotAri") << std::endl;
	}
	if (dat::isValid(gotGeo))
	{
		oss << "Failure of geometric mean mixed data test" << std::endl;
		oss << dat::infoString(expGeo, "expGeo") << std::endl;
		oss << dat::infoString(gotGeo, "gotGeo") << std::endl;
	}
	if (dat::isValid(gotHar))
	{
		oss << "Failure of harmonic mean mixed data test" << std::endl;
		oss << dat::infoString(expHar, "expHar") << std::endl;
		oss << dat::infoString(gotHar, "gotHar") << std::endl;
	}

	return oss.str();
}

//! Check standard case (all positive numbers)
std::string
prob_mean_test2
	()
{
	std::ostringstream oss;

	std::vector<double> const pos{ 1., 2., 3., 4. };
	std::vector<double> inv{ 1./pos[0], 1./pos[1], 1./pos[2], 1./pos[3] };
	double const scale{ 1./double(pos.size()) };

	using std::log;
	double const expAri{ scale * (pos[0] + pos[1] + pos[2] + pos[3]) };
	double const sumLogs
		{ log(pos[0]) + log(pos[1]) + log(pos[2]) + log(pos[3]) };
	double const expGeo{ std::exp(scale * sumLogs) };
	// identify between HM and AM
	double const ariOfInv{ scale * (inv[0] + inv[1] + inv[2] + inv[3]) };
	double const expHar{ 1. / ariOfInv };
	double const gotAri{ prob::mean::arithmetic(pos.begin(), pos.end()) };
	double const gotGeo{ prob::mean::geometric(pos.begin(), pos.end()) };
	double const gotHar{ prob::mean::harmonic(pos.begin(), pos.end()) };
	if (! dat::nearlyEquals(gotAri, expAri))
	{
		oss << "Failure of arithmetic mean pos data test" << std::endl;
		oss << dat::infoString(expAri, "expAri") << std::endl;
		oss << dat::infoString(gotAri, "gotAri") << std::endl;
	}
	if (! dat::nearlyEquals(gotGeo, expGeo))
	{
		oss << "Failure of geometric mean pos data test" << std::endl;
		oss << dat::infoString(expGeo, "expGeo") << std::endl;
		oss << dat::infoString(gotGeo, "gotGeo") << std::endl;
	}
	if (! dat::nearlyEquals(gotHar, expHar))
	{
		oss << "Failure of harmonic mean pos data test" << std::endl;
		oss << dat::infoString(expHar, "expHar") << std::endl;
		oss << dat::infoString(gotHar, "gotHar") << std::endl;
	}

	return oss.str();
}

//! Check empty data cases
std::string
prob_mean_test3
	()
{
	std::ostringstream oss;

	std::vector<double> const data{};
	double const expAri{ dat::nullValue<double>() };
	double const expGeo{ dat::nullValue<double>() };
	double const expHar{ dat::nullValue<double>() };
	double const gotAri{ prob::mean::arithmetic(data.begin(), data.end()) };
	double const gotGeo{ prob::mean::geometric(data.begin(), data.end()) };
	double const gotHar{ prob::mean::harmonic(data.begin(), data.end()) };
	if (dat::isValid(gotAri))
	{
		oss << "Failure of arithmetic mean empty data test" << std::endl;
		oss << dat::infoString(expAri, "expAri") << std::endl;
		oss << dat::infoString(gotAri, "gotAri") << std::endl;
	}
	if (dat::isValid(gotGeo))
	{
		oss << "Failure of geometric mean empty data test" << std::endl;
		oss << dat::infoString(expGeo, "expGeo") << std::endl;
		oss << dat::infoString(gotGeo, "gotGeo") << std::endl;
	}
	if (dat::isValid(gotHar))
	{
		oss << "Failure of harmonic mean empty data test" << std::endl;
		oss << dat::infoString(expHar, "expHar") << std::endl;
		oss << dat::infoString(gotHar, "gotHar") << std::endl;
	}

	return oss.str();
}

//! Check zero data cases
std::string
prob_mean_test4
	()
{
	std::ostringstream oss;

	std::vector<double> const zeros{ 0. };
	double const expAri{ 0. };
	double const expGeo{ 0. };
	double const expHar{ 0. };
	double const gotAri{ prob::mean::arithmetic(zeros.begin(), zeros.end()) };
	double const gotGeo{ prob::mean::geometric(zeros.begin(), zeros.end()) };
	double const gotHar{ prob::mean::harmonic(zeros.begin(), zeros.end()) };
	if (! dat::nearlyEquals(gotAri, expAri))
	{
		oss << "Failure of arithmetic mean zero data test" << std::endl;
		oss << dat::infoString(expAri, "expAri") << std::endl;
		oss << dat::infoString(gotAri, "gotAri") << std::endl;
	}
	if (! dat::nearlyEquals(gotGeo, expGeo))
	{
		oss << "Failure of geometric mean zero data test" << std::endl;
		oss << dat::infoString(expGeo, "expGeo") << std::endl;
		oss << dat::infoString(gotGeo, "gotGeo") << std::endl;
	}
	if (! dat::nearlyEquals(gotHar, expHar))
	{
		oss << "Failure of harmonic mean zero data test" << std::endl;
		oss << dat::infoString(expHar, "expHar") << std::endl;
		oss << dat::infoString(gotHar, "gotHar") << std::endl;
	}

	return oss.str();
}

}

//! Unit test for prob::mean
int
main
	( int const /*argc*/
	, char const * const * /*argv*/
	)
{
	std::ostringstream oss;

	// run tests
	oss << prob_mean_test0();
	oss << prob_mean_test1();
	oss << prob_mean_test2();
	oss << prob_mean_test3();
	oss << prob_mean_test4();

	// check/report results
	std::string const errMessages(oss.str());
	if (! errMessages.empty())
	{
		io::err() << errMessages << std::endl;
		return 1;
	}
	return 0;
}
<commit_msg>testprob/umean factored test code into check() function<commit_after>//
//
// MIT License
//
// Copyright (c) 2017 Stellacore Corporation.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//

/*! \file
\brief  This file contains unit test for prob::mean
*/

#include "libprob/mean.h"

#include "libdat/compare.h"
#include "libdat/info.h"
#include "libdat/validity.h"
#include "libio/stream.h"

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

namespace
{

//! Check for common functions
std::string
prob_mean_test0
	()
{
	std::ostringstream oss;
	/*
	prob::mean const aNull(dat::nullValue<prob::mean>());
	if (dat::isValid(aNull))
	{
		oss << "Failure of null value test" << std::endl;
		oss << "infoString: " << dat::infoString(aNull) << std::endl;
	}
	*/
	return oss.str();
}

struct Means
{
	double const theAri{};
	double const theGeo{};
	double const theHar{};

	explicit
	Means
		( double const & ari
		, double const & geo
		, double const & har
		)
		: theAri{ ari }
		, theGeo{ geo }
		, theHar{ har }
	{ }

	template <typename FwdIter>
	explicit
	Means
		( FwdIter const & beg
		, FwdIter const & end
		)
		: theAri{ prob::mean::arithmetic(beg, end) }
		, theGeo{ prob::mean::geometric(beg, end) }
		, theHar{ prob::mean::harmonic(beg, end) }
	{ }
};

//! Check test results
void
check
	( std::ostringstream & oss
	, Means const & got
	, Means const & exp
	, std::string const & tname
	)
{
	double const & gotAri = got.theAri;
	double const & gotGeo = got.theGeo;
	double const & gotHar = got.theHar;
	double const & expAri = exp.theAri;
	double const & expGeo = exp.theGeo;
	double const & expHar = exp.theHar;

	// only arithmetic mean is defined if non positive values
	if (! dat::areSame(gotAri, expAri))
	{
		oss << "Failure of arithmetic mean"
			<< " for " << tname << " data test" << std::endl;
		oss << dat::infoString(expAri, "expAri") << std::endl;
		oss << dat::infoString(gotAri, "gotAri") << std::endl;
	}
	if (! dat::areSame(gotGeo, expGeo))
	{
		oss << "Failure of geometric mean"
			<< " for " << tname << " data test" << std::endl;
		oss << dat::infoString(expGeo, "expGeo") << std::endl;
		oss << dat::infoString(gotGeo, "gotGeo") << std::endl;
	}
	if (! dat::areSame(gotHar, expHar))
	{
		oss << "Failure of harmonic mean"
			<< " for " << tname << " data test" << std::endl;
		oss << dat::infoString(expHar, "expHar") << std::endl;
		oss << dat::infoString(gotHar, "gotHar") << std::endl;
	}
}

//! Check error cases (involving negative numbers)
std::string
prob_mean_test1
	()
{
	std::ostringstream oss;

	// only arithmetic mean is defined if non positive values
	std::vector<double> const mix{ 2., 1., -2., 3. };
	double const expAri{ 1. };
	double const expGeo{ dat::nullValue<double>() };
	double const expHar{ dat::nullValue<double>() };

	Means const exp(expAri, expGeo, expHar);
	Means const got(mix.begin(), mix.end());
	check(oss, got, exp, "mixed");

	return oss.str();
}

//! Check standard case (all positive numbers)
std::string
prob_mean_test2
	()
{
	std::ostringstream oss;

	std::vector<double> const pos{ 1., 2., 3., 4. };
	std::vector<double> inv{ 1./pos[0], 1./pos[1], 1./pos[2], 1./pos[3] };
	double const scale{ 1./double(pos.size()) };

	using std::log;
	double const expAri{ scale * (pos[0] + pos[1] + pos[2] + pos[3]) };
	double const sumLogs
		{ log(pos[0]) + log(pos[1]) + log(pos[2]) + log(pos[3]) };
	double const expGeo{ std::exp(scale * sumLogs) };
	// identify between HM and AM
	double const ariOfInv{ scale * (inv[0] + inv[1] + inv[2] + inv[3]) };
	double const expHar{ 1. / ariOfInv };

	Means const exp(expAri, expGeo, expHar);
	Means const got(pos.begin(), pos.end());
	check(oss, got, exp, "positive");

	return oss.str();
}

//! Check empty data cases
std::string
prob_mean_test3
	()
{
	std::ostringstream oss;

	std::vector<double> const emp{};
	double const expAri{ dat::nullValue<double>() };
	double const expGeo{ dat::nullValue<double>() };
	double const expHar{ dat::nullValue<double>() };

	Means const exp(expAri, expGeo, expHar);
	Means const got(emp.begin(), emp.end());
	check(oss, got, exp, "empty");

	return oss.str();
}

//! Check zero data cases
std::string
prob_mean_test4
	()
{
	std::ostringstream oss;

	std::vector<double> const zeros{ 0. };
	double const expAri{ 0. };
	double const expGeo{ 0. };
	double const expHar{ 0. };

	Means const exp(expAri, expGeo, expHar);
	Means const got(zeros.begin(), zeros.end());
	check(oss, got, exp, "zeros");

	return oss.str();
}

}

//! Unit test for prob::mean
int
main
	( int const /*argc*/
	, char const * const * /*argv*/
	)
{
	std::ostringstream oss;

	// run tests
	oss << prob_mean_test0();
	oss << prob_mean_test1();
	oss << prob_mean_test2();
	oss << prob_mean_test3();
	oss << prob_mean_test4();

	// check/report results
	std::string const errMessages(oss.str());
	if (! errMessages.empty())
	{
		io::err() << errMessages << std::endl;
		return 1;
	}
	return 0;
}
<|endoftext|>


<commit_before>//===- Linux/Process.cpp - Linux Process Implementation ------- -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Reid Spencer and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides the Linux specific implementation of the Process class.
//
//===----------------------------------------------------------------------===//

// Include the generic Unix implementation
#include "../Unix/SUS/Process.cpp"

//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only Linux specific code
//===          and must not be generic UNIX code (see ../Unix/Process.cpp)
//===----------------------------------------------------------------------===//

// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab
<commit_msg>For PR351: No need for Unix/SUS/Process.cpp any more, just ifdef it.<commit_after>//===- Linux/Process.cpp - Linux Process Implementation ------- -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Reid Spencer and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides the Linux specific implementation of the Process class.
//
//===----------------------------------------------------------------------===//

// Include the generic Unix implementation
#include "../Unix/Process.cpp"

//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only Linux specific code
//===          and must not be generic UNIX code (see ../Unix/Process.cpp)
//===----------------------------------------------------------------------===//

// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab
<|endoftext|>


<commit_before>//===- JSONBackend.cpp - Generate a JSON dump of all records. -*- C++ -*-=====//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This TableGen back end generates a machine-readable representation
// of all the classes and records defined by the input, in JSON format.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/BitVector.h"
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include "llvm/Support/JSON.h"

#define DEBUG_TYPE "json-emitter"

using namespace llvm;

namespace {

class JSONEmitter {
private:
  RecordKeeper &Records;

  json::Value translateInit(const Init &I);
  json::Array listSuperclasses(const Record &R);

public:
  JSONEmitter(RecordKeeper &R);

  void run(raw_ostream &OS);
};

} // end anonymous namespace

JSONEmitter::JSONEmitter(RecordKeeper &R) : Records(R) {}

json::Value JSONEmitter::translateInit(const Init &I) {

  // Init subclasses that we return as JSON primitive values of one
  // kind or another.

  if (isa<UnsetInit>(&I)) {
    return nullptr;
  } else if (auto *Bit = dyn_cast<BitInit>(&I)) {
    return Bit->getValue() ? 1 : 0;
  } else if (auto *Bits = dyn_cast<BitsInit>(&I)) {
    json::Array array;
    for (unsigned i = 0, limit = Bits->getNumBits(); i < limit; i++)
      array.push_back(translateInit(*Bits->getBit(i)));
    return array;
  } else if (auto *Int = dyn_cast<IntInit>(&I)) {
    return Int->getValue();
  } else if (auto *Str = dyn_cast<StringInit>(&I)) {
    return Str->getValue();
  } else if (auto *Code = dyn_cast<CodeInit>(&I)) {
    return Code->getValue();
  } else if (auto *List = dyn_cast<ListInit>(&I)) {
    json::Array array;
    for (auto val : *List)
      array.push_back(translateInit(*val));
    return array;
  }

  // Init subclasses that we return as JSON objects containing a
  // 'kind' discriminator. For these, we also provide the same
  // translation back into TableGen input syntax that -print-records
  // would give.

  json::Object obj;
  obj["printable"] = I.getAsString();

  if (auto *Def = dyn_cast<DefInit>(&I)) {
    obj["kind"] = "def";
    obj["def"] = Def->getDef()->getName();
    return obj;
  } else if (auto *Var = dyn_cast<VarInit>(&I)) {
    obj["kind"] = "var";
    obj["var"] = Var->getName();
    return obj;
  } else if (auto *VarBit = dyn_cast<VarBitInit>(&I)) {
    if (auto *Var = dyn_cast<VarInit>(VarBit->getBitVar())) {
      obj["kind"] = "varbit";
      obj["var"] = Var->getName();
      obj["index"] = VarBit->getBitNum();
      return obj;
    }
  } else if (auto *Dag = dyn_cast<DagInit>(&I)) {
    obj["kind"] = "dag";
    obj["operator"] = translateInit(*Dag->getOperator());
    if (auto name = Dag->getName())
      obj["name"] = name->getAsUnquotedString();
    json::Array args;
    for (unsigned i = 0, limit = Dag->getNumArgs(); i < limit; ++i) {
      json::Array arg;
      arg.push_back(translateInit(*Dag->getArg(i)));
      if (auto argname = Dag->getArgName(i))
        arg.push_back(argname->getAsUnquotedString());
      else
        arg.push_back(nullptr);
      args.push_back(std::move(arg));
    }
    obj["args"] = std::move(args);
    return obj;
  }

  // Final fallback: anything that gets past here is simply given a
  // kind field of 'complex', and the only other field is the standard
  // 'printable' representation.

  assert(!I.isConcrete());
  obj["kind"] = "complex";
  return obj;
}

void JSONEmitter::run(raw_ostream &OS) {
  json::Object root;

  root["!tablegen_json_version"] = 1;

  // Prepare the arrays that will list the instances of every class.
  // We mostly fill those in by iterating over the superclasses of
  // each def, but we also want to ensure we store an empty list for a
  // class with no instances at all, so we do a preliminary iteration
  // over the classes, invoking std::map::operator[] to default-
  // construct the array for each one.
  std::map<std::string, json::Array> instance_lists;
  for (const auto &C : Records.getClasses()) {
    auto &Name = C.second->getNameInitAsString();
    (void)instance_lists[Name];
  }

  // Main iteration over the defs.
  for (const auto &D : Records.getDefs()) {
    auto &Name = D.second->getNameInitAsString();
    auto &Def = *D.second;

    json::Object obj;
    json::Array fields;

    for (const RecordVal &RV : Def.getValues()) {
      if (!Def.isTemplateArg(RV.getNameInit())) {
        auto Name = RV.getNameInitAsString();
        if (RV.getPrefix())
          fields.push_back(Name);
        obj[Name] = translateInit(*RV.getValue());
      }
    }

    obj["!fields"] = std::move(fields);

    json::Array superclasses;
    for (const auto &SuperPair : Def.getSuperClasses())
      superclasses.push_back(SuperPair.first->getNameInitAsString());
    obj["!superclasses"] = std::move(superclasses);

    obj["!name"] = Name;
    obj["!anonymous"] = Def.isAnonymous();

    root[Name] = std::move(obj);

    // Add this def to the instance list for each of its superclasses.
    for (const auto &SuperPair : Def.getSuperClasses()) {
      auto SuperName = SuperPair.first->getNameInitAsString();
      instance_lists[SuperName].push_back(Name);
    }
  }

  // Make a JSON object from the std::map of instance lists.
  json::Object instanceof;
  for (auto kv: instance_lists)
    instanceof[kv.first] = std::move(kv.second);
  root["!instanceof"] = std::move(instanceof);

  // Done. Write the output.
  OS << json::Value(std::move(root)) << "\n";
}

namespace llvm {

void EmitJSON(RecordKeeper &RK, raw_ostream &OS) { JSONEmitter(RK).run(OS); }
} // end namespace llvm
<commit_msg>[TableGen] Add missing std::moves to fix build failure.<commit_after>//===- JSONBackend.cpp - Generate a JSON dump of all records. -*- C++ -*-=====//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This TableGen back end generates a machine-readable representation
// of all the classes and records defined by the input, in JSON format.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/BitVector.h"
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include "llvm/Support/JSON.h"

#define DEBUG_TYPE "json-emitter"

using namespace llvm;

namespace {

class JSONEmitter {
private:
  RecordKeeper &Records;

  json::Value translateInit(const Init &I);
  json::Array listSuperclasses(const Record &R);

public:
  JSONEmitter(RecordKeeper &R);

  void run(raw_ostream &OS);
};

} // end anonymous namespace

JSONEmitter::JSONEmitter(RecordKeeper &R) : Records(R) {}

json::Value JSONEmitter::translateInit(const Init &I) {

  // Init subclasses that we return as JSON primitive values of one
  // kind or another.

  if (isa<UnsetInit>(&I)) {
    return nullptr;
  } else if (auto *Bit = dyn_cast<BitInit>(&I)) {
    return Bit->getValue() ? 1 : 0;
  } else if (auto *Bits = dyn_cast<BitsInit>(&I)) {
    json::Array array;
    for (unsigned i = 0, limit = Bits->getNumBits(); i < limit; i++)
      array.push_back(translateInit(*Bits->getBit(i)));
    return std::move(array);
  } else if (auto *Int = dyn_cast<IntInit>(&I)) {
    return Int->getValue();
  } else if (auto *Str = dyn_cast<StringInit>(&I)) {
    return Str->getValue();
  } else if (auto *Code = dyn_cast<CodeInit>(&I)) {
    return Code->getValue();
  } else if (auto *List = dyn_cast<ListInit>(&I)) {
    json::Array array;
    for (auto val : *List)
      array.push_back(translateInit(*val));
    return std::move(array);
  }

  // Init subclasses that we return as JSON objects containing a
  // 'kind' discriminator. For these, we also provide the same
  // translation back into TableGen input syntax that -print-records
  // would give.

  json::Object obj;
  obj["printable"] = I.getAsString();

  if (auto *Def = dyn_cast<DefInit>(&I)) {
    obj["kind"] = "def";
    obj["def"] = Def->getDef()->getName();
    return std::move(obj);
  } else if (auto *Var = dyn_cast<VarInit>(&I)) {
    obj["kind"] = "var";
    obj["var"] = Var->getName();
    return std::move(obj);
  } else if (auto *VarBit = dyn_cast<VarBitInit>(&I)) {
    if (auto *Var = dyn_cast<VarInit>(VarBit->getBitVar())) {
      obj["kind"] = "varbit";
      obj["var"] = Var->getName();
      obj["index"] = VarBit->getBitNum();
      return std::move(obj);
    }
  } else if (auto *Dag = dyn_cast<DagInit>(&I)) {
    obj["kind"] = "dag";
    obj["operator"] = translateInit(*Dag->getOperator());
    if (auto name = Dag->getName())
      obj["name"] = name->getAsUnquotedString();
    json::Array args;
    for (unsigned i = 0, limit = Dag->getNumArgs(); i < limit; ++i) {
      json::Array arg;
      arg.push_back(translateInit(*Dag->getArg(i)));
      if (auto argname = Dag->getArgName(i))
        arg.push_back(argname->getAsUnquotedString());
      else
        arg.push_back(nullptr);
      args.push_back(std::move(arg));
    }
    obj["args"] = std::move(args);
    return std::move(obj);
  }

  // Final fallback: anything that gets past here is simply given a
  // kind field of 'complex', and the only other field is the standard
  // 'printable' representation.

  assert(!I.isConcrete());
  obj["kind"] = "complex";
  return std::move(obj);
}

void JSONEmitter::run(raw_ostream &OS) {
  json::Object root;

  root["!tablegen_json_version"] = 1;

  // Prepare the arrays that will list the instances of every class.
  // We mostly fill those in by iterating over the superclasses of
  // each def, but we also want to ensure we store an empty list for a
  // class with no instances at all, so we do a preliminary iteration
  // over the classes, invoking std::map::operator[] to default-
  // construct the array for each one.
  std::map<std::string, json::Array> instance_lists;
  for (const auto &C : Records.getClasses()) {
    auto &Name = C.second->getNameInitAsString();
    (void)instance_lists[Name];
  }

  // Main iteration over the defs.
  for (const auto &D : Records.getDefs()) {
    auto &Name = D.second->getNameInitAsString();
    auto &Def = *D.second;

    json::Object obj;
    json::Array fields;

    for (const RecordVal &RV : Def.getValues()) {
      if (!Def.isTemplateArg(RV.getNameInit())) {
        auto Name = RV.getNameInitAsString();
        if (RV.getPrefix())
          fields.push_back(Name);
        obj[Name] = translateInit(*RV.getValue());
      }
    }

    obj["!fields"] = std::move(fields);

    json::Array superclasses;
    for (const auto &SuperPair : Def.getSuperClasses())
      superclasses.push_back(SuperPair.first->getNameInitAsString());
    obj["!superclasses"] = std::move(superclasses);

    obj["!name"] = Name;
    obj["!anonymous"] = Def.isAnonymous();

    root[Name] = std::move(obj);

    // Add this def to the instance list for each of its superclasses.
    for (const auto &SuperPair : Def.getSuperClasses()) {
      auto SuperName = SuperPair.first->getNameInitAsString();
      instance_lists[SuperName].push_back(Name);
    }
  }

  // Make a JSON object from the std::map of instance lists.
  json::Object instanceof;
  for (auto kv: instance_lists)
    instanceof[kv.first] = std::move(kv.second);
  root["!instanceof"] = std::move(instanceof);

  // Done. Write the output.
  OS << json::Value(std::move(root)) << "\n";
}

namespace llvm {

void EmitJSON(RecordKeeper &RK, raw_ostream &OS) { JSONEmitter(RK).run(OS); }
} // end namespace llvm
<|endoftext|>