<commit_before>#include <algorithm>
#include <iostream>
#include <string>
#include <tabulate/column.hpp>
#include <tabulate/font_style.hpp>
#include <tabulate/printer.hpp>
#include <tabulate/row.hpp>
#include <tabulate/termcolor.hpp>
#include <vector>

namespace tabulate {

Format &Cell::format() {
  std::shared_ptr<Row> parent = parent_.lock();
  if (!format_.has_value()) {   // no cell format
    format_ = parent->format(); // Use parent row format
  } else {
    // Cell has formatting
    // Merge cell formatting with parent row formatting
    format_ = Format::merge(format_.value(), parent->format());
  }
  return format_.value();
}

class TableInternal : public std::enable_shared_from_this<TableInternal> {
public:
  static std::shared_ptr<TableInternal> create() {
    auto result = std::shared_ptr<TableInternal>(new TableInternal());
    result->format_.set_defaults();
    return result;
  }

  void add_row(const std::vector<std::string> &cells) {
    auto row = std::make_shared<Row>(shared_from_this());
    for (auto &c : cells) {
      auto cell = std::make_shared<Cell>(row);
      cell->set_text(c);
      row->add_cell(cell);
    }
    rows_.push_back(row);
  }

  Row &operator[](size_t index) { return *(rows_[index]); }

  const Row &operator[](size_t index) const { return *(rows_[index]); }

  Column column(size_t index) {
    Column column(shared_from_this());
    for (size_t i = 0; i < rows_.size(); ++i) {
      auto row = rows_[i];
      auto &cell = row->cell(index);
      column.add_cell(cell);
    }
    return column;
  }

  size_t size() const { return rows_.size(); }

  Format &format() { return format_; }

  void print(std::ostream &stream) { Printer::print_table(stream, *this); }

  size_t estimate_num_columns() const {
    size_t result{0};
    if (size()) {
      auto first_row = operator[](size_t(0));
      result = first_row.size();
    }
    return result;
  }

private:
  TableInternal() {}
  TableInternal &operator=(const TableInternal &);
  TableInternal(const TableInternal &);

  std::vector<std::shared_ptr<Row>> rows_;
  Format format_;
};

Format &Row::format() {
  std::shared_ptr<TableInternal> parent = parent_.lock();
  if (!format_.has_value()) {   // no row format
    format_ = parent->format(); // Use parent table format
  } else {
    // Row has formatting rules
    // Merge with parent table format
    format_ = Format::merge(format_.value(), parent->format());
  }
  return format_.value();
}

std::pair<std::vector<size_t>, std::vector<size_t>>
Printer::compute_cell_dimensions(TableInternal &table) {
  std::pair<std::vector<size_t>, std::vector<size_t>> result;
  size_t num_rows = table.size();
  size_t num_columns = table.estimate_num_columns();

  std::vector<size_t> row_heights, column_widths{};

  for (size_t i = 0; i < num_columns; ++i) {
    Column column = table.column(i);
    size_t configured_width = column.get_configured_width();
    size_t computed_width = column.get_computed_width();
    if (configured_width != 0)
      column_widths.push_back(configured_width);
    else
      column_widths.push_back(computed_width);
  }

  for (size_t i = 0; i < num_rows; ++i) {
    Row row = table[i];
    size_t configured_height = row.get_configured_height();
    size_t computed_height = row.get_computed_height(column_widths);

    // NOTE: Unlike column width, row height is calculated as the max
    // b/w configured height and computed height
    // which means that .width() has higher precedence than .height()
    // when both are configured by the user
    //
    // TODO: Maybe this can be configured?
    // If such a configuration is exposed, i.e., prefer height over width
    // then the logic will be reversed, i.e.,
    // column_widths.push_back(std::max(configured_width, computed_width))
    // and
    // row_height = configured_height if != 0 else computed_height

    row_heights.push_back(std::max(configured_height, computed_height));
  }

  result.first = row_heights;
  result.second = column_widths;

  return result;
}

void Printer::print_table(std::ostream &stream, TableInternal &table) {
  size_t num_rows = table.size();
  size_t num_columns = table.estimate_num_columns();
  auto dimensions = compute_cell_dimensions(table);
  auto row_heights = dimensions.first;
  auto column_widths = dimensions.second;

  // For each row,
  for (size_t i = 0; i < num_rows; ++i) {

    // Print top border
    bool border_top_printed{true};
    for (size_t j = 0; j < num_columns; ++j) {
      border_top_printed &= print_cell_border_top(stream, table, {i, j}, {row_heights[i], column_widths[j]}, num_columns);
    }
    if (border_top_printed)
      stream << "\n";

    // Print row contents with word wrapping
    for (size_t k = 0; k < row_heights[i]; ++k) {
      for (size_t j = 0; j < num_columns; ++j) {
        print_row_in_cell(stream, table, {i, j}, {row_heights[i], column_widths[j]}, num_columns,
                          k);
      }
      if (k + 1 < row_heights[i])
        stream << "\n";
    }

    if (i + 1 == num_rows) {

      // Check if there is bottom border to print:
      auto bottom_border_needed{true};
      for (size_t j = 0; j < num_columns; ++j) {
        auto cell = table[i][j];
        auto format = cell.format();
        auto column_width = column_widths[j];
        auto corner = format.corner_.value();
        auto border_bottom = format.border_bottom_.value();
        if (corner == "" && border_bottom == "") {
          bottom_border_needed = false;
          break;
        }
      }

      if (bottom_border_needed)
        stream << "\n";
      // Print bottom border for table
      for (size_t j = 0; j < num_columns; ++j) {
        print_cell_border_bottom(stream, table, {i, j}, {row_heights[i], column_widths[j]},
                                 num_columns);
      }
    }
    if (i + 1 < num_rows)
      stream << "\n"; // Don't add newline after last row
  }
}

void Printer::print_row_in_cell(std::ostream &stream, TableInternal &table,
                                const std::pair<size_t, size_t> &index,
                                const std::pair<size_t, size_t> &dimension, size_t num_columns,
                                size_t row_index) {
  auto row_height = dimension.first;
  auto column_width = dimension.second;
  auto cell = table[index.first][index.second];
  auto format = cell.format();
  auto text = cell.get_text();
  auto word_wrapped_text = Format::word_wrap(text, column_width);
  auto text_height = std::count(word_wrapped_text.begin(), word_wrapped_text.end(), '\n') + 1;
  auto padding_top = format.padding_top_.value();
  auto padding_bottom = format.padding_bottom_.value();

  apply_element_style(stream, format.border_left_color_.value(),
                      format.border_left_background_color_.value(), {});
  stream << format.border_left_.value();
  reset_element_style(stream);

  apply_element_style(stream, format.font_color_.value(), format.font_background_color_.value(),
                      {});

  if (row_index < padding_top) {
    // Padding top
    stream << std::string(column_width, ' ');
  } else if (row_index >= padding_top && (row_index <= (padding_top + text_height))) {
    // Row contents

    // Retrieve padding left and right
    // (column_width - padding_left - padding_right) is the amount of space
    // available for cell text - Use this to word wrap cell contents
    auto padding_left = format.padding_left_.value();
    auto padding_right = format.padding_right_.value();

    // Check if input text has embedded \n that are to be respected
    auto newlines_in_input = Format::split_lines(text, "\n").size() - 1;
    std::string word_wrapped_text;

    // If there are no embedded \n characters, then apply word wrap
    if (newlines_in_input == 0) {
      // Apply word wrapping to input text
      // Then display one word-wrapped line at a time within cell
      if (column_width > (padding_left + padding_right))
        word_wrapped_text = Format::word_wrap(text, column_width - padding_left - padding_right);
      else {
        // Configured column width cannot be lower than (padding_left + padding_right)
        // This is a bad configuration
        // E.g., the user is trying to force the column width to be 5
        // when padding_left and padding_right are each configured to 3
        // (padding_left + padding_right) = 6 > column_width
      }
    } else {
      word_wrapped_text = text; // repect the embedded '\n' characters
    }

    auto lines = Format::split_lines(word_wrapped_text, "\n");

    if (row_index - padding_top < lines.size()) {
      auto line = lines[row_index - padding_top];

      // Print left padding characters
      stream << std::string(padding_left, ' ');

      // Print word-wrapped line
      line = Format::trim(line);
      auto line_with_padding_size = line.size() + padding_left + padding_right;
      switch (format.font_align_.value()) {
      case FontAlign::left:
        print_content_left_aligned(stream, line, format, line_with_padding_size, column_width);
        break;
      case FontAlign::center:
        print_content_center_aligned(stream, line, format, line_with_padding_size, column_width);
        break;
      case FontAlign::right:
        print_content_right_aligned(stream, line, format, line_with_padding_size, column_width);
        break;
      }

      // Print right padding characters
      stream << std::string(format.padding_right_.value(), ' ');
    } else
      stream << std::string(column_width, ' ');

  } else {
    // Padding bottom
    stream << std::string(column_width, ' ');
  }

  reset_element_style(stream);

  if (index.second + 1 == num_columns) {
    // Print right border after last column
    apply_element_style(stream, format.border_right_color_.value(),
                        format.border_right_background_color_.value(), {});
    stream << format.border_right_.value();
    reset_element_style(stream);
  }
}

bool Printer::print_cell_border_top(std::ostream &stream, TableInternal &table,
                                    const std::pair<size_t, size_t> &index,
                                    const std::pair<size_t, size_t> &dimension,
                                    size_t num_columns) {
  auto cell = table[index.first][index.second];
  auto format = cell.format();
  auto column_width = dimension.second;

  auto corner = format.corner_.value();
  auto border_top = format.border_top_.value();

  if ((corner == "" && border_top == "") || !format.show_border_top_.value())
    return false;

  apply_element_style(stream, format.corner_color_.value(), format.corner_background_color_.value(),
                      {});
  stream << corner;
  reset_element_style(stream);

  for (size_t i = 0; i < column_width; ++i) {
    apply_element_style(stream, format.border_top_color_.value(),
                        format.border_bottom_background_color_.value(), {});
    stream << border_top;
    reset_element_style(stream);
  }

  if (index.second + 1 == num_columns) {
    // Print corner after last column
    apply_element_style(stream, format.corner_color_.value(),
                        format.corner_background_color_.value(), {});
    stream << corner;
    reset_element_style(stream);
  }
  return true;
}

bool Printer::print_cell_border_bottom(std::ostream &stream, TableInternal &table,
                                       const std::pair<size_t, size_t> &index,
                                       const std::pair<size_t, size_t> &dimension,
                                       size_t num_columns) {
  auto cell = table[index.first][index.second];
  auto format = cell.format();
  auto column_width = dimension.second;

  auto corner = format.corner_.value();
  auto border_bottom = format.border_bottom_.value();

  if ((corner == "" && border_bottom == "") || !format.show_border_bottom_.value())
    return false;

  apply_element_style(stream, format.corner_color_.value(), format.corner_background_color_.value(),
                      {});
  stream << corner;
  reset_element_style(stream);

  for (size_t i = 0; i < column_width; ++i) {
    apply_element_style(stream, format.border_bottom_color_.value(),
                        format.border_left_background_color_.value(), {});
    stream << border_bottom;
    reset_element_style(stream);
  }

  if (index.second + 1 == num_columns) {
    // Print corner after last column
    apply_element_style(stream, format.corner_color_.value(),
                        format.corner_background_color_.value(), {});
    stream << corner;
    reset_element_style(stream);
  }
  return true;
}

} // namespace tabulate<commit_msg>Handled show_border_left/right<commit_after>#include <algorithm>
#include <iostream>
#include <string>
#include <tabulate/column.hpp>
#include <tabulate/font_style.hpp>
#include <tabulate/printer.hpp>
#include <tabulate/row.hpp>
#include <tabulate/termcolor.hpp>
#include <vector>

namespace tabulate {

Format &Cell::format() {
  std::shared_ptr<Row> parent = parent_.lock();
  if (!format_.has_value()) {   // no cell format
    format_ = parent->format(); // Use parent row format
  } else {
    // Cell has formatting
    // Merge cell formatting with parent row formatting
    format_ = Format::merge(format_.value(), parent->format());
  }
  return format_.value();
}

class TableInternal : public std::enable_shared_from_this<TableInternal> {
public:
  static std::shared_ptr<TableInternal> create() {
    auto result = std::shared_ptr<TableInternal>(new TableInternal());
    result->format_.set_defaults();
    return result;
  }

  void add_row(const std::vector<std::string> &cells) {
    auto row = std::make_shared<Row>(shared_from_this());
    for (auto &c : cells) {
      auto cell = std::make_shared<Cell>(row);
      cell->set_text(c);
      row->add_cell(cell);
    }
    rows_.push_back(row);
  }

  Row &operator[](size_t index) { return *(rows_[index]); }

  const Row &operator[](size_t index) const { return *(rows_[index]); }

  Column column(size_t index) {
    Column column(shared_from_this());
    for (size_t i = 0; i < rows_.size(); ++i) {
      auto row = rows_[i];
      auto &cell = row->cell(index);
      column.add_cell(cell);
    }
    return column;
  }

  size_t size() const { return rows_.size(); }

  Format &format() { return format_; }

  void print(std::ostream &stream) { Printer::print_table(stream, *this); }

  size_t estimate_num_columns() const {
    size_t result{0};
    if (size()) {
      auto first_row = operator[](size_t(0));
      result = first_row.size();
    }
    return result;
  }

private:
  TableInternal() {}
  TableInternal &operator=(const TableInternal &);
  TableInternal(const TableInternal &);

  std::vector<std::shared_ptr<Row>> rows_;
  Format format_;
};

Format &Row::format() {
  std::shared_ptr<TableInternal> parent = parent_.lock();
  if (!format_.has_value()) {   // no row format
    format_ = parent->format(); // Use parent table format
  } else {
    // Row has formatting rules
    // Merge with parent table format
    format_ = Format::merge(format_.value(), parent->format());
  }
  return format_.value();
}

std::pair<std::vector<size_t>, std::vector<size_t>>
Printer::compute_cell_dimensions(TableInternal &table) {
  std::pair<std::vector<size_t>, std::vector<size_t>> result;
  size_t num_rows = table.size();
  size_t num_columns = table.estimate_num_columns();

  std::vector<size_t> row_heights, column_widths{};

  for (size_t i = 0; i < num_columns; ++i) {
    Column column = table.column(i);
    size_t configured_width = column.get_configured_width();
    size_t computed_width = column.get_computed_width();
    if (configured_width != 0)
      column_widths.push_back(configured_width);
    else
      column_widths.push_back(computed_width);
  }

  for (size_t i = 0; i < num_rows; ++i) {
    Row row = table[i];
    size_t configured_height = row.get_configured_height();
    size_t computed_height = row.get_computed_height(column_widths);

    // NOTE: Unlike column width, row height is calculated as the max
    // b/w configured height and computed height
    // which means that .width() has higher precedence than .height()
    // when both are configured by the user
    //
    // TODO: Maybe this can be configured?
    // If such a configuration is exposed, i.e., prefer height over width
    // then the logic will be reversed, i.e.,
    // column_widths.push_back(std::max(configured_width, computed_width))
    // and
    // row_height = configured_height if != 0 else computed_height

    row_heights.push_back(std::max(configured_height, computed_height));
  }

  result.first = row_heights;
  result.second = column_widths;

  return result;
}

void Printer::print_table(std::ostream &stream, TableInternal &table) {
  size_t num_rows = table.size();
  size_t num_columns = table.estimate_num_columns();
  auto dimensions = compute_cell_dimensions(table);
  auto row_heights = dimensions.first;
  auto column_widths = dimensions.second;

  // For each row,
  for (size_t i = 0; i < num_rows; ++i) {

    // Print top border
    bool border_top_printed{true};
    for (size_t j = 0; j < num_columns; ++j) {
      border_top_printed &= print_cell_border_top(stream, table, {i, j}, {row_heights[i], column_widths[j]}, num_columns);
    }
    if (border_top_printed)
      stream << "\n";

    // Print row contents with word wrapping
    for (size_t k = 0; k < row_heights[i]; ++k) {
      for (size_t j = 0; j < num_columns; ++j) {
        print_row_in_cell(stream, table, {i, j}, {row_heights[i], column_widths[j]}, num_columns,
                          k);
      }
      if (k + 1 < row_heights[i])
        stream << "\n";
    }

    if (i + 1 == num_rows) {

      // Check if there is bottom border to print:
      auto bottom_border_needed{true};
      for (size_t j = 0; j < num_columns; ++j) {
        auto cell = table[i][j];
        auto format = cell.format();
        auto column_width = column_widths[j];
        auto corner = format.corner_.value();
        auto border_bottom = format.border_bottom_.value();
        if (corner == "" && border_bottom == "") {
          bottom_border_needed = false;
          break;
        }
      }

      if (bottom_border_needed)
        stream << "\n";
      // Print bottom border for table
      for (size_t j = 0; j < num_columns; ++j) {
        print_cell_border_bottom(stream, table, {i, j}, {row_heights[i], column_widths[j]},
                                 num_columns);
      }
    }
    if (i + 1 < num_rows)
      stream << "\n"; // Don't add newline after last row
  }
}

void Printer::print_row_in_cell(std::ostream &stream, TableInternal &table,
                                const std::pair<size_t, size_t> &index,
                                const std::pair<size_t, size_t> &dimension, size_t num_columns,
                                size_t row_index) {
  auto row_height = dimension.first;
  auto column_width = dimension.second;
  auto cell = table[index.first][index.second];
  auto format = cell.format();
  auto text = cell.get_text();
  auto word_wrapped_text = Format::word_wrap(text, column_width);
  auto text_height = std::count(word_wrapped_text.begin(), word_wrapped_text.end(), '\n') + 1;
  auto padding_top = format.padding_top_.value();
  auto padding_bottom = format.padding_bottom_.value();

  if (format.show_border_left_.value()) {
    apply_element_style(stream, format.border_left_color_.value(),
                        format.border_left_background_color_.value(), {});
    stream << format.border_left_.value();
    reset_element_style(stream);
  }

  apply_element_style(stream, format.font_color_.value(), format.font_background_color_.value(),
                      {});

  if (row_index < padding_top) {
    // Padding top
    stream << std::string(column_width, ' ');
  } else if (row_index >= padding_top && (row_index <= (padding_top + text_height))) {
    // Row contents

    // Retrieve padding left and right
    // (column_width - padding_left - padding_right) is the amount of space
    // available for cell text - Use this to word wrap cell contents
    auto padding_left = format.padding_left_.value();
    auto padding_right = format.padding_right_.value();

    // Check if input text has embedded \n that are to be respected
    auto newlines_in_input = Format::split_lines(text, "\n").size() - 1;
    std::string word_wrapped_text;

    // If there are no embedded \n characters, then apply word wrap
    if (newlines_in_input == 0) {
      // Apply word wrapping to input text
      // Then display one word-wrapped line at a time within cell
      if (column_width > (padding_left + padding_right))
        word_wrapped_text = Format::word_wrap(text, column_width - padding_left - padding_right);
      else {
        // Configured column width cannot be lower than (padding_left + padding_right)
        // This is a bad configuration
        // E.g., the user is trying to force the column width to be 5
        // when padding_left and padding_right are each configured to 3
        // (padding_left + padding_right) = 6 > column_width
      }
    } else {
      word_wrapped_text = text; // repect the embedded '\n' characters
    }

    auto lines = Format::split_lines(word_wrapped_text, "\n");

    if (row_index - padding_top < lines.size()) {
      auto line = lines[row_index - padding_top];

      // Print left padding characters
      stream << std::string(padding_left, ' ');

      // Print word-wrapped line
      line = Format::trim(line);
      auto line_with_padding_size = line.size() + padding_left + padding_right;
      switch (format.font_align_.value()) {
      case FontAlign::left:
        print_content_left_aligned(stream, line, format, line_with_padding_size, column_width);
        break;
      case FontAlign::center:
        print_content_center_aligned(stream, line, format, line_with_padding_size, column_width);
        break;
      case FontAlign::right:
        print_content_right_aligned(stream, line, format, line_with_padding_size, column_width);
        break;
      }

      // Print right padding characters
      stream << std::string(format.padding_right_.value(), ' ');
    } else
      stream << std::string(column_width, ' ');

  } else {
    // Padding bottom
    stream << std::string(column_width, ' ');
  }

  reset_element_style(stream);

  if (index.second + 1 == num_columns) {
    // Print right border after last column
    if (format.show_border_right_.value()) {
      apply_element_style(stream, format.border_right_color_.value(),
                          format.border_right_background_color_.value(), {});
      stream << format.border_right_.value();
      reset_element_style(stream);
    }
  }
}

bool Printer::print_cell_border_top(std::ostream &stream, TableInternal &table,
                                    const std::pair<size_t, size_t> &index,
                                    const std::pair<size_t, size_t> &dimension,
                                    size_t num_columns) {
  auto cell = table[index.first][index.second];
  auto format = cell.format();
  auto column_width = dimension.second;

  auto corner = format.corner_.value();
  auto border_top = format.border_top_.value();

  if ((corner == "" && border_top == "") || !format.show_border_top_.value())
    return false;

  apply_element_style(stream, format.corner_color_.value(), format.corner_background_color_.value(),
                      {});
  stream << corner;
  reset_element_style(stream);

  for (size_t i = 0; i < column_width; ++i) {
    apply_element_style(stream, format.border_top_color_.value(),
                        format.border_bottom_background_color_.value(), {});
    stream << border_top;
    reset_element_style(stream);
  }

  if (index.second + 1 == num_columns) {
    // Print corner after last column
    apply_element_style(stream, format.corner_color_.value(),
                        format.corner_background_color_.value(), {});
    stream << corner;
    reset_element_style(stream);
  }
  return true;
}

bool Printer::print_cell_border_bottom(std::ostream &stream, TableInternal &table,
                                       const std::pair<size_t, size_t> &index,
                                       const std::pair<size_t, size_t> &dimension,
                                       size_t num_columns) {
  auto cell = table[index.first][index.second];
  auto format = cell.format();
  auto column_width = dimension.second;

  auto corner = format.corner_.value();
  auto border_bottom = format.border_bottom_.value();

  if ((corner == "" && border_bottom == "") || !format.show_border_bottom_.value())
    return false;

  apply_element_style(stream, format.corner_color_.value(), format.corner_background_color_.value(),
                      {});
  stream << corner;
  reset_element_style(stream);

  for (size_t i = 0; i < column_width; ++i) {
    apply_element_style(stream, format.border_bottom_color_.value(),
                        format.border_bottom_background_color_.value(), {});
    stream << border_bottom;
    reset_element_style(stream);
  }

  if (index.second + 1 == num_columns) {
    // Print corner after last column
    apply_element_style(stream, format.corner_color_.value(),
                        format.corner_background_color_.value(), {});
    stream << corner;
    reset_element_style(stream);
  }
  return true;
}

} // namespace tabulate<|endoftext|>


<commit_before>#include "selfdrive/common/params.h"

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif  // _GNU_SOURCE

#include <dirent.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <unistd.h>

#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <mutex>
#include <unordered_map>

#include "selfdrive/common/swaglog.h"
#include "selfdrive/common/util.h"
#include "selfdrive/hardware/hw.h"

// keep trying if x gets interrupted by a signal
#define HANDLE_EINTR(x)                                       \
  ({                                                          \
    decltype(x) ret;                                          \
    int try_cnt = 0;                                          \
    do {                                                      \
      ret = (x);                                              \
    } while (ret == -1 && errno == EINTR && try_cnt++ < 100); \
    ret;                                                      \
  })

namespace {

const std::string default_params_path = Hardware::PC() ? util::getenv_default("HOME", "/.comma/params", "/data/params")
                                                       : "/data/params";
const std::string persistent_params_path = Hardware::PC() ? default_params_path : "/persist/comma/params";

volatile sig_atomic_t params_do_exit = 0;
void params_sig_handler(int signal) {
  params_do_exit = 1;
}

int fsync_dir(const char* path) {
  int fd = HANDLE_EINTR(open(path, O_RDONLY, 0755));
  if (fd < 0) {
    return -1;
  }

  int result = fsync(fd);
  int result_close = close(fd);
  if (result_close < 0) {
    result = result_close;
  }
  return result;
}

// TODO: replace by std::filesystem::create_directories
int mkdir_p(std::string path) {
  char * _path = (char *)path.c_str();

  mode_t prev_mask = umask(0);
  for (char *p = _path + 1; *p; p++) {
    if (*p == '/') {
      *p = '\0'; // Temporarily truncate
      if (mkdir(_path, 0777) != 0) {
        if (errno != EEXIST) return -1;
      }
      *p = '/';
    }
  }
  if (mkdir(_path, 0777) != 0) {
    if (errno != EEXIST) return -1;
  }
  chmod(_path, 0777);
  umask(prev_mask);
  return 0;
}

static bool create_params_path(const std::string &param_path, const std::string &key_path) {
  // Make sure params path exists
  if (!util::file_exists(param_path) && mkdir_p(param_path) != 0) {
    return false;
  }

  // See if the symlink exists, otherwise create it
  if (!util::file_exists(key_path)) {
    // 1) Create temp folder
    // 2) Set permissions
    // 3) Symlink it to temp link
    // 4) Move symlink to <params>/d

    std::string tmp_path = param_path + "/.tmp_XXXXXX";
    // this should be OK since mkdtemp just replaces characters in place
    char *tmp_dir = mkdtemp((char *)tmp_path.c_str());
    if (tmp_dir == NULL) {
      return false;
    }

    if (chmod(tmp_dir, 0777) != 0) {
      return false;
    }

    std::string link_path = std::string(tmp_dir) + ".link";
    if (symlink(tmp_dir, link_path.c_str()) != 0) {
      return false;
    }

    // don't return false if it has been created by other
    if (rename(link_path.c_str(), key_path.c_str()) != 0 && errno != EEXIST) {
      return false;
    }
  }

  // Ensure permissions are correct in case we didn't create the symlink
  return chmod(key_path.c_str(), 0777) == 0;
}

static void ensure_params_path(const std::string &params_path) {
  if (!create_params_path(params_path, params_path + "/d")) {
    throw std::runtime_error(util::string_format("Failed to ensure params path, errno=%d", errno));
  }
}

class FileLock {
 public:
  FileLock(const std::string& file_name, int op) : fn_(file_name), op_(op) {}

  void lock() {
    fd_ = HANDLE_EINTR(open(fn_.c_str(), O_CREAT, 0775));
    if (fd_ < 0) {
      LOGE("Failed to open lock file %s, errno=%d", fn_.c_str(), errno);
      return;
    }
    if (HANDLE_EINTR(flock(fd_, op_)) < 0) {
      close(fd_);
      LOGE("Failed to lock file %s, errno=%d", fn_.c_str(), errno);
    }
  }

  void unlock() { close(fd_); }

private:
  int fd_ = -1, op_;
  std::string fn_;
};

std::unordered_map<std::string, uint32_t> keys = {
    {"AccessToken", CLEAR_ON_MANAGER_START},
    {"ApiCache_DriveStats", PERSISTENT},
    {"ApiCache_Device", PERSISTENT},
    {"ApiCache_Owner", PERSISTENT},
    {"ApiCache_NavDestinations", PERSISTENT},
    {"AthenadPid", PERSISTENT},
    {"CalibrationParams", PERSISTENT},
    {"CarBatteryCapacity", PERSISTENT},
    {"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT | CLEAR_ON_IGNITION_ON},
    {"CarParamsCache", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT},
    {"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT | CLEAR_ON_IGNITION_ON},
    {"CommunityFeaturesToggle", PERSISTENT},
    {"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT | CLEAR_ON_IGNITION_ON},
    {"DisableRadar", PERSISTENT}, // WARNING: THIS DISABLES AEB
    {"EnableLteOnroad", PERSISTENT},
    {"EndToEndToggle", PERSISTENT},
    {"CompletedTrainingVersion", PERSISTENT},
    {"DisablePowerDown", PERSISTENT},
    {"DisableUpdates", PERSISTENT},
    {"EnableWideCamera", PERSISTENT},
    {"DoUninstall", CLEAR_ON_MANAGER_START},
    {"DongleId", PERSISTENT},
    {"GitDiff", PERSISTENT},
    {"GitBranch", PERSISTENT},
    {"GitCommit", PERSISTENT},
    {"GitRemote", PERSISTENT},
    {"GithubSshKeys", PERSISTENT},
    {"GithubUsername", PERSISTENT},
    {"HardwareSerial", PERSISTENT},
    {"HasAcceptedTerms", PERSISTENT},
    {"IsDriverViewEnabled", CLEAR_ON_MANAGER_START},
    {"IMEI", PERSISTENT},
    {"IsLdwEnabled", PERSISTENT},
    {"IsMetric", PERSISTENT},
    {"IsOffroad", CLEAR_ON_MANAGER_START},
    {"IsOnroad", PERSISTENT},
    {"IsRHD", PERSISTENT},
    {"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
    {"IsUpdateAvailable", CLEAR_ON_MANAGER_START},
    {"UploadRaw", PERSISTENT},
    {"LastAthenaPingTime", PERSISTENT},
    {"LastGPSPosition", PERSISTENT},
    {"LastUpdateException", PERSISTENT},
    {"LastUpdateTime", PERSISTENT},
    {"LiveParameters", PERSISTENT},
    {"MapboxToken", PERSISTENT},
    {"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
    {"NavSettingTime24h", PERSISTENT},
    {"OpenpilotEnabledToggle", PERSISTENT},
    {"PandaFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT},
    {"PandaFirmwareHex", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT},
    {"PandaDongleId", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT},
    {"Passive", PERSISTENT},
    {"RecordFront", PERSISTENT},
    {"RecordFrontLock", PERSISTENT},  // for the internal fleet
    {"ReleaseNotes", PERSISTENT},
    {"ShouldDoUpdate", CLEAR_ON_MANAGER_START},
    {"SubscriberInfo", PERSISTENT},
    {"SshEnabled", PERSISTENT},
    {"TermsVersion", PERSISTENT},
    {"Timezone", PERSISTENT},
    {"TrainingVersion", PERSISTENT},
    {"UpdateAvailable", CLEAR_ON_MANAGER_START},
    {"UpdateFailedCount", CLEAR_ON_MANAGER_START},
    {"Version", PERSISTENT},
    {"VisionRadarToggle", PERSISTENT},
    {"Offroad_ChargeDisabled", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT},
    {"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START},
    {"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START},
    {"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START},
    {"Offroad_PandaFirmwareMismatch", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT},
    {"Offroad_InvalidTime", CLEAR_ON_MANAGER_START},
    {"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START},
    {"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START},
    {"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START},
    {"Offroad_HardwareUnsupported", CLEAR_ON_MANAGER_START},
    {"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START},
    {"Offroad_NvmeMissing", CLEAR_ON_MANAGER_START},
    {"ForcePowerDown", CLEAR_ON_MANAGER_START},
    {"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
};

} // namespace

Params::Params(bool persistent_param) : Params(persistent_param ? persistent_params_path : default_params_path) {}

std::once_flag default_params_path_ensured;
Params::Params(const std::string &path) : params_path(path) {
  if (path == default_params_path) {
    std::call_once(default_params_path_ensured, ensure_params_path, path);
  } else {
    ensure_params_path(path);
  }
}

bool Params::checkKey(const std::string &key) {
  return keys.find(key) != keys.end();
}

int Params::put(const char* key, const char* value, size_t value_size) {
  // Information about safely and atomically writing a file: https://lwn.net/Articles/457667/
  // 1) Create temp file
  // 2) Write data to temp file
  // 3) fsync() the temp file
  // 4) rename the temp file to the real name
  // 5) fsync() the containing directory
  std::string tmp_path = params_path + "/.tmp_value_XXXXXX";
  int tmp_fd = mkstemp((char*)tmp_path.c_str());
  if (tmp_fd < 0) return -1;

  int result = -1;
  do {
    // Write value to temp.
    ssize_t bytes_written = HANDLE_EINTR(write(tmp_fd, value, value_size));
    if (bytes_written < 0 || (size_t)bytes_written != value_size) {
      result = -20;
      break;
    }

    // change permissions to 0666 for apks
    if ((result = fchmod(tmp_fd, 0666)) < 0) break;
    // fsync to force persist the changes.
    if ((result = fsync(tmp_fd)) < 0) break;

    FileLock file_lock(params_path + "/.lock", LOCK_EX);
    std::lock_guard<FileLock> lk(file_lock);

    // Move temp into place.
    std::string path = params_path + "/d/" + std::string(key);
    if ((result = rename(tmp_path.c_str(), path.c_str())) < 0) break;

    // fsync parent directory
    path = params_path + "/d";
    result = fsync_dir(path.c_str());
  } while (false);

  close(tmp_fd);
  remove(tmp_path.c_str());
  return result;
}

int Params::remove(const char *key) {
  FileLock file_lock(params_path + "/.lock", LOCK_EX);
  std::lock_guard<FileLock> lk(file_lock);
  // Delete value.
  std::string path = params_path + "/d/" + key;
  int result = ::remove(path.c_str());
  if (result != 0) {
    result = ERR_NO_VALUE;
    return result;
  }
  // fsync parent directory
  path = params_path + "/d";
  return fsync_dir(path.c_str());
}

std::string Params::get(const char *key, bool block) {
  std::string path = params_path + "/d/" + key;
  if (!block) {
    return util::read_file(path);
  } else {
    // blocking read until successful
    params_do_exit = 0;
    void (*prev_handler_sigint)(int) = std::signal(SIGINT, params_sig_handler);
    void (*prev_handler_sigterm)(int) = std::signal(SIGTERM, params_sig_handler);

    std::string value;
    while (!params_do_exit) {
      if (value = util::read_file(path); !value.empty()) {
        break;
      }
      util::sleep_for(100);  // 0.1 s
    }

    std::signal(SIGINT, prev_handler_sigint);
    std::signal(SIGTERM, prev_handler_sigterm);
    return value;
  }
}

int Params::readAll(std::map<std::string, std::string> *params) {
  FileLock file_lock(params_path + "/.lock", LOCK_SH);
  std::lock_guard<FileLock> lk(file_lock);

  std::string key_path = params_path + "/d";
  return util::read_files_in_dir(key_path, params);
}

void Params::clearAll(ParamKeyType key_type) {
  for (auto &[key, type] : keys) {
    if (type & key_type) {
      remove(key);
    }
  }
}
<commit_msg>fix FileLock: fd could be closed twice (#21362)<commit_after>#include "selfdrive/common/params.h"

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif  // _GNU_SOURCE

#include <dirent.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <unistd.h>

#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <mutex>
#include <unordered_map>

#include "selfdrive/common/swaglog.h"
#include "selfdrive/common/util.h"
#include "selfdrive/hardware/hw.h"

// keep trying if x gets interrupted by a signal
#define HANDLE_EINTR(x)                                       \
  ({                                                          \
    decltype(x) ret;                                          \
    int try_cnt = 0;                                          \
    do {                                                      \
      ret = (x);                                              \
    } while (ret == -1 && errno == EINTR && try_cnt++ < 100); \
    ret;                                                      \
  })

namespace {

const std::string default_params_path = Hardware::PC() ? util::getenv_default("HOME", "/.comma/params", "/data/params")
                                                       : "/data/params";
const std::string persistent_params_path = Hardware::PC() ? default_params_path : "/persist/comma/params";

volatile sig_atomic_t params_do_exit = 0;
void params_sig_handler(int signal) {
  params_do_exit = 1;
}

int fsync_dir(const char* path) {
  int fd = HANDLE_EINTR(open(path, O_RDONLY, 0755));
  if (fd < 0) {
    return -1;
  }

  int result = fsync(fd);
  int result_close = close(fd);
  if (result_close < 0) {
    result = result_close;
  }
  return result;
}

// TODO: replace by std::filesystem::create_directories
int mkdir_p(std::string path) {
  char * _path = (char *)path.c_str();

  mode_t prev_mask = umask(0);
  for (char *p = _path + 1; *p; p++) {
    if (*p == '/') {
      *p = '\0'; // Temporarily truncate
      if (mkdir(_path, 0777) != 0) {
        if (errno != EEXIST) return -1;
      }
      *p = '/';
    }
  }
  if (mkdir(_path, 0777) != 0) {
    if (errno != EEXIST) return -1;
  }
  chmod(_path, 0777);
  umask(prev_mask);
  return 0;
}

static bool create_params_path(const std::string &param_path, const std::string &key_path) {
  // Make sure params path exists
  if (!util::file_exists(param_path) && mkdir_p(param_path) != 0) {
    return false;
  }

  // See if the symlink exists, otherwise create it
  if (!util::file_exists(key_path)) {
    // 1) Create temp folder
    // 2) Set permissions
    // 3) Symlink it to temp link
    // 4) Move symlink to <params>/d

    std::string tmp_path = param_path + "/.tmp_XXXXXX";
    // this should be OK since mkdtemp just replaces characters in place
    char *tmp_dir = mkdtemp((char *)tmp_path.c_str());
    if (tmp_dir == NULL) {
      return false;
    }

    if (chmod(tmp_dir, 0777) != 0) {
      return false;
    }

    std::string link_path = std::string(tmp_dir) + ".link";
    if (symlink(tmp_dir, link_path.c_str()) != 0) {
      return false;
    }

    // don't return false if it has been created by other
    if (rename(link_path.c_str(), key_path.c_str()) != 0 && errno != EEXIST) {
      return false;
    }
  }

  // Ensure permissions are correct in case we didn't create the symlink
  return chmod(key_path.c_str(), 0777) == 0;
}

static void ensure_params_path(const std::string &params_path) {
  if (!create_params_path(params_path, params_path + "/d")) {
    throw std::runtime_error(util::string_format("Failed to ensure params path, errno=%d", errno));
  }
}

class FileLock {
 public:
  FileLock(const std::string& file_name, int op) : fn_(file_name), op_(op) {}

  void lock() {
    fd_ = HANDLE_EINTR(open(fn_.c_str(), O_CREAT, 0775));
    if (fd_ < 0) {
      LOGE("Failed to open lock file %s, errno=%d", fn_.c_str(), errno);
      return;
    }
    if (HANDLE_EINTR(flock(fd_, op_)) < 0) {
      LOGE("Failed to lock file %s, errno=%d", fn_.c_str(), errno);
    }
  }

  void unlock() { close(fd_); }

private:
  int fd_ = -1, op_;
  std::string fn_;
};

std::unordered_map<std::string, uint32_t> keys = {
    {"AccessToken", CLEAR_ON_MANAGER_START},
    {"ApiCache_DriveStats", PERSISTENT},
    {"ApiCache_Device", PERSISTENT},
    {"ApiCache_Owner", PERSISTENT},
    {"ApiCache_NavDestinations", PERSISTENT},
    {"AthenadPid", PERSISTENT},
    {"CalibrationParams", PERSISTENT},
    {"CarBatteryCapacity", PERSISTENT},
    {"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT | CLEAR_ON_IGNITION_ON},
    {"CarParamsCache", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT},
    {"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT | CLEAR_ON_IGNITION_ON},
    {"CommunityFeaturesToggle", PERSISTENT},
    {"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT | CLEAR_ON_IGNITION_ON},
    {"DisableRadar", PERSISTENT}, // WARNING: THIS DISABLES AEB
    {"EnableLteOnroad", PERSISTENT},
    {"EndToEndToggle", PERSISTENT},
    {"CompletedTrainingVersion", PERSISTENT},
    {"DisablePowerDown", PERSISTENT},
    {"DisableUpdates", PERSISTENT},
    {"EnableWideCamera", PERSISTENT},
    {"DoUninstall", CLEAR_ON_MANAGER_START},
    {"DongleId", PERSISTENT},
    {"GitDiff", PERSISTENT},
    {"GitBranch", PERSISTENT},
    {"GitCommit", PERSISTENT},
    {"GitRemote", PERSISTENT},
    {"GithubSshKeys", PERSISTENT},
    {"GithubUsername", PERSISTENT},
    {"HardwareSerial", PERSISTENT},
    {"HasAcceptedTerms", PERSISTENT},
    {"IsDriverViewEnabled", CLEAR_ON_MANAGER_START},
    {"IMEI", PERSISTENT},
    {"IsLdwEnabled", PERSISTENT},
    {"IsMetric", PERSISTENT},
    {"IsOffroad", CLEAR_ON_MANAGER_START},
    {"IsOnroad", PERSISTENT},
    {"IsRHD", PERSISTENT},
    {"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
    {"IsUpdateAvailable", CLEAR_ON_MANAGER_START},
    {"UploadRaw", PERSISTENT},
    {"LastAthenaPingTime", PERSISTENT},
    {"LastGPSPosition", PERSISTENT},
    {"LastUpdateException", PERSISTENT},
    {"LastUpdateTime", PERSISTENT},
    {"LiveParameters", PERSISTENT},
    {"MapboxToken", PERSISTENT},
    {"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
    {"NavSettingTime24h", PERSISTENT},
    {"OpenpilotEnabledToggle", PERSISTENT},
    {"PandaFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT},
    {"PandaFirmwareHex", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT},
    {"PandaDongleId", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT},
    {"Passive", PERSISTENT},
    {"RecordFront", PERSISTENT},
    {"RecordFrontLock", PERSISTENT},  // for the internal fleet
    {"ReleaseNotes", PERSISTENT},
    {"ShouldDoUpdate", CLEAR_ON_MANAGER_START},
    {"SubscriberInfo", PERSISTENT},
    {"SshEnabled", PERSISTENT},
    {"TermsVersion", PERSISTENT},
    {"Timezone", PERSISTENT},
    {"TrainingVersion", PERSISTENT},
    {"UpdateAvailable", CLEAR_ON_MANAGER_START},
    {"UpdateFailedCount", CLEAR_ON_MANAGER_START},
    {"Version", PERSISTENT},
    {"VisionRadarToggle", PERSISTENT},
    {"Offroad_ChargeDisabled", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT},
    {"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START},
    {"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START},
    {"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START},
    {"Offroad_PandaFirmwareMismatch", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT},
    {"Offroad_InvalidTime", CLEAR_ON_MANAGER_START},
    {"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START},
    {"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START},
    {"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START},
    {"Offroad_HardwareUnsupported", CLEAR_ON_MANAGER_START},
    {"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START},
    {"Offroad_NvmeMissing", CLEAR_ON_MANAGER_START},
    {"ForcePowerDown", CLEAR_ON_MANAGER_START},
    {"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
};

} // namespace

Params::Params(bool persistent_param) : Params(persistent_param ? persistent_params_path : default_params_path) {}

std::once_flag default_params_path_ensured;
Params::Params(const std::string &path) : params_path(path) {
  if (path == default_params_path) {
    std::call_once(default_params_path_ensured, ensure_params_path, path);
  } else {
    ensure_params_path(path);
  }
}

bool Params::checkKey(const std::string &key) {
  return keys.find(key) != keys.end();
}

int Params::put(const char* key, const char* value, size_t value_size) {
  // Information about safely and atomically writing a file: https://lwn.net/Articles/457667/
  // 1) Create temp file
  // 2) Write data to temp file
  // 3) fsync() the temp file
  // 4) rename the temp file to the real name
  // 5) fsync() the containing directory
  std::string tmp_path = params_path + "/.tmp_value_XXXXXX";
  int tmp_fd = mkstemp((char*)tmp_path.c_str());
  if (tmp_fd < 0) return -1;

  int result = -1;
  do {
    // Write value to temp.
    ssize_t bytes_written = HANDLE_EINTR(write(tmp_fd, value, value_size));
    if (bytes_written < 0 || (size_t)bytes_written != value_size) {
      result = -20;
      break;
    }

    // change permissions to 0666 for apks
    if ((result = fchmod(tmp_fd, 0666)) < 0) break;
    // fsync to force persist the changes.
    if ((result = fsync(tmp_fd)) < 0) break;

    FileLock file_lock(params_path + "/.lock", LOCK_EX);
    std::lock_guard<FileLock> lk(file_lock);

    // Move temp into place.
    std::string path = params_path + "/d/" + std::string(key);
    if ((result = rename(tmp_path.c_str(), path.c_str())) < 0) break;

    // fsync parent directory
    path = params_path + "/d";
    result = fsync_dir(path.c_str());
  } while (false);

  close(tmp_fd);
  remove(tmp_path.c_str());
  return result;
}

int Params::remove(const char *key) {
  FileLock file_lock(params_path + "/.lock", LOCK_EX);
  std::lock_guard<FileLock> lk(file_lock);
  // Delete value.
  std::string path = params_path + "/d/" + key;
  int result = ::remove(path.c_str());
  if (result != 0) {
    result = ERR_NO_VALUE;
    return result;
  }
  // fsync parent directory
  path = params_path + "/d";
  return fsync_dir(path.c_str());
}

std::string Params::get(const char *key, bool block) {
  std::string path = params_path + "/d/" + key;
  if (!block) {
    return util::read_file(path);
  } else {
    // blocking read until successful
    params_do_exit = 0;
    void (*prev_handler_sigint)(int) = std::signal(SIGINT, params_sig_handler);
    void (*prev_handler_sigterm)(int) = std::signal(SIGTERM, params_sig_handler);

    std::string value;
    while (!params_do_exit) {
      if (value = util::read_file(path); !value.empty()) {
        break;
      }
      util::sleep_for(100);  // 0.1 s
    }

    std::signal(SIGINT, prev_handler_sigint);
    std::signal(SIGTERM, prev_handler_sigterm);
    return value;
  }
}

int Params::readAll(std::map<std::string, std::string> *params) {
  FileLock file_lock(params_path + "/.lock", LOCK_SH);
  std::lock_guard<FileLock> lk(file_lock);

  std::string key_path = params_path + "/d";
  return util::read_files_in_dir(key_path, params);
}

void Params::clearAll(ParamKeyType key_type) {
  for (auto &[key, type] : keys) {
    if (type & key_type) {
      remove(key);
    }
  }
}
<|endoftext|>


<commit_before>#pragma once

#include <gcl/functional.hpp>

#include <tuple>
#include <type_traits>

namespace gcl::mp
{
    template <typename Function>
    class function_traits
    {
        template <typename>
        struct member_function_traits_impl;
        template <typename ClassType, typename ReturnType, typename... Arguments>
        struct member_function_traits_impl<ReturnType (ClassType::*)(Arguments...)>
        {
            using result_type = ReturnType;
            using class_type = ClassType;
            using arguments = std::tuple<Arguments...>;
            template <std::size_t N>
            using argument = typename std::tuple_element_t<N, std::tuple<Arguments...>>;
        };
        template <typename ClassType, typename ReturnType, typename... Arguments>
        struct member_function_traits_impl<ReturnType (ClassType::*)(Arguments...) const>
        {
            using result_type = ReturnType;
            using class_type = const ClassType;
            using arguments = std::tuple<Arguments...>;
            template <std::size_t N>
            using argument = typename std::tuple_element_t<N, std::tuple<Arguments...>>;
        };

        template <typename>
        struct function_traits_impl;
        template <typename ReturnType, typename... Arguments>
        struct function_traits_impl<ReturnType (*)(Arguments...)>
        {
            using result_type = ReturnType;
            using arguments = std::tuple<Arguments...>;
            template <std::size_t N>
            using argument = typename std::tuple_element_t<N, std::tuple<Arguments...>>;
        };

      public:
        using type = std::conditional_t<
            std::is_member_function_pointer_v<Function>,
            member_function_traits_impl<Function>,
            function_traits_impl<Function>>;
    };

    template <typename Function>
    using function_traits_t = typename function_traits<Function>::type;
    // using function_traits = member_function_traits_impl<decltype(&Function::operator())>;
}

namespace gcl::mp::test
{
    struct toto
    {
        int const_member(char) const { return 42; }
        int not_const_member(char) { return 42; }
    };
    static_assert(std::is_same_v<int, function_traits_t<decltype(&toto::const_member)>::result_type>);
    static_assert(std::is_same_v<int, function_traits_t<decltype(&toto::not_const_member)>::result_type>);
    int qwe(char) { return 42; };
    static_assert(std::is_same_v<char, function_traits_t<decltype(&qwe)>::argument<0>>);
}<commit_msg>[mp::function_trait] add no_except<commit_after>#pragma once

#include <gcl/functional.hpp>

#include <tuple>
#include <type_traits>

namespace gcl::mp
{
    template <typename Function>
    class function_traits {
        struct informations {
            const bool is_const_v;
            const bool is_member_function_v;
            const bool is_no_except;
            // is constexpr
        };

        template <typename>
        struct member_function_traits_impl;
        template <typename ClassType, typename ReturnType, typename... Arguments>
        struct member_function_traits_impl<ReturnType (ClassType::*)(Arguments...)> {
            using result_type = ReturnType;
            using class_type = ClassType;
            using arguments = std::tuple<Arguments...>;
            template <std::size_t N>
            using argument = typename std::tuple_element_t<N, std::tuple<Arguments...>>;
        };
        template <typename ClassType, typename ReturnType, typename... Arguments>
        struct member_function_traits_impl<ReturnType (ClassType::*)(Arguments...) noexcept>
            : member_function_traits_impl<ReturnType (ClassType::*)(Arguments...)> {};
        template <typename ClassType, typename ReturnType, typename... Arguments>
        struct member_function_traits_impl<ReturnType (ClassType::*)(Arguments...) const>
            : member_function_traits_impl<ReturnType (ClassType::*)(Arguments...)> {};
        template <typename ClassType, typename ReturnType, typename... Arguments>
        struct member_function_traits_impl<ReturnType (ClassType::*)(Arguments...) const noexcept>
            : member_function_traits_impl<ReturnType (ClassType::*)(Arguments...)> {};

        template <typename>
        struct function_traits_impl;
        template <typename ReturnType, typename... Arguments>
        struct function_traits_impl<ReturnType (*)(Arguments...)> {
            using result_type = ReturnType;
            using arguments = std::tuple<Arguments...>;
            template <std::size_t N>
            using argument = typename std::tuple_element_t<N, std::tuple<Arguments...>>;
        };

      public:
        using type = std::conditional_t<
            std::is_member_function_pointer_v<Function>,
            member_function_traits_impl<Function>,
            function_traits_impl<Function>>;
    };

    template <typename Function>
    using function_traits_t = typename function_traits<Function>::type;
    // using function_traits = member_function_traits_impl<decltype(&Function::operator())>;
}

namespace gcl::mp::test
{
    struct toto
    {
        int const_member(char) const { return 42; }
        int not_const_member(char) { return 42; }
        int noexcept_const_member(char) const noexcept { return 42; }
        int noexcept_not_const_member(char) noexcept { return 42; }
    };
    static_assert(std::is_same_v<int, function_traits_t<decltype(&toto::const_member)>::result_type>);
    static_assert(std::is_same_v<int, function_traits_t<decltype(&toto::not_const_member)>::result_type>);
    int qwe(char) { return 42; };
    static_assert(std::is_same_v<char, function_traits_t<decltype(&qwe)>::argument<0>>);
}<|endoftext|>


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

#pragma hdrstop

#include "saveopt.hxx"

#ifndef _UTL_CONFIGMGR_HXX_
#include <unotools/configmgr.hxx>
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif

#include <osl/mutex.hxx>

using namespace utl;
using namespace rtl;
using namespace com::sun::star::uno;

static SvtSaveOptions_Impl* pOptions = NULL;
static sal_Int32           nRefCount = 0;

class SvtSaveOptions_Impl : public utl::ConfigItem
{
    sal_Int32                           nAutoSaveTime;
    SvtSaveOptions::SaveGraphicsMode    eSaveGraphics;
    sal_Bool                            bUseUserData,
                                        bBackup,
                                        bAutoSave,
                                        bAutoSavePrompt,
                                        bDocInfSave,
                                        bSaveWorkingSet,
                                        bSaveDocWins,
                                        bSaveDocView,
                                        bSaveRelINet,
                                        bSaveRelFSys;
public:
                            SvtSaveOptions_Impl();

    virtual void            Notify( const com::sun::star::uno::Sequence< rtl::OUString >& aPropertyNames );
    virtual void            Commit();

    void                    SetAutoSaveTime( sal_Int32 n )      { nAutoSaveTime = n; SetModified();  }
    sal_Int32               GetAutoSaveTime() const             { return nAutoSaveTime; }
    void                    SetUseUserData( BOOL b )            { bUseUserData = b; SetModified();}
    BOOL                    IsUseUserData() const               { return bUseUserData; }
    void                    SetBackup( BOOL b )                 { bBackup = b; SetModified();}
    BOOL                    IsBackup() const                    { return bBackup; }
    void                    SetAutoSave( BOOL b )               { bAutoSave = b; SetModified();    }
    BOOL                    IsAutoSave() const                  { return bAutoSave; }
    void                    SetAutoSavePrompt( BOOL b )         { bAutoSavePrompt = b; SetModified();  }
    BOOL                    IsAutoSavePrompt() const            { return bAutoSavePrompt; }
    void                    SetDocInfoSave(BOOL b)              { bDocInfSave = b; SetModified(); }
    BOOL                    IsDocInfoSave() const               { return bDocInfSave; }
    void                    SetSaveGraphicsMode( SvtSaveOptions::SaveGraphicsMode eMode )   { eSaveGraphics = eMode; SetModified(); }
    SvtSaveOptions::SaveGraphicsMode        GetSaveGraphicsMode() const         { return eSaveGraphics; }
    void                    SetSaveWorkingSet( BOOL b )         { bSaveWorkingSet = b; SetModified();}
    BOOL                    IsSaveWorkingSet() const            { return bSaveWorkingSet;         }
    void                    SetSaveDocWins( BOOL b )            { bSaveDocWins = b; SetModified();}
    BOOL                    IsSaveDocWins() const               { return bSaveDocWins; }
    void                    SetSaveDocView( BOOL b )            { bSaveDocView = b; SetModified();}
    BOOL                    IsSaveDocView() const               { return bSaveDocView; }
    void                    SetSaveRelINet( BOOL b )            { bSaveRelINet = b; SetModified();}
    BOOL                    IsSaveRelINet() const               { return bSaveRelINet; }
    void                    SetSaveRelFSys( BOOL b )            { bSaveRelFSys = b; SetModified();}
    BOOL                    IsSaveRelFSys() const               { return bSaveRelFSys; }
};

#define FORMAT 0
#define TIMEINTERVALL 1
#define USEUSERDATA 2
#define CREATEBACKUP 3
#define AUTOSAVE 4
#define PROMPT 5
#define EDITPROPERTY 6
#define SAVEDOCWINS 7
#define SAVEVIEWINFO 8
#define FILESYSTEM 9
#define INTERNET 10
#define SAVEWORKINGSET 11

Sequence< OUString > GetPropertyNames()
{
    static const char* aPropNames[] =
    {
        "Graphic/Format",
        "Document/AutoSaveTimeIntervall",
        "Document/UseUserData",
        "Document/CreateBackup",
        "Document/AutoSave",
        "Document/AutoSavePrompt",
        "Document/EditProperty",
        "Document/DocumentWindows",
        "Document/ViewInfo",
        "URL/FileSystem",
        "URL/Internet",
        "WorkingSet"
    };

    const int nCount = sizeof( aPropNames ) / sizeof( const char* );
    Sequence< OUString > aNames( nCount );
    OUString* pNames = aNames.getArray();
    for ( int i = 0; i < nCount; i++ )
        pNames[i] = OUString::createFromAscii( aPropNames[i] );

    return aNames;
}

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

SvtSaveOptions_Impl::SvtSaveOptions_Impl()
    : ConfigItem( OUString::createFromAscii("Office.Common/Save") )
    , nAutoSaveTime( 0 )
    , eSaveGraphics( SvtSaveOptions::SaveGraphicsNormal )
    , bUseUserData( sal_False )
    , bBackup( sal_False )
    , bAutoSave( sal_False )
    , bAutoSavePrompt( sal_False )
    , bDocInfSave( sal_False )
    , bSaveWorkingSet( sal_False )
    , bSaveDocWins( sal_False )
    , bSaveDocView( sal_False )
    , bSaveRelINet( sal_False )
    , bSaveRelFSys( sal_False )
{
    Sequence< OUString > aNames = GetPropertyNames();
    Sequence< Any > aValues = GetProperties( aNames );
    EnableNotification( aNames );
    const Any* pValues = aValues.getConstArray();
    DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" );
    if ( aValues.getLength() == aNames.getLength() )
    {
        for ( int nProp = 0; nProp < aNames.getLength(); nProp++ )
        {
            DBG_ASSERT( pValues[nProp].hasValue(), "property value missing" );
            if ( pValues[nProp].hasValue() )
            {
                sal_Int32 nTemp;
                switch ( nProp )
                {
                    case TIMEINTERVALL :
                        if ( pValues[nProp] >>= nTemp )
                            nAutoSaveTime = nTemp;
                        else
                            DBG_ERROR( "Wrong Type!" );
                        break;

                    case FORMAT :
                        if ( pValues[nProp] >>= nTemp )
                            eSaveGraphics = (SvtSaveOptions::SaveGraphicsMode) nTemp;
                        else
                            DBG_ERROR( "Wrong Type!" );
                        break;

                    default:
                    {
                        sal_Bool bTemp;
                        if ( pValues[nProp] >>= bTemp )
                        {
                            switch ( nProp )
                            {
                                case USEUSERDATA :
                                    bUseUserData = bTemp;
                                    break;
                                case CREATEBACKUP :
                                    bBackup = bTemp;
                                    break;
                                case AUTOSAVE :
                                    bAutoSave = bTemp;
                                    break;
                                case PROMPT :
                                    bAutoSavePrompt = bTemp;
                                    break;
                                case EDITPROPERTY :
                                    bDocInfSave = bTemp;
                                    break;
                                case SAVEWORKINGSET :
                                    bSaveWorkingSet = bTemp;
                                    break;
                                case SAVEDOCWINS :
                                    bSaveDocWins = bTemp;
                                    break;
                                case SAVEVIEWINFO :
                                    bSaveDocView = bTemp;
                                    break;
                                case FILESYSTEM :
                                    bSaveRelFSys = bTemp;
                                    break;
                                case INTERNET :
                                    bSaveRelINet = bTemp;
                                    break;

                                default :
                                    DBG_ERRORFILE( "invalid index to load a path" );
                            }
                        }
                        else
                            DBG_ERROR( "Wrong Type!" );

                    }
                }
            }
        }
    }
}

void SvtSaveOptions_Impl::Commit()
{
    Sequence< OUString > aNames = GetPropertyNames();
    OUString* pNames = aNames.getArray();
    Sequence< Any > aValues( aNames.getLength() );
    Any* pValues = aValues.getArray();
    for ( int nProp = 0; nProp < aNames.getLength(); nProp++ )
    {
        switch ( nProp )
        {
            case TIMEINTERVALL :
                pValues[nProp] <<= nAutoSaveTime;
                break;
            case FORMAT :
                pValues[nProp] <<= (sal_Int16 ) eSaveGraphics;
                break;
            case USEUSERDATA :
                pValues[nProp] <<= bUseUserData;
                break;
            case CREATEBACKUP :
                pValues[nProp] <<= bBackup;
                break;
            case AUTOSAVE :
                pValues[nProp] <<= bAutoSave;
                break;
            case PROMPT :
                pValues[nProp] <<= bAutoSavePrompt;
                break;
            case EDITPROPERTY :
                pValues[nProp] <<= bDocInfSave;
                break;
            case SAVEWORKINGSET :
                pValues[nProp] <<= bSaveWorkingSet;
                break;
            case SAVEDOCWINS :
                pValues[nProp] <<= bSaveDocWins;
                break;
            case SAVEVIEWINFO :
                pValues[nProp] <<= bSaveDocView;
                break;
            case FILESYSTEM :
                pValues[nProp] <<= bSaveRelFSys;
                break;
            case INTERNET :
                pValues[nProp] <<= bSaveRelINet;
                break;
            default:
                DBG_ERRORFILE( "invalid index to save a path" );
        }
    }

    PutProperties( aNames, aValues );
}

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

void SvtSaveOptions_Impl::Notify( const Sequence<rtl::OUString>& aPropertyNames )
{
    DBG_ERRORFILE( "properties have been changed" );
}

SvtSaveOptions::SvtSaveOptions()
{
    // Global access, must be guarded (multithreading)
    ::osl::MutexGuard aGuard( osl::Mutex::getGlobalMutex() );
    if ( !pOptions )
        pOptions = new SvtSaveOptions_Impl;
    ++nRefCount;
    pImp = pOptions;
}

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

SvtSaveOptions::~SvtSaveOptions()
{
    // Global access, must be guarded (multithreading)
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if ( !--nRefCount )
    {
        if ( pOptions->IsModified() )
            pOptions->Commit();
        DELETEZ( pOptions );
    }
}

void SvtSaveOptions::SetAutoSaveTime( sal_Int32 n )
{
    pImp->SetAutoSaveTime( n );
}

sal_Int32 SvtSaveOptions::GetAutoSaveTime() const
{
    return pImp->GetAutoSaveTime();
}

void SvtSaveOptions::SetUseUserData( sal_Bool b )
{
    pImp->SetUseUserData( b );
}

sal_Bool SvtSaveOptions::IsUseUserData() const
{
    return pImp->IsUseUserData();
}

void SvtSaveOptions::SetBackup( sal_Bool b )
{
    pImp->SetBackup( b );
}

sal_Bool SvtSaveOptions::IsBackup() const
{
    return pImp->IsBackup();
}

void SvtSaveOptions::SetAutoSave( sal_Bool b )
{
    pImp->SetAutoSave( b );
}

sal_Bool SvtSaveOptions::IsAutoSave() const
{
    return pImp->IsAutoSave();
}

void SvtSaveOptions::SetAutoSavePrompt( sal_Bool b )
{
    pImp->SetAutoSavePrompt( b );
}

sal_Bool SvtSaveOptions::IsAutoSavePrompt() const
{
    return pImp->IsAutoSavePrompt();
}

void SvtSaveOptions::SetDocInfoSave(sal_Bool b)
{
    pImp->SetDocInfoSave( b );
}

sal_Bool SvtSaveOptions::IsDocInfoSave() const
{
    return pImp->IsDocInfoSave();
}

void SvtSaveOptions::SetSaveWorkingSet( sal_Bool b )
{
    pImp->SetSaveWorkingSet( b );
}

sal_Bool SvtSaveOptions::IsSaveWorkingSet() const
{
    return pImp->IsSaveWorkingSet();
}

void SvtSaveOptions::SetSaveDocWins( sal_Bool b )
{
    pImp->SetSaveDocWins( b );
}

sal_Bool SvtSaveOptions::IsSaveDocWins() const
{
    return pImp->IsSaveDocWins();
}

void SvtSaveOptions::SetSaveDocView( sal_Bool b )
{
    pImp->SetSaveDocView( b );
}

sal_Bool SvtSaveOptions::IsSaveDocView() const
{
    return pImp->IsSaveDocView();
}

void SvtSaveOptions::SetSaveRelINet( sal_Bool b )
{
    pImp->SetSaveRelINet( b );
}

sal_Bool SvtSaveOptions::IsSaveRelINet() const
{
    return pImp->IsSaveRelINet();
}

void SvtSaveOptions::SetSaveRelFSys( sal_Bool b )
{
    pImp->SetSaveRelFSys( b );
}

sal_Bool SvtSaveOptions::IsSaveRelFSys() const
{
    return pImp->IsSaveRelFSys();
}

SvtSaveOptions::SaveGraphicsMode SvtSaveOptions::GetSaveGraphicsMode() const
{
    return pImp->GetSaveGraphicsMode();
}

void SvtSaveOptions::SetSaveGraphicsMode( SvtSaveOptions::SaveGraphicsMode eMode )
{
    // #87097#: don't allow setting of this property (it isn't needed anymore)
    // pImp->SetSaveGraphicsMode( eMode );
}

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

#pragma hdrstop

#include "saveopt.hxx"

#ifndef _UTL_CONFIGMGR_HXX_
#include <unotools/configmgr.hxx>
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif

#include <osl/mutex.hxx>

using namespace utl;
using namespace rtl;
using namespace com::sun::star::uno;

static SvtSaveOptions_Impl* pOptions = NULL;
static sal_Int32           nRefCount = 0;

class SvtSaveOptions_Impl : public utl::ConfigItem
{
    sal_Int32                           nAutoSaveTime;
    SvtSaveOptions::SaveGraphicsMode    eSaveGraphics;
    sal_Bool                            bUseUserData,
                                        bBackup,
                                        bAutoSave,
                                        bAutoSavePrompt,
                                        bDocInfSave,
                                        bSaveWorkingSet,
                                        bSaveDocWins,
                                        bSaveDocView,
                                        bSaveRelINet,
                                        bSaveRelFSys,
                                        bSaveUnpacked;
public:
                            SvtSaveOptions_Impl();

    virtual void            Notify( const com::sun::star::uno::Sequence< rtl::OUString >& aPropertyNames );
    virtual void            Commit();

    void                    SetAutoSaveTime( sal_Int32 n )      { nAutoSaveTime = n; SetModified();  }
    sal_Int32               GetAutoSaveTime() const             { return nAutoSaveTime; }
    void                    SetUseUserData( BOOL b )            { bUseUserData = b; SetModified();}
    BOOL                    IsUseUserData() const               { return bUseUserData; }
    void                    SetBackup( BOOL b )                 { bBackup = b; SetModified();}
    BOOL                    IsBackup() const                    { return bBackup; }
    void                    SetAutoSave( BOOL b )               { bAutoSave = b; SetModified();    }
    BOOL                    IsAutoSave() const                  { return bAutoSave; }
    void                    SetAutoSavePrompt( BOOL b )         { bAutoSavePrompt = b; SetModified();  }
    BOOL                    IsAutoSavePrompt() const            { return bAutoSavePrompt; }
    void                    SetDocInfoSave(BOOL b)              { bDocInfSave = b; SetModified(); }
    BOOL                    IsDocInfoSave() const               { return bDocInfSave; }
    void                    SetSaveGraphicsMode( SvtSaveOptions::SaveGraphicsMode eMode )   { eSaveGraphics = eMode; SetModified(); }
    SvtSaveOptions::SaveGraphicsMode        GetSaveGraphicsMode() const         { return eSaveGraphics; }
    void                    SetSaveWorkingSet( BOOL b )         { bSaveWorkingSet = b; SetModified();}
    BOOL                    IsSaveWorkingSet() const            { return bSaveWorkingSet;         }
    void                    SetSaveDocWins( BOOL b )            { bSaveDocWins = b; SetModified();}
    BOOL                    IsSaveDocWins() const               { return bSaveDocWins; }
    void                    SetSaveDocView( BOOL b )            { bSaveDocView = b; SetModified();}
    BOOL                    IsSaveDocView() const               { return bSaveDocView; }
    void                    SetSaveRelINet( BOOL b )            { bSaveRelINet = b; SetModified();}
    BOOL                    IsSaveRelINet() const               { return bSaveRelINet; }
    void                    SetSaveRelFSys( BOOL b )            { bSaveRelFSys = b; SetModified();}
    BOOL                    IsSaveRelFSys() const               { return bSaveRelFSys; }
    void                    SetSaveUnpacked( BOOL b )           { bSaveUnpacked = b; SetModified();}
    BOOL                    IsSaveUnpacked() const              { return bSaveUnpacked; }
};

#define FORMAT 0
#define TIMEINTERVALL 1
#define USEUSERDATA 2
#define CREATEBACKUP 3
#define AUTOSAVE 4
#define PROMPT 5
#define EDITPROPERTY 6
#define SAVEDOCWINS 7
#define SAVEVIEWINFO 8
#define UNPACKED 9
#define FILESYSTEM 10
#define INTERNET 11
#define SAVEWORKINGSET 12

Sequence< OUString > GetPropertyNames()
{
    static const char* aPropNames[] =
    {
        "Graphic/Format",
        "Document/AutoSaveTimeIntervall",
        "Document/UseUserData",
        "Document/CreateBackup",
        "Document/AutoSave",
        "Document/AutoSavePrompt",
        "Document/EditProperty",
        "Document/DocumentWindows",
        "Document/ViewInfo",
        "Document/Unpacked",
        "URL/FileSystem",
        "URL/Internet",
        "WorkingSet"
    };

    const int nCount = sizeof( aPropNames ) / sizeof( const char* );
    Sequence< OUString > aNames( nCount );
    OUString* pNames = aNames.getArray();
    for ( int i = 0; i < nCount; i++ )
        pNames[i] = OUString::createFromAscii( aPropNames[i] );

    return aNames;
}

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

SvtSaveOptions_Impl::SvtSaveOptions_Impl()
    : ConfigItem( OUString::createFromAscii("Office.Common/Save") )
    , nAutoSaveTime( 0 )
    , eSaveGraphics( SvtSaveOptions::SaveGraphicsNormal )
    , bUseUserData( sal_False )
    , bBackup( sal_False )
    , bAutoSave( sal_False )
    , bAutoSavePrompt( sal_False )
    , bDocInfSave( sal_False )
    , bSaveWorkingSet( sal_False )
    , bSaveDocWins( sal_False )
    , bSaveDocView( sal_False )
    , bSaveRelINet( sal_False )
    , bSaveRelFSys( sal_False )
    , bSaveUnpacked( sal_False )
{
    Sequence< OUString > aNames = GetPropertyNames();
    Sequence< Any > aValues = GetProperties( aNames );
    EnableNotification( aNames );
    const Any* pValues = aValues.getConstArray();
    DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" );
    if ( aValues.getLength() == aNames.getLength() )
    {
        for ( int nProp = 0; nProp < aNames.getLength(); nProp++ )
        {
            DBG_ASSERT( pValues[nProp].hasValue(), "property value missing" );
            if ( pValues[nProp].hasValue() )
            {
                sal_Int32 nTemp;
                switch ( nProp )
                {
                    case TIMEINTERVALL :
                        if ( pValues[nProp] >>= nTemp )
                            nAutoSaveTime = nTemp;
                        else
                            DBG_ERROR( "Wrong Type!" );
                        break;

                    case FORMAT :
                        if ( pValues[nProp] >>= nTemp )
                            eSaveGraphics = (SvtSaveOptions::SaveGraphicsMode) nTemp;
                        else
                            DBG_ERROR( "Wrong Type!" );
                        break;

                    default:
                    {
                        sal_Bool bTemp;
                        if ( pValues[nProp] >>= bTemp )
                        {
                            switch ( nProp )
                            {
                                case USEUSERDATA :
                                    bUseUserData = bTemp;
                                    break;
                                case CREATEBACKUP :
                                    bBackup = bTemp;
                                    break;
                                case AUTOSAVE :
                                    bAutoSave = bTemp;
                                    break;
                                case PROMPT :
                                    bAutoSavePrompt = bTemp;
                                    break;
                                case EDITPROPERTY :
                                    bDocInfSave = bTemp;
                                    break;
                                case SAVEWORKINGSET :
                                    bSaveWorkingSet = bTemp;
                                    break;
                                case SAVEDOCWINS :
                                    bSaveDocWins = bTemp;
                                    break;
                                case SAVEVIEWINFO :
                                    bSaveDocView = bTemp;
                                    break;
                                case FILESYSTEM :
                                    bSaveRelFSys = bTemp;
                                    break;
                                case INTERNET :
                                    bSaveRelINet = bTemp;
                                    break;
                                case UNPACKED :
                                    bSaveUnpacked = bTemp;
                                    break;

                                default :
                                    DBG_ERRORFILE( "invalid index to load a path" );
                            }
                        }
                        else
                            DBG_ERROR( "Wrong Type!" );

                    }
                }
            }
        }
    }
}

void SvtSaveOptions_Impl::Commit()
{
    Sequence< OUString > aNames = GetPropertyNames();
    OUString* pNames = aNames.getArray();
    Sequence< Any > aValues( aNames.getLength() );
    Any* pValues = aValues.getArray();
    for ( int nProp = 0; nProp < aNames.getLength(); nProp++ )
    {
        switch ( nProp )
        {
            case TIMEINTERVALL :
                pValues[nProp] <<= nAutoSaveTime;
                break;
            case FORMAT :
                pValues[nProp] <<= (sal_Int16 ) eSaveGraphics;
                break;
            case USEUSERDATA :
                pValues[nProp] <<= bUseUserData;
                break;
            case CREATEBACKUP :
                pValues[nProp] <<= bBackup;
                break;
            case AUTOSAVE :
                pValues[nProp] <<= bAutoSave;
                break;
            case PROMPT :
                pValues[nProp] <<= bAutoSavePrompt;
                break;
            case EDITPROPERTY :
                pValues[nProp] <<= bDocInfSave;
                break;
            case SAVEWORKINGSET :
                pValues[nProp] <<= bSaveWorkingSet;
                break;
            case SAVEDOCWINS :
                pValues[nProp] <<= bSaveDocWins;
                break;
            case SAVEVIEWINFO :
                pValues[nProp] <<= bSaveDocView;
                break;
            case FILESYSTEM :
                pValues[nProp] <<= bSaveRelFSys;
                break;
            case INTERNET :
                pValues[nProp] <<= bSaveRelINet;
                break;
            case UNPACKED :
                pValues[nProp] <<= bSaveUnpacked;
                break;
            default:
                DBG_ERRORFILE( "invalid index to save a path" );
        }
    }

    PutProperties( aNames, aValues );
}

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

void SvtSaveOptions_Impl::Notify( const Sequence<rtl::OUString>& aPropertyNames )
{
    DBG_ERRORFILE( "properties have been changed" );
}

SvtSaveOptions::SvtSaveOptions()
{
    // Global access, must be guarded (multithreading)
    ::osl::MutexGuard aGuard( osl::Mutex::getGlobalMutex() );
    if ( !pOptions )
        pOptions = new SvtSaveOptions_Impl;
    ++nRefCount;
    pImp = pOptions;
}

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

SvtSaveOptions::~SvtSaveOptions()
{
    // Global access, must be guarded (multithreading)
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if ( !--nRefCount )
    {
        if ( pOptions->IsModified() )
            pOptions->Commit();
        DELETEZ( pOptions );
    }
}

void SvtSaveOptions::SetAutoSaveTime( sal_Int32 n )
{
    pImp->SetAutoSaveTime( n );
}

sal_Int32 SvtSaveOptions::GetAutoSaveTime() const
{
    return pImp->GetAutoSaveTime();
}

void SvtSaveOptions::SetUseUserData( sal_Bool b )
{
    pImp->SetUseUserData( b );
}

sal_Bool SvtSaveOptions::IsUseUserData() const
{
    return pImp->IsUseUserData();
}

void SvtSaveOptions::SetBackup( sal_Bool b )
{
    pImp->SetBackup( b );
}

sal_Bool SvtSaveOptions::IsBackup() const
{
    return pImp->IsBackup();
}

void SvtSaveOptions::SetAutoSave( sal_Bool b )
{
    pImp->SetAutoSave( b );
}

sal_Bool SvtSaveOptions::IsAutoSave() const
{
    return pImp->IsAutoSave();
}

void SvtSaveOptions::SetAutoSavePrompt( sal_Bool b )
{
    pImp->SetAutoSavePrompt( b );
}

sal_Bool SvtSaveOptions::IsAutoSavePrompt() const
{
    return pImp->IsAutoSavePrompt();
}

void SvtSaveOptions::SetDocInfoSave(sal_Bool b)
{
    pImp->SetDocInfoSave( b );
}

sal_Bool SvtSaveOptions::IsDocInfoSave() const
{
    return pImp->IsDocInfoSave();
}

void SvtSaveOptions::SetSaveWorkingSet( sal_Bool b )
{
    pImp->SetSaveWorkingSet( b );
}

sal_Bool SvtSaveOptions::IsSaveWorkingSet() const
{
    return pImp->IsSaveWorkingSet();
}

void SvtSaveOptions::SetSaveDocWins( sal_Bool b )
{
    pImp->SetSaveDocWins( b );
}

sal_Bool SvtSaveOptions::IsSaveDocWins() const
{
    return pImp->IsSaveDocWins();
}

void SvtSaveOptions::SetSaveDocView( sal_Bool b )
{
    pImp->SetSaveDocView( b );
}

sal_Bool SvtSaveOptions::IsSaveDocView() const
{
    return pImp->IsSaveDocView();
}

void SvtSaveOptions::SetSaveRelINet( sal_Bool b )
{
    pImp->SetSaveRelINet( b );
}

sal_Bool SvtSaveOptions::IsSaveRelINet() const
{
    return pImp->IsSaveRelINet();
}

void SvtSaveOptions::SetSaveRelFSys( sal_Bool b )
{
    pImp->SetSaveRelFSys( b );
}

sal_Bool SvtSaveOptions::IsSaveRelFSys() const
{
    return pImp->IsSaveRelFSys();
}

void SvtSaveOptions::SetSaveUnpacked( sal_Bool b )
{
    pImp->SetSaveUnpacked( b );
}

sal_Bool SvtSaveOptions::IsSaveUnpacked() const
{
    return pImp->IsSaveUnpacked();
}
SvtSaveOptions::SaveGraphicsMode SvtSaveOptions::GetSaveGraphicsMode() const
{
    return pImp->GetSaveGraphicsMode();
}

void SvtSaveOptions::SetSaveGraphicsMode( SvtSaveOptions::SaveGraphicsMode eMode )
{
    // #87097#: don't allow setting of this property (it isn't needed anymore)
    // pImp->SetSaveGraphicsMode( eMode );
}

<|endoftext|>


<commit_before>/*
* DataSource
* (C) 1999-2007 Jack Lloyd
*     2005 Matthew Gregan
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/data_src.h>
#include <botan/exceptn.h>
#include <fstream>
#include <algorithm>

namespace Botan {

/*
* Read a single byte from the DataSource
*/
size_t DataSource::read_byte(byte& out)
   {
   return read(&out, 1);
   }

/*
* Peek a single byte from the DataSource
*/
size_t DataSource::peek_byte(byte& out) const
   {
   return peek(&out, 1, 0);
   }

/*
* Discard the next N bytes of the data
*/
size_t DataSource::discard_next(size_t n)
   {
   byte buf[64] = { 0 };
   size_t discarded = 0;

   while(n)
      {
      const size_t got = this->read(buf, std::min(n, sizeof(buf)));
      discarded += got;
      n -= got;

      if(got == 0)
         break;
      }

   return discarded;
   }

/*
* Read from a memory buffer
*/
size_t DataSource_Memory::read(byte out[], size_t length)
   {
   size_t got = std::min<size_t>(m_source.size() - m_offset, length);
   copy_mem(out, m_source.data() + m_offset, got);
   m_offset += got;
   return got;
   }

bool DataSource_Memory::check_available(size_t n)
   {
   return (n <= (m_source.size() - m_offset));
   }

/*
* Peek into a memory buffer
*/
size_t DataSource_Memory::peek(byte out[], size_t length,
                               size_t peek_offset) const
   {
   const size_t bytes_left = m_source.size() - m_offset;
   if(peek_offset >= bytes_left) return 0;

   size_t got = std::min(bytes_left - peek_offset, length);
   copy_mem(out, &m_source[m_offset + peek_offset], got);
   return got;
   }

/*
* Check if the memory buffer is empty
*/
bool DataSource_Memory::end_of_data() const
   {
   return (m_offset == m_source.size());
   }

/*
* DataSource_Memory Constructor
*/
DataSource_Memory::DataSource_Memory(const std::string& in) :
   m_source(reinterpret_cast<const byte*>(in.data()),
          reinterpret_cast<const byte*>(in.data()) + in.length()),
   m_offset(0)
   {
   m_offset = 0;
   }

/*
* Read from a stream
*/
size_t DataSource_Stream::read(byte out[], size_t length)
   {
   m_source.read(reinterpret_cast<char*>(out), length);
   if(m_source.bad())
      throw Stream_IO_Error("DataSource_Stream::read: Source failure");

   size_t got = m_source.gcount();
   m_total_read += got;
   return got;
   }

bool DataSource_Stream::check_available(size_t n)
   {
   const std::streampos orig_pos = m_source.tellg();
   m_source.seekg(0, std::ios::end);
   const size_t avail = m_source.tellg() - orig_pos;
   m_source.seekg(orig_pos);
   return (avail >= n);
   }

/*
* Peek into a stream
*/
size_t DataSource_Stream::peek(byte out[], size_t length, size_t offset) const
   {
   if(end_of_data())
      throw Invalid_State("DataSource_Stream: Cannot peek when out of data");

   size_t got = 0;

   if(offset)
      {
      secure_vector<byte> buf(offset);
      m_source.read(reinterpret_cast<char*>(buf.data()), buf.size());
      if(m_source.bad())
         throw Stream_IO_Error("DataSource_Stream::peek: Source failure");
      got = m_source.gcount();
      }

   if(got == offset)
      {
      m_source.read(reinterpret_cast<char*>(out), length);
      if(m_source.bad())
         throw Stream_IO_Error("DataSource_Stream::peek: Source failure");
      got = m_source.gcount();
      }

   if(m_source.eof())
      m_source.clear();
   m_source.seekg(m_total_read, std::ios::beg);

   return got;
   }

/*
* Check if the stream is empty or in error
*/
bool DataSource_Stream::end_of_data() const
   {
   return (!m_source.good());
   }

/*
* Return a human-readable ID for this stream
*/
std::string DataSource_Stream::id() const
   {
   return m_identifier;
   }

/*
* DataSource_Stream Constructor
*/
DataSource_Stream::DataSource_Stream(const std::string& path,
                                     bool use_binary) :
   m_identifier(path),
   m_source_p(new std::ifstream(path,
                              use_binary ? std::ios::binary : std::ios::in)),
   m_source(*m_source_p),
   m_total_read(0)
   {
   if(!m_source.good())
      {
      delete m_source_p;
      throw Stream_IO_Error("DataSource: Failure opening file " + path);
      }
   }

/*
* DataSource_Stream Constructor
*/
DataSource_Stream::DataSource_Stream(std::istream& in,
                                     const std::string& name) :
   m_identifier(name),
   m_source_p(nullptr),
   m_source(in),
   m_total_read(0)
   {
   }

/*
* DataSource_Stream Destructor
*/
DataSource_Stream::~DataSource_Stream()
   {
   delete m_source_p;
   }

}
<commit_msg>Remove redundant initialization. Closes GH #399<commit_after>/*
* DataSource
* (C) 1999-2007 Jack Lloyd
*     2005 Matthew Gregan
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/data_src.h>
#include <botan/exceptn.h>
#include <fstream>
#include <algorithm>

namespace Botan {

/*
* Read a single byte from the DataSource
*/
size_t DataSource::read_byte(byte& out)
   {
   return read(&out, 1);
   }

/*
* Peek a single byte from the DataSource
*/
size_t DataSource::peek_byte(byte& out) const
   {
   return peek(&out, 1, 0);
   }

/*
* Discard the next N bytes of the data
*/
size_t DataSource::discard_next(size_t n)
   {
   byte buf[64] = { 0 };
   size_t discarded = 0;

   while(n)
      {
      const size_t got = this->read(buf, std::min(n, sizeof(buf)));
      discarded += got;
      n -= got;

      if(got == 0)
         break;
      }

   return discarded;
   }

/*
* Read from a memory buffer
*/
size_t DataSource_Memory::read(byte out[], size_t length)
   {
   size_t got = std::min<size_t>(m_source.size() - m_offset, length);
   copy_mem(out, m_source.data() + m_offset, got);
   m_offset += got;
   return got;
   }

bool DataSource_Memory::check_available(size_t n)
   {
   return (n <= (m_source.size() - m_offset));
   }

/*
* Peek into a memory buffer
*/
size_t DataSource_Memory::peek(byte out[], size_t length,
                               size_t peek_offset) const
   {
   const size_t bytes_left = m_source.size() - m_offset;
   if(peek_offset >= bytes_left) return 0;

   size_t got = std::min(bytes_left - peek_offset, length);
   copy_mem(out, &m_source[m_offset + peek_offset], got);
   return got;
   }

/*
* Check if the memory buffer is empty
*/
bool DataSource_Memory::end_of_data() const
   {
   return (m_offset == m_source.size());
   }

/*
* DataSource_Memory Constructor
*/
DataSource_Memory::DataSource_Memory(const std::string& in) :
   m_source(reinterpret_cast<const byte*>(in.data()),
          reinterpret_cast<const byte*>(in.data()) + in.length()),
   m_offset(0)
   {
   }

/*
* Read from a stream
*/
size_t DataSource_Stream::read(byte out[], size_t length)
   {
   m_source.read(reinterpret_cast<char*>(out), length);
   if(m_source.bad())
      throw Stream_IO_Error("DataSource_Stream::read: Source failure");

   size_t got = m_source.gcount();
   m_total_read += got;
   return got;
   }

bool DataSource_Stream::check_available(size_t n)
   {
   const std::streampos orig_pos = m_source.tellg();
   m_source.seekg(0, std::ios::end);
   const size_t avail = m_source.tellg() - orig_pos;
   m_source.seekg(orig_pos);
   return (avail >= n);
   }

/*
* Peek into a stream
*/
size_t DataSource_Stream::peek(byte out[], size_t length, size_t offset) const
   {
   if(end_of_data())
      throw Invalid_State("DataSource_Stream: Cannot peek when out of data");

   size_t got = 0;

   if(offset)
      {
      secure_vector<byte> buf(offset);
      m_source.read(reinterpret_cast<char*>(buf.data()), buf.size());
      if(m_source.bad())
         throw Stream_IO_Error("DataSource_Stream::peek: Source failure");
      got = m_source.gcount();
      }

   if(got == offset)
      {
      m_source.read(reinterpret_cast<char*>(out), length);
      if(m_source.bad())
         throw Stream_IO_Error("DataSource_Stream::peek: Source failure");
      got = m_source.gcount();
      }

   if(m_source.eof())
      m_source.clear();
   m_source.seekg(m_total_read, std::ios::beg);

   return got;
   }

/*
* Check if the stream is empty or in error
*/
bool DataSource_Stream::end_of_data() const
   {
   return (!m_source.good());
   }

/*
* Return a human-readable ID for this stream
*/
std::string DataSource_Stream::id() const
   {
   return m_identifier;
   }

/*
* DataSource_Stream Constructor
*/
DataSource_Stream::DataSource_Stream(const std::string& path,
                                     bool use_binary) :
   m_identifier(path),
   m_source_p(new std::ifstream(path,
                              use_binary ? std::ios::binary : std::ios::in)),
   m_source(*m_source_p),
   m_total_read(0)
   {
   if(!m_source.good())
      {
      delete m_source_p;
      throw Stream_IO_Error("DataSource: Failure opening file " + path);
      }
   }

/*
* DataSource_Stream Constructor
*/
DataSource_Stream::DataSource_Stream(std::istream& in,
                                     const std::string& name) :
   m_identifier(name),
   m_source_p(nullptr),
   m_source(in),
   m_total_read(0)
   {
   }

/*
* DataSource_Stream Destructor
*/
DataSource_Stream::~DataSource_Stream()
   {
   delete m_source_p;
   }

}
<|endoftext|>