<commit_before>/*
Copyright 2015 Adam Grandquist

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */
/**
 * @author Adam Grandquist
 * @copyright Apache
 */

#include "./reql/cursor.h"

#include "./reql/decode.hpp"

#include "./reql/connection.h"
#include "./reql/error.h"
#include "./reql/query.h"

#include <memory>
#include <future>

#include <pthread.h>

enum {
  EACH,
  END,
  ERROR
};

static void
reql_cur_close_(ReQL_Cur_t *cur);

static void
reql_cur_error(const char *msg, const char *trace) {
  reql_error_init(REQL_E_CURSOR, msg, trace);
}

static void
reql_cur_memory_error(const char *trace) {
  reql_cur_error("Insufficient memory", trace);
}

static void
reql_cur_lock(ReQL_Cur_t *cur) {
  pthread_mutex_lock(cur->condition.mutex);
}

static void
reql_cur_unlock(ReQL_Cur_t *cur) {
  if (cur == nullptr) {
    return;
  }
  pthread_mutex_unlock(cur->condition.mutex);
}

static char
reql_cur_open_(ReQL_Cur_t *cur) {
  return cur->conn != nullptr;
}

static void
reql_cur_set_end_cb_(ReQL_Cur_t *cur, ReQL_End_Function cb, void *arg) {
  cur->cb.end = cb;
  cur->cb.data[END] = arg;
}

static void
reql_cur_set_error_cb_(ReQL_Cur_t *cur, ReQL_Error_Function cb, void *arg) {
  cur->cb.error = cb;
  cur->cb.data[ERROR] = arg;
}

extern void
reql_cur_set_end_cb(ReQL_Cur_t *cur, ReQL_End_Function cb, void *arg) {
  reql_cur_lock(cur);
  reql_cur_set_end_cb_(cur, cb, arg);
  reql_cur_unlock(cur);
}

extern void
reql_cur_set_error_cb(ReQL_Cur_t *cur, ReQL_Error_Function cb, void *arg) {
  reql_cur_lock(cur);
  reql_cur_set_error_cb_(cur, cb, arg);
  reql_cur_unlock(cur);
}

extern void
reql_cur_set_response(ReQL_Cur_t *cur, const ReQL_Byte *res, ReQL_Size length) {
  reql_cur_lock(cur);
  ReQL_Parse_t u_parser = cur->get_parser();
  reql_decode(std::basic_string<ReQL_Byte>(res, length), Parser<std::basic_string<ReQL_Byte>>(&u_parser, cur));
  reql_cur_unlock(cur);
}

static void
reql_cur_close_(ReQL_Cur_t *cur) {
  if (reql_cur_open_(cur) != 0) {
    ReQL_Cur_t *prev = cur->prev == cur ? nullptr : cur->prev;
    ReQL_Cur_t *next = cur->next == cur ? nullptr : cur->next;
    if (next == nullptr && prev == nullptr) {
    } else if (prev == nullptr) {
      next->prev = next;
    } else if (next == nullptr) {
      prev->next = prev;
    } else {
      next->prev = prev;
      prev->next = next;
    }
    cur->conn->cursors = next;
    cur->conn = nullptr;
    if (cur->cb.each != nullptr) {
      cur->cb.each(nullptr, cur->cb.data[EACH]);
    }
    if (cur->cb.end != nullptr) {
      cur->cb.end(cur->cb.data[END]);
    }
    cur->cb.data[EACH] = nullptr;
    cur->cb.data[END] = nullptr;
    cur->cb.data[ERROR] = nullptr;
    cur->cb.each = nullptr;
    cur->cb.end = nullptr;
    cur->cb.error = nullptr;
  }
}

static void *
reql_cur_loop(void *data) {
  ReQL_Cur_t *cur = reinterpret_cast<ReQL_Cur_t *>(data);
  reql_cur_lock(cur);
  while (cur->conn != nullptr) {
    if (cur->response == nullptr) {
      reql_cur_unlock(cur);
      sched_yield();
      reql_cur_lock(cur);
      continue;
    }
    void *res = cur->response; cur->response = nullptr;
    int r_type = cur->r_type;
    reql_cur_unlock(cur);
    auto close = false;
    switch (r_type) {
      case REQL_SUCCESS_ATOM:
      case REQL_SUCCESS_SEQUENCE:
      case REQL_WAIT_COMPLETE: {
        close = true;
        break;
      }
      case REQL_SUCCESS_PARTIAL: {
        reql_cur_lock(cur);
        if (cur->conn != nullptr) {
          reql_continue_query(cur);
        }
        reql_cur_unlock(cur);
        break;
      }
      case REQL_CLIENT_ERROR:
      case REQL_COMPILE_ERROR:
      case REQL_RUNTIME_ERROR:
      default: {
        reql_cur_lock(cur);
        if (cur->cb.error != nullptr) {
          cur->cb.error(cur->cb.data[ERROR], res);
        }
        reql_cur_unlock(cur);
        reql_cur_close(cur);
      }
    }
    reql_cur_lock(cur);
    while (cur->cb.each == nullptr) {
      reql_cur_unlock(cur);
      if (reql_cur_open(cur) == 0) {
        return nullptr;
      }
      sched_yield();
      reql_cur_lock(cur);
      continue;
    }
    if (cur->cb.each(cur->cb.data[EACH], res) != 0) {
      reql_cur_unlock(cur);
      reql_cur_close(cur);
      return nullptr;
    }
    reql_cur_unlock(cur);
    if (close) {
      reql_cur_close(cur);
    }
    reql_cur_lock(cur);
  }
  reql_cur_unlock(cur);
  return nullptr;
}

extern void
reql_cur_close(ReQL_Cur_t *cur) {
  reql_cur_lock(cur);
  if (cur->conn != nullptr) {
    reql_stop_query(cur);
  }
  reql_cur_close_(cur);
  reql_cur_unlock(cur);
}

extern char
reql_cur_open(ReQL_Cur_t *cur) {
  reql_cur_lock(cur);
  const char open = reql_cur_open_(cur);
  reql_cur_unlock(cur);
  return open;
}

extern void
reql_cur_init(ReQL_Cur_t *cur, ReQL_Conn_t *conn, ReQL_Token token, ReQL_Parse_t (*get_parser)()) {
  pthread_mutexattr_t *attrs;
  pthread_mutex_t *mutex;
  try {
    attrs = new pthread_mutexattr_t;
  } catch (std::bad_alloc&) {
    reql_cur_memory_error(__func__);
    return;
  }
  try {
    mutex = new pthread_mutex_t;
  } catch (std::bad_alloc&) {
    delete attrs;
    reql_cur_memory_error(__func__);
    return;
  }
  pthread_mutexattr_init(attrs);
  pthread_mutexattr_settype(attrs, PTHREAD_MUTEX_ERRORCHECK);
  pthread_mutex_init(mutex, attrs);
  pthread_mutexattr_destroy(attrs);
  delete attrs;

  memset(cur, static_cast<int>(NULL), sizeof(ReQL_Cur_t));

  cur->condition.mutex = mutex;

  reql_cur_lock(cur);
  cur->next = conn->cursors == nullptr ? cur : conn->cursors;
  cur->next->prev = cur;
  cur->prev = cur;
  cur->conn = conn;
  cur->token = token;
  cur->get_parser = get_parser;
  cur->cb.each = nullptr;
  cur->cb.end = nullptr;
  cur->cb.error = nullptr;
  cur->cb.data[EACH] = nullptr;
  cur->cb.data[END] = nullptr;
  cur->cb.data[ERROR] = nullptr;

  if (pthread_create(&cur->condition.thread, nullptr, reql_cur_loop, cur) != 0) {
    reql_cur_memory_error(__func__);
  }

  reql_cur_unlock(cur);
}

extern void
reql_cur_destroy(ReQL_Cur_t *cur) {
  if (cur == nullptr) {
    return;
  }
  reql_cur_lock(cur);
  reql_cur_close_(cur);
  cur->response = nullptr;
  if (cur->condition.thread != nullptr) {
    reql_cur_unlock(cur);
    pthread_join(cur->condition.thread, nullptr);
    cur->condition.thread = nullptr;
  } else {
    reql_cur_unlock(cur);
  }
}

class ReQL_Cur_Holder {
public:
  ReQL_Cur_Holder(void *a_data) : data(a_data) {}
  auto get() {
    return p_done.get_future().get();
  }
  void set(void *val) {
    return p_done.set_value(val);
  }
  void wait() {
    return p_done.get_future().wait();
  }

  void *data;

private:
  std::promise<void *> p_done;
};

class ReQL_Cur_Next_Data_Holder: public ReQL_Cur_Holder {
public:
  ReQL_Cur_Next_Data_Holder(void *a_data) : ReQL_Cur_Holder(a_data) {}
};

static int
reql_cur_next_cb(void *arg, void *a_res) {
  auto p_data = reinterpret_cast<ReQL_Cur_Next_Data_Holder *>(arg);
  auto cur = reinterpret_cast<ReQL_Cur_t*>(p_data->data);
  cur->cb.each = nullptr;
  p_data->set(a_res);
  return 0;
}

static void
reql_cur_each_(ReQL_Cur_t *cur, ReQL_Each_Function cb, void *arg) {
  cur->cb.each = cb;
  cur->cb.data[EACH] = arg;
}

static void *
reql_cur_next_(ReQL_Cur_t *cur) {
  if (reql_cur_open_(cur) == 0) {
    return nullptr;
  }
  auto each = std::move(cur->cb.each);
  auto cb_data = std::move(cur->cb.data[EACH]);
  ReQL_Cur_Next_Data_Holder data(cur);
  reql_cur_each_(cur, reql_cur_next_cb, &data);
  data.wait();
  std::swap(cur->cb.each, each);
  std::swap(cur->cb.data[EACH], cb_data);
  return data.get();
}

extern void *
reql_cur_next(ReQL_Cur_t *cur) {
  reql_cur_lock(cur);
  void *res = reql_cur_next_(cur);
  reql_cur_unlock(cur);
  return res;
}

extern void
reql_cur_each(ReQL_Cur_t *cur, ReQL_Each_Function cb, void *arg) {
  reql_cur_lock(cur);
  reql_cur_each_(cur, cb, arg);
  reql_cur_unlock(cur);
}

static int
reql_cur_drain_blank_cb(void *, void *) {
  return 0;
}

class ReQL_Cur_Drain_Data_Holder: public ReQL_Cur_Holder {
public:
  ReQL_Cur_Drain_Data_Holder(void *data, ReQL_End_Function end) : ReQL_Cur_Holder(data), p_end(end) {}
  auto end() {
    return p_end;
  }
private:
  ReQL_End_Function p_end;
};

static void
reql_cur_drain_end_cb(void *arg) {
  auto p_data = reinterpret_cast<ReQL_Cur_Drain_Data_Holder *>(arg);
  auto end = p_data->end();
  if (end != nullptr) {
    end(p_data->data);
  }
  p_data->set(nullptr);
}

static void
reql_cur_drain_(ReQL_Cur_t *cur) {
  if (cur->cb.each == nullptr) {
    reql_cur_each_(cur, reql_cur_drain_blank_cb, nullptr);
  }
  ReQL_Cur_Drain_Data_Holder data(cur->cb.data[END], cur->cb.end);
  reql_cur_set_end_cb_(cur, reql_cur_drain_end_cb, &data);
  data.wait();
  cur->cb.end = nullptr;
}

extern void
reql_cur_drain(ReQL_Cur_t *cur) {
  reql_cur_lock(cur);
  reql_cur_drain_(cur);
  reql_cur_unlock(cur);
}
<commit_msg>Function doesn't need declaration here.<commit_after>/*
Copyright 2015 Adam Grandquist

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */
/**
 * @author Adam Grandquist
 * @copyright Apache
 */

#include "./reql/cursor.h"

#include "./reql/decode.hpp"

#include "./reql/connection.h"
#include "./reql/error.h"
#include "./reql/query.h"

#include <memory>
#include <future>

#include <pthread.h>

enum {
  EACH,
  END,
  ERROR
};

static void
reql_cur_error(const char *msg, const char *trace) {
  reql_error_init(REQL_E_CURSOR, msg, trace);
}

static void
reql_cur_memory_error(const char *trace) {
  reql_cur_error("Insufficient memory", trace);
}

static void
reql_cur_lock(ReQL_Cur_t *cur) {
  pthread_mutex_lock(cur->condition.mutex);
}

static void
reql_cur_unlock(ReQL_Cur_t *cur) {
  if (cur == nullptr) {
    return;
  }
  pthread_mutex_unlock(cur->condition.mutex);
}

static char
reql_cur_open_(ReQL_Cur_t *cur) {
  return cur->conn != nullptr;
}

static void
reql_cur_set_end_cb_(ReQL_Cur_t *cur, ReQL_End_Function cb, void *arg) {
  cur->cb.end = cb;
  cur->cb.data[END] = arg;
}

static void
reql_cur_set_error_cb_(ReQL_Cur_t *cur, ReQL_Error_Function cb, void *arg) {
  cur->cb.error = cb;
  cur->cb.data[ERROR] = arg;
}

extern void
reql_cur_set_end_cb(ReQL_Cur_t *cur, ReQL_End_Function cb, void *arg) {
  reql_cur_lock(cur);
  reql_cur_set_end_cb_(cur, cb, arg);
  reql_cur_unlock(cur);
}

extern void
reql_cur_set_error_cb(ReQL_Cur_t *cur, ReQL_Error_Function cb, void *arg) {
  reql_cur_lock(cur);
  reql_cur_set_error_cb_(cur, cb, arg);
  reql_cur_unlock(cur);
}

extern void
reql_cur_set_response(ReQL_Cur_t *cur, const ReQL_Byte *res, ReQL_Size length) {
  reql_cur_lock(cur);
  ReQL_Parse_t u_parser = cur->get_parser();
  reql_decode(std::basic_string<ReQL_Byte>(res, length), Parser<std::basic_string<ReQL_Byte>>(&u_parser, cur));
  reql_cur_unlock(cur);
}

static void
reql_cur_close_(ReQL_Cur_t *cur) {
  if (reql_cur_open_(cur) != 0) {
    ReQL_Cur_t *prev = cur->prev == cur ? nullptr : cur->prev;
    ReQL_Cur_t *next = cur->next == cur ? nullptr : cur->next;
    if (next == nullptr && prev == nullptr) {
    } else if (prev == nullptr) {
      next->prev = next;
    } else if (next == nullptr) {
      prev->next = prev;
    } else {
      next->prev = prev;
      prev->next = next;
    }
    cur->conn->cursors = next;
    cur->conn = nullptr;
    if (cur->cb.each != nullptr) {
      cur->cb.each(nullptr, cur->cb.data[EACH]);
    }
    if (cur->cb.end != nullptr) {
      cur->cb.end(cur->cb.data[END]);
    }
    cur->cb.data[EACH] = nullptr;
    cur->cb.data[END] = nullptr;
    cur->cb.data[ERROR] = nullptr;
    cur->cb.each = nullptr;
    cur->cb.end = nullptr;
    cur->cb.error = nullptr;
  }
}

static void *
reql_cur_loop(void *data) {
  ReQL_Cur_t *cur = reinterpret_cast<ReQL_Cur_t *>(data);
  reql_cur_lock(cur);
  while (cur->conn != nullptr) {
    if (cur->response == nullptr) {
      reql_cur_unlock(cur);
      sched_yield();
      reql_cur_lock(cur);
      continue;
    }
    void *res = cur->response; cur->response = nullptr;
    int r_type = cur->r_type;
    reql_cur_unlock(cur);
    auto close = false;
    switch (r_type) {
      case REQL_SUCCESS_ATOM:
      case REQL_SUCCESS_SEQUENCE:
      case REQL_WAIT_COMPLETE: {
        close = true;
        break;
      }
      case REQL_SUCCESS_PARTIAL: {
        reql_cur_lock(cur);
        if (cur->conn != nullptr) {
          reql_continue_query(cur);
        }
        reql_cur_unlock(cur);
        break;
      }
      case REQL_CLIENT_ERROR:
      case REQL_COMPILE_ERROR:
      case REQL_RUNTIME_ERROR:
      default: {
        reql_cur_lock(cur);
        if (cur->cb.error != nullptr) {
          cur->cb.error(cur->cb.data[ERROR], res);
        }
        reql_cur_unlock(cur);
        reql_cur_close(cur);
      }
    }
    reql_cur_lock(cur);
    while (cur->cb.each == nullptr) {
      reql_cur_unlock(cur);
      if (reql_cur_open(cur) == 0) {
        return nullptr;
      }
      sched_yield();
      reql_cur_lock(cur);
      continue;
    }
    if (cur->cb.each(cur->cb.data[EACH], res) != 0) {
      reql_cur_unlock(cur);
      reql_cur_close(cur);
      return nullptr;
    }
    reql_cur_unlock(cur);
    if (close) {
      reql_cur_close(cur);
    }
    reql_cur_lock(cur);
  }
  reql_cur_unlock(cur);
  return nullptr;
}

extern void
reql_cur_close(ReQL_Cur_t *cur) {
  reql_cur_lock(cur);
  if (cur->conn != nullptr) {
    reql_stop_query(cur);
  }
  reql_cur_close_(cur);
  reql_cur_unlock(cur);
}

extern char
reql_cur_open(ReQL_Cur_t *cur) {
  reql_cur_lock(cur);
  const char open = reql_cur_open_(cur);
  reql_cur_unlock(cur);
  return open;
}

extern void
reql_cur_init(ReQL_Cur_t *cur, ReQL_Conn_t *conn, ReQL_Token token, ReQL_Parse_t (*get_parser)()) {
  pthread_mutexattr_t *attrs;
  pthread_mutex_t *mutex;
  try {
    attrs = new pthread_mutexattr_t;
  } catch (std::bad_alloc&) {
    reql_cur_memory_error(__func__);
    return;
  }
  try {
    mutex = new pthread_mutex_t;
  } catch (std::bad_alloc&) {
    delete attrs;
    reql_cur_memory_error(__func__);
    return;
  }
  pthread_mutexattr_init(attrs);
  pthread_mutexattr_settype(attrs, PTHREAD_MUTEX_ERRORCHECK);
  pthread_mutex_init(mutex, attrs);
  pthread_mutexattr_destroy(attrs);
  delete attrs;

  memset(cur, static_cast<int>(NULL), sizeof(ReQL_Cur_t));

  cur->condition.mutex = mutex;

  reql_cur_lock(cur);
  cur->next = conn->cursors == nullptr ? cur : conn->cursors;
  cur->next->prev = cur;
  cur->prev = cur;
  cur->conn = conn;
  cur->token = token;
  cur->get_parser = get_parser;
  cur->cb.each = nullptr;
  cur->cb.end = nullptr;
  cur->cb.error = nullptr;
  cur->cb.data[EACH] = nullptr;
  cur->cb.data[END] = nullptr;
  cur->cb.data[ERROR] = nullptr;

  if (pthread_create(&cur->condition.thread, nullptr, reql_cur_loop, cur) != 0) {
    reql_cur_memory_error(__func__);
  }

  reql_cur_unlock(cur);
}

extern void
reql_cur_destroy(ReQL_Cur_t *cur) {
  if (cur == nullptr) {
    return;
  }
  reql_cur_lock(cur);
  reql_cur_close_(cur);
  cur->response = nullptr;
  if (cur->condition.thread != nullptr) {
    reql_cur_unlock(cur);
    pthread_join(cur->condition.thread, nullptr);
    cur->condition.thread = nullptr;
  } else {
    reql_cur_unlock(cur);
  }
}

class ReQL_Cur_Holder {
public:
  ReQL_Cur_Holder(void *a_data) : data(a_data) {}
  auto get() {
    return p_done.get_future().get();
  }
  void set(void *val) {
    return p_done.set_value(val);
  }
  void wait() {
    return p_done.get_future().wait();
  }

  void *data;

private:
  std::promise<void *> p_done;
};

class ReQL_Cur_Next_Data_Holder: public ReQL_Cur_Holder {
public:
  ReQL_Cur_Next_Data_Holder(void *a_data) : ReQL_Cur_Holder(a_data) {}
};

static int
reql_cur_next_cb(void *arg, void *a_res) {
  auto p_data = reinterpret_cast<ReQL_Cur_Next_Data_Holder *>(arg);
  auto cur = reinterpret_cast<ReQL_Cur_t*>(p_data->data);
  cur->cb.each = nullptr;
  p_data->set(a_res);
  return 0;
}

static void
reql_cur_each_(ReQL_Cur_t *cur, ReQL_Each_Function cb, void *arg) {
  cur->cb.each = cb;
  cur->cb.data[EACH] = arg;
}

static void *
reql_cur_next_(ReQL_Cur_t *cur) {
  if (reql_cur_open_(cur) == 0) {
    return nullptr;
  }
  auto each = std::move(cur->cb.each);
  auto cb_data = std::move(cur->cb.data[EACH]);
  ReQL_Cur_Next_Data_Holder data(cur);
  reql_cur_each_(cur, reql_cur_next_cb, &data);
  data.wait();
  std::swap(cur->cb.each, each);
  std::swap(cur->cb.data[EACH], cb_data);
  return data.get();
}

extern void *
reql_cur_next(ReQL_Cur_t *cur) {
  reql_cur_lock(cur);
  void *res = reql_cur_next_(cur);
  reql_cur_unlock(cur);
  return res;
}

extern void
reql_cur_each(ReQL_Cur_t *cur, ReQL_Each_Function cb, void *arg) {
  reql_cur_lock(cur);
  reql_cur_each_(cur, cb, arg);
  reql_cur_unlock(cur);
}

static int
reql_cur_drain_blank_cb(void *, void *) {
  return 0;
}

class ReQL_Cur_Drain_Data_Holder: public ReQL_Cur_Holder {
public:
  ReQL_Cur_Drain_Data_Holder(void *data, ReQL_End_Function end) : ReQL_Cur_Holder(data), p_end(end) {}
  auto end() {
    return p_end;
  }
private:
  ReQL_End_Function p_end;
};

static void
reql_cur_drain_end_cb(void *arg) {
  auto p_data = reinterpret_cast<ReQL_Cur_Drain_Data_Holder *>(arg);
  auto end = p_data->end();
  if (end != nullptr) {
    end(p_data->data);
  }
  p_data->set(nullptr);
}

static void
reql_cur_drain_(ReQL_Cur_t *cur) {
  if (cur->cb.each == nullptr) {
    reql_cur_each_(cur, reql_cur_drain_blank_cb, nullptr);
  }
  ReQL_Cur_Drain_Data_Holder data(cur->cb.data[END], cur->cb.end);
  reql_cur_set_end_cb_(cur, reql_cur_drain_end_cb, &data);
  data.wait();
  cur->cb.end = nullptr;
}

extern void
reql_cur_drain(ReQL_Cur_t *cur) {
  reql_cur_lock(cur);
  reql_cur_drain_(cur);
  reql_cur_unlock(cur);
}
<|endoftext|>


<commit_before>/*
 * tools
 *
 * Copyright (c) 2014-2015 FOXEL SA - http://foxel.ch
 * Please read <http://foxel.ch/license> for more information.
 *
 *
 * Author(s):
 *
 *      Stéphane Flotron <s.flotron@foxel.ch>
 *
 *
 * This file is part of the FOXEL project <http://foxel.ch>.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Additional Terms:
 *
 *      You are required to preserve legal notices and author attributions in
 *      that material or in the Appropriate Legal Notices displayed by works
 *      containing it.
 *
 *      You are required to attribute the work as explained in the "Usage and
 *      Attribution" section of <http://foxel.ch/license>.
 */

#ifndef TOOLS_HPP_
#define TOOLS_HPP_

#include <fastcal-all.h>
#include <vector>
#include <string.h>
#include <types.hpp>

using namespace std;

/*******************************************************************************
* Split an input string with a delimiter and fill a string vector
*
********************************************************************************
*/

bool split ( const std::string src, const std::string& delim, std::vector<std::string>& vec_value );

/*******************************************************************************
*  Given 4 angles, compute Elphel rotation
*
********************************************************************************
*/
 void computeRotationEl ( li_Real_t* R , li_Real_t az , li_Real_t head, li_Real_t ele , li_Real_t roll);

/********************************************************************************
*  Given three angles, entrance pupil forward, radius and height, compute optical center position.
*
*********************************************************************************
*/

 void getOpticalCenter ( li_Real_t* C ,
                const li_Real_t& radius,
                const li_Real_t& height,
                const li_Real_t& azimuth,
                const li_Real_t* R,
                const li_Real_t& entrancePupilForward );

#endif /* TOOLS_HPP_ */
<commit_msg>documented file tools.hpp<commit_after>/*
 * tools
 *
 * Copyright (c) 2014-2015 FOXEL SA - http://foxel.ch
 * Please read <http://foxel.ch/license> for more information.
 *
 *
 * Author(s):
 *
 *      Stéphane Flotron <s.flotron@foxel.ch>
 *
 *
 * This file is part of the FOXEL project <http://foxel.ch>.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Additional Terms:
 *
 *      You are required to preserve legal notices and author attributions in
 *      that material or in the Appropriate Legal Notices displayed by works
 *      containing it.
 *
 *      You are required to attribute the work as explained in the "Usage and
 *      Attribution" section of <http://foxel.ch/license>.
 */

 /*! \file tools.hpp
 * \author Stephane Flotron <s.flotron@foxel.ch>
 */
 /*! \mainpage listomvg
 * \section listomvg
 *
 * For Elphel's camera, generate file lists.txt needed by openMVG, for rigid rig and standard openMVG.
 *
 * \section Documentation
 *
 * Documentation can be consulted on the [wiki](https://github.com/FoxelSA/listomvg/wiki).
 *
 * \section Copyright
 *
 * Copyright (c) 2014-2015 FOXEL SA - [http://foxel.ch](http://foxel.ch)<br />
 * This program is part of the FOXEL project <[http://foxel.ch](http://foxel.ch)>.
 *
 * Please read the [COPYRIGHT.md](COPYRIGHT.md) file for more information.
 *
 * \section License
 *
 * This program is licensed under the terms of the
 * [GNU Affero General Public License v3](http://www.gnu.org/licenses/agpl.html)
 * (GNU AGPL), with two additional terms. The content is licensed under the terms
 * of the [Creative Commons Attribution-ShareAlike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/)
 * (CC BY-SA) license.
 *
 * You must read <[http://foxel.ch/license](http://foxel.ch/license)> for more
 *information about our Licensing terms and our Usage and Attribution guidelines.
 *
 */

#ifndef TOOLS_HPP_
#define TOOLS_HPP_

#include <fastcal-all.h>
#include <vector>
#include <string.h>
#include <types.hpp>

using namespace std;

/*******************************************************************************
* Split an input string with a delimiter and fill a string vector
*
********************************************************************************
*/

/*! \brief Split a string using a delimiter
*
* This function split a string into substring using a delimiter and fill a string
* vector
*
* \param src         Input string
* \param delim       Delimiter
* \param vec_value   vector containing the sub string
*
* \return bool value that says if the splitting was sucessfull or not
*/

bool split ( const std::string src, const std::string& delim, std::vector<std::string>& vec_value );

/*******************************************************************************
*  Given 4 angles, compute Elphel rotation
*
********************************************************************************
*/

/*! \brief Compute rotation rig referential to sensor referential
*
* This function compute the rotation rig referential to sensor referential using
* elphel calibration angle and rotation.
*
* \param R           Computed rotation
* \param az          Elphel's Angle azimuth (in radian) of subcamera
* \param head        Elphel's Angle heading (in radian) of subcamera
* \param ele         Elphel's Angle elevation (in radian) of subcamera
* \param roll        Elphel's Angle roll (in radian) of subcamera
*
* \return The rotation in the array R
*/

 void computeRotationEl ( li_Real_t* R , li_Real_t az , li_Real_t head, li_Real_t ele , li_Real_t roll);

/********************************************************************************
*  Given three angles, entrance pupil forward, radius and height, compute optical center position.
*
*********************************************************************************
*/

/*! \brief Compute optical center of elphel's subcamera
*
* This function compute the optical center of a given elphel subcamera
*
* \param C           Computed optical center
* \param radius      Radius of optical center in elphel's coordinate frame
* \param heigt       Height of optical center in elphel's coordinate frame
* \param azimuth     Elphel's Angle azimuth (in radian) of subcamera
* \param R           Rotation rig referential frame to sensor frame
* \param entrancePupilForward  Entrance pupil forward of the associated camera
*
* \return The optical center in the array C
*/

 void getOpticalCenter ( li_Real_t* C ,
                const li_Real_t& radius,
                const li_Real_t& height,
                const li_Real_t& azimuth,
                const li_Real_t* R,
                const li_Real_t& entrancePupilForward );

#endif /* TOOLS_HPP_ */
<|endoftext|>


<commit_before>/**
 * @brief plan node utilities.
 *
 * Copyright(c) 2015, CMU
 *
 */

#include <sstream>

#include "planner/plan_node_util.h"
#include "common/types.h"
#include "common/exception.h"
#include "common/logger.h"
#include "planner/nodes.h"

namespace nstore {
namespace planner {

AbstractPlanNode* GetEmptyPlanNode(PlanNodeType type) {

  LOG4CXX_TRACE(logger, "Creating an empty PlanNode of type : " << PlanNodeToString(type));
  AbstractPlanNode* ret = NULL;

  switch (type) {
    /*
    case (PLAN_NODE_TYPE_SEQSCAN):
        ret = new SeqScanPlanNode();
    break;
    case (PLAN_NODE_TYPE_INDEXSCAN):
        ret = new IndexScanPlanNode();
    break;
    case (PLAN_NODE_TYPE_NESTLOOP):
        ret = new NestLoopPlanNode();
    break;
    case (PLAN_NODE_TYPE_NESTLOOPINDEX):
        ret = new NestLoopIndexPlanNode();
    break;
    case (PLAN_NODE_TYPE_UPDATE):
        ret = new UpdatePlanNode();
    break;
    case (PLAN_NODE_TYPE_INSERT):
        ret = new InsertPlanNode();
    break;
    case (PLAN_NODE_TYPE_DELETE):
        ret = new DeletePlanNode();
    break;
    case (PLAN_NODE_TYPE_HASHAGGREGATE):
    case (PLAN_NODE_TYPE_AGGREGATE):
    ret = new AggregatePlanNode(type);
    break;
    case (PLAN_NODE_TYPE_UNION):
        ret = new UnionPlanNode();
    break;
    case (PLAN_NODE_TYPE_ORDERBY):
        ret = new OrderByPlanNode();
    break;
    case (PLAN_NODE_TYPE_PROJECTION):
        ret = new ProjectionPlanNode();
    break;
    case (PLAN_NODE_TYPE_MATERIALIZE):
        ret = new MaterializePlanNode();
    break;
    case (PLAN_NODE_TYPE_SEND):
        ret = new SendPlanNode();
    break;
    case (PLAN_NODE_TYPE_LIMIT):
        ret = new LimitPlanNode();
    break;
    case (PLAN_NODE_TYPE_DISTINCT):
        ret = new DistinctPlanNode();
    break;
    case (PLAN_NODE_TYPE_RECEIVE):
        ret = new ReceivePlanNode();
    break;
     */

    default: {
      throw PlannerException("Invalid PlanNode type : " + PlanNodeToString(type));
    }
  }
  LOG4CXX_TRACE(logger, "created plannode : " << typeid(*ret).name());

  return (ret);
}

} // namespace planner
} // namespace nstore

<commit_msg>Commented out logging in plan node util.<commit_after>/**
 * @brief plan node utilities.
 *
 * Copyright(c) 2015, CMU
 *
 */

#include <sstream>

#include "planner/plan_node_util.h"
#include "common/types.h"
#include "common/exception.h"
#include "common/logger.h"
#include "planner/nodes.h"

namespace nstore {
namespace planner {

AbstractPlanNode* GetEmptyPlanNode(PlanNodeType type) {

  //TODO Uncomment after fixing compilation error.
  //LOG4CXX_TRACE(logger, "Creating an empty PlanNode of type : " << PlanNodeToString(type));
  AbstractPlanNode* ret = NULL;

  switch (type) {
    /*
    case (PLAN_NODE_TYPE_SEQSCAN):
        ret = new SeqScanPlanNode();
    break;
    case (PLAN_NODE_TYPE_INDEXSCAN):
        ret = new IndexScanPlanNode();
    break;
    case (PLAN_NODE_TYPE_NESTLOOP):
        ret = new NestLoopPlanNode();
    break;
    case (PLAN_NODE_TYPE_NESTLOOPINDEX):
        ret = new NestLoopIndexPlanNode();
    break;
    case (PLAN_NODE_TYPE_UPDATE):
        ret = new UpdatePlanNode();
    break;
    case (PLAN_NODE_TYPE_INSERT):
        ret = new InsertPlanNode();
    break;
    case (PLAN_NODE_TYPE_DELETE):
        ret = new DeletePlanNode();
    break;
    case (PLAN_NODE_TYPE_HASHAGGREGATE):
    case (PLAN_NODE_TYPE_AGGREGATE):
    ret = new AggregatePlanNode(type);
    break;
    case (PLAN_NODE_TYPE_UNION):
        ret = new UnionPlanNode();
    break;
    case (PLAN_NODE_TYPE_ORDERBY):
        ret = new OrderByPlanNode();
    break;
    case (PLAN_NODE_TYPE_PROJECTION):
        ret = new ProjectionPlanNode();
    break;
    case (PLAN_NODE_TYPE_MATERIALIZE):
        ret = new MaterializePlanNode();
    break;
    case (PLAN_NODE_TYPE_SEND):
        ret = new SendPlanNode();
    break;
    case (PLAN_NODE_TYPE_LIMIT):
        ret = new LimitPlanNode();
    break;
    case (PLAN_NODE_TYPE_DISTINCT):
        ret = new DistinctPlanNode();
    break;
    case (PLAN_NODE_TYPE_RECEIVE):
        ret = new ReceivePlanNode();
    break;
     */

    default: {
      throw PlannerException("Invalid PlanNode type : " + PlanNodeToString(type));
    }
  }
  //TODO Uncomment after fixing compilation error.
  //LOG4CXX_TRACE(logger, "created plannode : " << typeid(*ret).name());

  return (ret);
}

} // namespace planner
} // namespace nstore

<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This application is open source and may be redistributed and/or modified
 * freely and without restriction, both in commericial and non commericial applications,
 * as long as this copyright notice is maintained.
 *
 * This application 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.
*/

#include <osgDB/ReadFile>
#include <osgUtil/Optimizer>
#include <osgProducer/Viewer>

int main( int argc, char **argv )
{

    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    // set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models.");
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");

    // construct the viewer.
    osgProducer::Viewer viewer(arguments);

    // set up the value with sensible default event handlers.
    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);

    // get details on keyboard and mouse bindings used by the viewer.
    viewer.getUsage(*arguments.getApplicationUsage());

    // if user request help write it out to cout.
    if (arguments.read("-h") || arguments.read("--help"))
    {
        arguments.getApplicationUsage()->write(std::cout);
        return 1;
    }

    // any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized();

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
        return 1;
    }

    if (arguments.argc()<=1)
    {
        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
        return 1;
    }

    osg::Timer timer;
    osg::Timer_t start_tick = timer.tick();

    // read the scene from the list of file specified commandline args.
    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);

    // if no model has been successfully loaded report failure.
    if (!loadedModel)
    {
        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
        return 1;
    }

    osg::Timer_t end_tick = timer.tick();

    std::cout << "Time to load = "<<timer.delta_s(start_tick,end_tick)<<std::endl;

    // optimize the scene graph, remove rendundent nodes and state etc.
    osgUtil::Optimizer optimizer;
    optimizer.optimize(loadedModel.get());

    // set the scene to render
    viewer.setSceneData(loadedModel.get());

    // create the windows and run the threads.
    viewer.realize();

    while( !viewer.done() )
    {
        // wait for all cull and draw threads to complete.
        viewer.sync();

        // update the scene by traversing it with the the update visitor which will
        // call all node update callbacks and animations.
        viewer.update();

        // fire off the cull and draw traversals of the scene.
        viewer.frame();

    }

    // wait for all cull and draw threads to complete before exit.
    viewer.sync();

    return 0;
}

<commit_msg>Moved the unrecognized options check to after loaded<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This application is open source and may be redistributed and/or modified
 * freely and without restriction, both in commericial and non commericial applications,
 * as long as this copyright notice is maintained.
 *
 * This application 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.
*/

#include <osgDB/ReadFile>
#include <osgUtil/Optimizer>
#include <osgProducer/Viewer>

int main( int argc, char **argv )
{

    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    // set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models.");
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");

    // construct the viewer.
    osgProducer::Viewer viewer(arguments);

    // set up the value with sensible default event handlers.
    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);

    // get details on keyboard and mouse bindings used by the viewer.
    viewer.getUsage(*arguments.getApplicationUsage());

    // if user request help write it out to cout.
    if (arguments.read("-h") || arguments.read("--help"))
    {
        arguments.getApplicationUsage()->write(std::cout);
        return 1;
    }

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
        return 1;
    }

    if (arguments.argc()<=1)
    {
        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
        return 1;
    }

    osg::Timer timer;
    osg::Timer_t start_tick = timer.tick();

    // read the scene from the list of file specified commandline args.
    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);

    // if no model has been successfully loaded report failure.
    if (!loadedModel)
    {
        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
        return 1;
    }

    // any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized();

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
    }

    osg::Timer_t end_tick = timer.tick();

    std::cout << "Time to load = "<<timer.delta_s(start_tick,end_tick)<<std::endl;

    // optimize the scene graph, remove rendundent nodes and state etc.
    osgUtil::Optimizer optimizer;
    optimizer.optimize(loadedModel.get());

    // set the scene to render
    viewer.setSceneData(loadedModel.get());

    // create the windows and run the threads.
    viewer.realize();

    while( !viewer.done() )
    {
        // wait for all cull and draw threads to complete.
        viewer.sync();

        // update the scene by traversing it with the the update visitor which will
        // call all node update callbacks and animations.
        viewer.update();

        // fire off the cull and draw traversals of the scene.
        viewer.frame();

    }

    // wait for all cull and draw threads to complete before exit.
    viewer.sync();

    return 0;
}

<|endoftext|>


<commit_before>#include "ui.h"

#include <memory>
#include <vector>

#include <glibmm/main.h>
#include <gtkmm/main.h>
#include <gtkmm/scrolledwindow.h>
#include <gtkmm/textbuffer.h>
#include <gtkmm/textview.h>
#include <gtkmm/widget.h>

#include "debug.h"
#include "utils.h"

using namespace std;
using namespace Gtk;
using namespace Glib;

// TODO: eliminate all the global objects, as their initialization is not well defined
static TextView *lyricView;
static ScrolledWindow *lyricbar;
static RefPtr<TextBuffer> refBuffer;
static RefPtr<TextTag> tagItalic, tagBold, tagLarge, tagCenter;
static vector<RefPtr<TextTag>> tagsTitle, tagsArtist;

void set_lyrics(DB_playItem_t *track, ustring lyrics) {
    signal_idle().connect_once([track, lyrics = move(lyrics)]() -> void {
        ustring artist, title;
        {
            pl_lock_guard guard;

            if (!is_playing(track))
                return;
            artist = deadbeef->pl_find_meta(track, "artist");
            title  = deadbeef->pl_find_meta(track, "title");
        }
        refBuffer->erase(refBuffer->begin(), refBuffer->end());
        refBuffer->insert_with_tags(refBuffer->begin(), title, tagsTitle);
        refBuffer->insert_with_tags(refBuffer->end(), ustring("\n") + artist + "\n\n", tagsArtist);

        bool italic = false;
        bool bold = false;
        size_t prev_mark = 0;
        vector<RefPtr<TextTag>> tags;
        while (prev_mark != ustring::npos) {
            size_t italic_mark = lyrics.find("''", prev_mark);
            if (italic_mark == ustring::npos)
                break;
            size_t bold_mark = ustring::npos;
            if (italic_mark < lyrics.size() - 2 && lyrics[italic_mark + 2] == '\'')
                bold_mark = italic_mark;

            tags.clear();
            if (italic) tags.push_back(tagItalic);
            if (bold)   tags.push_back(tagBold);
            refBuffer->insert_with_tags(refBuffer->end(),
                    lyrics.substr(prev_mark, min(bold_mark, italic_mark) - prev_mark), tags);

            if (bold_mark == ustring::npos) {
                prev_mark = italic_mark + 2;
                italic = !italic;
            } else {
                prev_mark = bold_mark + 3;
                bold = !bold;
            }
        }
        refBuffer->insert(refBuffer->end(), lyrics.substr(prev_mark)); // in case if no formatting found
        last = track;
    });
}

Justification get_justification() {
    int align = deadbeef->conf_get_int("lyricbar.lyrics.alignment", 0);
    switch (align) {
        case 0:
            return JUSTIFY_LEFT;
        case 2:
            return JUSTIFY_RIGHT;
        default:
            return JUSTIFY_CENTER;
    }
}

extern "C"
GtkWidget *construct_lyricbar() {
    Gtk::Main::init_gtkmm_internals();
    refBuffer = TextBuffer::create();

    tagItalic = refBuffer->create_tag();
    tagItalic->property_style() = Pango::STYLE_ITALIC;

    tagBold = refBuffer->create_tag();
    tagBold->property_weight() = Pango::WEIGHT_BOLD;

    tagLarge = refBuffer->create_tag();
    tagLarge->property_scale() = Pango::SCALE_LARGE;

    tagCenter = refBuffer->create_tag();
    tagCenter->property_justification() = JUSTIFY_CENTER;

    tagsTitle = {tagLarge, tagBold, tagCenter};
    tagsArtist = {tagItalic, tagCenter};

    lyricView = new TextView(refBuffer);
    lyricView->set_editable(false);
    lyricView->set_can_focus(false);
    lyricView->set_justification(get_justification());
    lyricView->set_wrap_mode(WRAP_WORD_CHAR);
    lyricView->show();

    lyricbar = new ScrolledWindow();
    lyricbar->add(*lyricView);
    lyricbar->set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC);

    return GTK_WIDGET(lyricbar->gobj());
}

extern "C"
int message_handler(struct ddb_gtkui_widget_s*, uint32_t id, uintptr_t ctx, uint32_t, uint32_t) {
    auto event = reinterpret_cast<ddb_event_track_t *>(ctx);
    switch (id) {
        case DB_EV_CONFIGCHANGED:
            debug_out << "CONFIG CHANGED\n";
            signal_idle().connect_once([](){ lyricView->set_justification(get_justification()); });
            break;
        case DB_EV_SONGSTARTED:
            debug_out << "SONG STARTED\n";
        case DB_EV_TRACKINFOCHANGED:
            if (!event->track || deadbeef->pl_get_item_duration(event->track) <= 0)
                return 0;
            auto tid = deadbeef->thread_start(update_lyrics, event->track);
            deadbeef->thread_detach(tid);
            break;
    }

    return 0;
}

extern "C"
void lyricbar_destroy() {
    delete lyricbar;
    delete lyricView;
    tagsArtist.clear();
    tagsTitle.clear();
    tagLarge.reset();
    tagBold.reset();
    tagItalic.reset();
    refBuffer.reset();
}

<commit_msg>Add another null-check to fix #3<commit_after>#include "ui.h"

#include <memory>
#include <vector>

#include <glibmm/main.h>
#include <gtkmm/main.h>
#include <gtkmm/scrolledwindow.h>
#include <gtkmm/textbuffer.h>
#include <gtkmm/textview.h>
#include <gtkmm/widget.h>

#include "debug.h"
#include "gettext.h"
#include "utils.h"

using namespace std;
using namespace Gtk;
using namespace Glib;

// TODO: eliminate all the global objects, as their initialization is not well defined
static TextView *lyricView;
static ScrolledWindow *lyricbar;
static RefPtr<TextBuffer> refBuffer;
static RefPtr<TextTag> tagItalic, tagBold, tagLarge, tagCenter;
static vector<RefPtr<TextTag>> tagsTitle, tagsArtist;

void set_lyrics(DB_playItem_t *track, ustring lyrics) {
    signal_idle().connect_once([track, lyrics = move(lyrics)]() -> void {
        const char *artist, *title;
        {
            pl_lock_guard guard;

            if (!is_playing(track))
                return;
            artist = deadbeef->pl_find_meta(track, "artist");
            title  = deadbeef->pl_find_meta(track, "title");
        }
	if (!artist)
	    artist = _("Unknown Artist");
	if (!title)
	    title = _("Unknown Title");
        refBuffer->erase(refBuffer->begin(), refBuffer->end());
        refBuffer->insert_with_tags(refBuffer->begin(), title, tagsTitle);
        refBuffer->insert_with_tags(refBuffer->end(), ustring("\n") + artist + "\n\n", tagsArtist);

        bool italic = false;
        bool bold = false;
        size_t prev_mark = 0;
        vector<RefPtr<TextTag>> tags;
        while (prev_mark != ustring::npos) {
            size_t italic_mark = lyrics.find("''", prev_mark);
            if (italic_mark == ustring::npos)
                break;
            size_t bold_mark = ustring::npos;
            if (italic_mark < lyrics.size() - 2 && lyrics[italic_mark + 2] == '\'')
                bold_mark = italic_mark;

            tags.clear();
            if (italic) tags.push_back(tagItalic);
            if (bold)   tags.push_back(tagBold);
            refBuffer->insert_with_tags(refBuffer->end(),
                    lyrics.substr(prev_mark, min(bold_mark, italic_mark) - prev_mark), tags);

            if (bold_mark == ustring::npos) {
                prev_mark = italic_mark + 2;
                italic = !italic;
            } else {
                prev_mark = bold_mark + 3;
                bold = !bold;
            }
        }
        refBuffer->insert(refBuffer->end(), lyrics.substr(prev_mark)); // in case if no formatting found
        last = track;
    });
}

Justification get_justification() {
    int align = deadbeef->conf_get_int("lyricbar.lyrics.alignment", 0);
    switch (align) {
        case 0:
            return JUSTIFY_LEFT;
        case 2:
            return JUSTIFY_RIGHT;
        default:
            return JUSTIFY_CENTER;
    }
}

extern "C"
GtkWidget *construct_lyricbar() {
    Gtk::Main::init_gtkmm_internals();
    refBuffer = TextBuffer::create();

    tagItalic = refBuffer->create_tag();
    tagItalic->property_style() = Pango::STYLE_ITALIC;

    tagBold = refBuffer->create_tag();
    tagBold->property_weight() = Pango::WEIGHT_BOLD;

    tagLarge = refBuffer->create_tag();
    tagLarge->property_scale() = Pango::SCALE_LARGE;

    tagCenter = refBuffer->create_tag();
    tagCenter->property_justification() = JUSTIFY_CENTER;

    tagsTitle = {tagLarge, tagBold, tagCenter};
    tagsArtist = {tagItalic, tagCenter};

    lyricView = new TextView(refBuffer);
    lyricView->set_editable(false);
    lyricView->set_can_focus(false);
    lyricView->set_justification(get_justification());
    lyricView->set_wrap_mode(WRAP_WORD_CHAR);
    lyricView->show();

    lyricbar = new ScrolledWindow();
    lyricbar->add(*lyricView);
    lyricbar->set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC);

    return GTK_WIDGET(lyricbar->gobj());
}

extern "C"
int message_handler(struct ddb_gtkui_widget_s*, uint32_t id, uintptr_t ctx, uint32_t, uint32_t) {
    auto event = reinterpret_cast<ddb_event_track_t *>(ctx);
    switch (id) {
        case DB_EV_CONFIGCHANGED:
            debug_out << "CONFIG CHANGED\n";
            signal_idle().connect_once([](){ lyricView->set_justification(get_justification()); });
            break;
        case DB_EV_SONGSTARTED:
            debug_out << "SONG STARTED\n";
        case DB_EV_TRACKINFOCHANGED:
            if (!event->track || deadbeef->pl_get_item_duration(event->track) <= 0)
                return 0;
            auto tid = deadbeef->thread_start(update_lyrics, event->track);
            deadbeef->thread_detach(tid);
            break;
    }

    return 0;
}

extern "C"
void lyricbar_destroy() {
    delete lyricbar;
    delete lyricView;
    tagsArtist.clear();
    tagsTitle.clear();
    tagLarge.reset();
    tagBold.reset();
    tagItalic.reset();
    refBuffer.reset();
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// OpenGL ES 2.0 code

#include <jni.h>
#include <android/log.h>

#include <GLES2/gl2.h>

#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <cmath>
#include <string>

#include <android/asset_manager_jni.h>
#include <android/asset_manager.h>

#define  LOG_TAG    "libgl2jni"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

const int SENSOR_HISTORY_LENGTH = 100;
GLfloat gSensorData[SENSOR_HISTORY_LENGTH*2];
int gSensorDataIndex = 0;
GLfloat gPositionX[SENSOR_HISTORY_LENGTH];
void initializePositionX() {
    for (auto i = 0; i < SENSOR_HISTORY_LENGTH; i++) {
        float t = float(i) / float(SENSOR_HISTORY_LENGTH - 1);
        gPositionX[i] = -1.f * (1.f - t) + 1.f * t;
    }
}

static void printGLString(const char *name, GLenum s) {
    const char *v = (const char *) glGetString(s);
    LOGI("GL %s = %s\n", name, v);
}

static void checkGlError(const char* op) {
    for (GLint error = glGetError(); error; error
            = glGetError()) {
        LOGI("after %s() glError (0x%x)\n", op, error);
    }
}

GLuint loadShader(GLenum shaderType, const std::string& pSource) {
    GLuint shader = glCreateShader(shaderType);
    if (shader) {
        const char *sourceBuf = pSource.c_str();
        glShaderSource(shader, 1, &sourceBuf, NULL);
        glCompileShader(shader);
        GLint compiled = 0;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
        if (!compiled) {
            GLint infoLen = 0;
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen) {
                char* buf = (char*) malloc(infoLen);
                if (buf) {
                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
                    LOGE("Could not compile shader %d:\n%s\n",
                            shaderType, buf);
                    free(buf);
                }
                glDeleteShader(shader);
                shader = 0;
            }
        }
    }
    return shader;
}

GLuint createProgram(const std::string& pVertexSource, const std::string& pFragmentSource) {
    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
    if (!vertexShader) {
        return 0;
    }

    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
    if (!pixelShader) {
        return 0;
    }

    GLuint program = glCreateProgram();
    if (program) {
        glAttachShader(program, vertexShader);
        checkGlError("glAttachShader");
        glAttachShader(program, pixelShader);
        checkGlError("glAttachShader");
        glLinkProgram(program);
        GLint linkStatus = GL_FALSE;
        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
        if (linkStatus != GL_TRUE) {
            GLint bufLength = 0;
            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
            if (bufLength) {
                char* buf = (char*) malloc(bufLength);
                if (buf) {
                    glGetProgramInfoLog(program, bufLength, NULL, buf);
                    LOGE("Could not link program:\n%s\n", buf);
                    free(buf);
                }
            }
            glDeleteProgram(program);
            program = 0;
        }
    }
    return program;
}

GLuint gProgram;
GLuint gvPositionXHandle;
GLuint gvSensorValueHandle;

bool init(AAssetManager *assetManager, jint w, jint h) {
    printGLString("Version", GL_VERSION);
    printGLString("Vendor", GL_VENDOR);
    printGLString("Renderer", GL_RENDERER);
    printGLString("Extensions", GL_EXTENSIONS);

    LOGI("setupGraphics(%d, %d)", w, h);
    AAsset *vertexShader = AAssetManager_open(assetManager, "shader.glslv", AASSET_MODE_BUFFER);
    assert(vertexShader != NULL);
    const void *vertexShaderBuf = AAsset_getBuffer(vertexShader);
    assert(vertexShaderBuf != NULL);
    int vertexShaderLength = AAsset_getLength(vertexShader);
    std::string vertexShaderSource((const char*)vertexShaderBuf, vertexShaderLength);

    AAsset *fragmentShader = AAssetManager_open(assetManager, "shader.glslf", AASSET_MODE_BUFFER);
    assert(fragmentShader != NULL);
    const void *fragmentShaderBuf = AAsset_getBuffer(fragmentShader);
    assert(fragmentShaderBuf != NULL);
    int fragmentShaderLength = AAsset_getLength(fragmentShader);
    std::string fragmentShaderSource((const char*)fragmentShaderBuf, fragmentShaderLength);

    gProgram = createProgram(vertexShaderSource, fragmentShaderSource);
    if (!gProgram) {
        LOGE("Could not create program.");
        return false;
    }
    gvPositionXHandle = glGetAttribLocation(gProgram, "vPositionX");
    checkGlError("glGetAttribLocation");
    LOGI("glGetAttribLocation(\"vPositionX\") = %d\n",
            gvPositionXHandle);

    gvSensorValueHandle = glGetAttribLocation(gProgram, "vSensorValue");
    checkGlError("glGetAttribLocation");
    LOGI("glGetAttribLocation(\"vSensorValue\") = %d\n",
         gvSensorValueHandle);

    glViewport(0, 0, w, h);
    checkGlError("glViewport");

    initializePositionX();
    return true;
}

void update() {

    float value = cos(gSensorDataIndex);
    gSensorData[gSensorDataIndex] = value;
    gSensorData[SENSOR_HISTORY_LENGTH+gSensorDataIndex] = value;
    gSensorDataIndex = (gSensorDataIndex + 1) % SENSOR_HISTORY_LENGTH;
}

void render() {
    glClearColor(0.f, 0.f, 0.f, 1.0f);
    checkGlError("glClearColor");
    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    checkGlError("glClear");

    glUseProgram(gProgram);
    checkGlError("glUseProgram");

    glVertexAttribPointer(gvPositionXHandle, 1, GL_FLOAT, GL_FALSE, 0, gPositionX);
    checkGlError("glVertexAttribPointer");
    glEnableVertexAttribArray(gvPositionXHandle);
    checkGlError("glEnableVertexAttribArray");
    glVertexAttribPointer(gvSensorValueHandle, 1, GL_FLOAT, GL_FALSE, 0, gSensorData+gSensorDataIndex);
    checkGlError("glVertexAttribPointer");
    glEnableVertexAttribArray(gvSensorValueHandle);
    checkGlError("glEnableVertexAttribArray");
    glDrawArrays(GL_LINE_STRIP, 0, SENSOR_HISTORY_LENGTH);
    checkGlError("glDrawArrays");
}

extern "C" {
    JNIEXPORT void JNICALL
    Java_com_android_gl2jni_GL2JNILib_init(JNIEnv *env, jclass type, jobject assetManager, jint width,
                                           jint height) {
        AAssetManager *nativeAssetManager = AAssetManager_fromJava(env, assetManager);
        init(nativeAssetManager, width, height);
    }

    JNIEXPORT void JNICALL
    Java_com_android_gl2jni_GL2JNILib_step(JNIEnv *env, jclass type) {
        update();
        render();
    }
}<commit_msg>sensor-graph: get sensor data<commit_after>/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// OpenGL ES 2.0 code

#include <jni.h>
#include <android/log.h>

#include <GLES2/gl2.h>

#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <cmath>
#include <string>

#include <android/asset_manager_jni.h>
#include <android/sensor.h>

#define  LOG_TAG    "libgl2jni"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

const int LOOPER_ID_USER = 3;
const int SENSOR_HISTORY_LENGTH = 100;
const int SENSOR_REFRESH_RATE = 20;
const float GRAVITY = 9.81f;

GLfloat gSensorData[SENSOR_HISTORY_LENGTH*2];
int gSensorDataIndex = 0;
GLfloat gPositionX[SENSOR_HISTORY_LENGTH];
void initializePositionX() {
    for (auto i = 0; i < SENSOR_HISTORY_LENGTH; i++) {
        float t = float(i) / float(SENSOR_HISTORY_LENGTH - 1);
        gPositionX[i] = -1.f * (1.f - t) + 1.f * t;
    }
}
ASensorEventQueue* gAccQueue;

static void printGLString(const char *name, GLenum s) {
    const char *v = (const char *) glGetString(s);
    LOGI("GL %s = %s\n", name, v);
}

static void checkGlError(const char* op) {
    for (GLint error = glGetError(); error; error
            = glGetError()) {
        LOGI("after %s() glError (0x%x)\n", op, error);
    }
}

GLuint loadShader(GLenum shaderType, const std::string& pSource) {
    GLuint shader = glCreateShader(shaderType);
    if (shader) {
        const char *sourceBuf = pSource.c_str();
        glShaderSource(shader, 1, &sourceBuf, NULL);
        glCompileShader(shader);
        GLint compiled = 0;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
        if (!compiled) {
            GLint infoLen = 0;
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen) {
                char* buf = (char*) malloc(infoLen);
                if (buf) {
                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
                    LOGE("Could not compile shader %d:\n%s\n",
                            shaderType, buf);
                    free(buf);
                }
                glDeleteShader(shader);
                shader = 0;
            }
        }
    }
    return shader;
}

GLuint createProgram(const std::string& pVertexSource, const std::string& pFragmentSource) {
    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
    if (!vertexShader) {
        return 0;
    }

    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
    if (!pixelShader) {
        return 0;
    }

    GLuint program = glCreateProgram();
    if (program) {
        glAttachShader(program, vertexShader);
        checkGlError("glAttachShader");
        glAttachShader(program, pixelShader);
        checkGlError("glAttachShader");
        glLinkProgram(program);
        GLint linkStatus = GL_FALSE;
        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
        if (linkStatus != GL_TRUE) {
            GLint bufLength = 0;
            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
            if (bufLength) {
                char* buf = (char*) malloc(bufLength);
                if (buf) {
                    glGetProgramInfoLog(program, bufLength, NULL, buf);
                    LOGE("Could not link program:\n%s\n", buf);
                    free(buf);
                }
            }
            glDeleteProgram(program);
            program = 0;
        }
    }
    return program;
}

GLuint gProgram;
GLuint gvPositionXHandle;
GLuint gvSensorValueHandle;

bool init(AAssetManager *assetManager, jint w, jint h) {
    printGLString("Version", GL_VERSION);
    printGLString("Vendor", GL_VENDOR);
    printGLString("Renderer", GL_RENDERER);
    printGLString("Extensions", GL_EXTENSIONS);

    LOGI("setupGraphics(%d, %d)", w, h);
    AAsset *vertexShader = AAssetManager_open(assetManager, "shader.glslv", AASSET_MODE_BUFFER);
    assert(vertexShader != NULL);
    const void *vertexShaderBuf = AAsset_getBuffer(vertexShader);
    assert(vertexShaderBuf != NULL);
    int vertexShaderLength = AAsset_getLength(vertexShader);
    std::string vertexShaderSource((const char*)vertexShaderBuf, vertexShaderLength);

    AAsset *fragmentShader = AAssetManager_open(assetManager, "shader.glslf", AASSET_MODE_BUFFER);
    assert(fragmentShader != NULL);
    const void *fragmentShaderBuf = AAsset_getBuffer(fragmentShader);
    assert(fragmentShaderBuf != NULL);
    int fragmentShaderLength = AAsset_getLength(fragmentShader);
    std::string fragmentShaderSource((const char*)fragmentShaderBuf, fragmentShaderLength);

    gProgram = createProgram(vertexShaderSource, fragmentShaderSource);
    if (!gProgram) {
        LOGE("Could not create program.");
        return false;
    }
    gvPositionXHandle = glGetAttribLocation(gProgram, "vPositionX");
    checkGlError("glGetAttribLocation");
    LOGI("glGetAttribLocation(\"vPositionX\") = %d\n",
            gvPositionXHandle);

    gvSensorValueHandle = glGetAttribLocation(gProgram, "vSensorValue");
    checkGlError("glGetAttribLocation");
    LOGI("glGetAttribLocation(\"vSensorValue\") = %d\n",
         gvSensorValueHandle);

    glViewport(0, 0, w, h);
    checkGlError("glViewport");

    initializePositionX();

    ASensorManager* sensorManager = ASensorManager_getInstance();
    assert(sensorManager != NULL);
    const ASensor* acc = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
    assert(acc != NULL);
    ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
    assert(looper != NULL);
    gAccQueue = ASensorManager_createEventQueue(sensorManager, looper, LOOPER_ID_USER, NULL, NULL);
    assert(gAccQueue != NULL);
    ASensorEventQueue_setEventRate(gAccQueue, acc, int32_t(10000000 / SENSOR_REFRESH_RATE));
    int enableSensorResult = ASensorEventQueue_enableSensor(gAccQueue, acc);
    assert(enableSensorResult >= 0);
    return true;
}

void update() {
    ALooper_pollAll(0, NULL, NULL, NULL);
    ASensorEvent event;
    while (ASensorEventQueue_getEvents(gAccQueue, &event, 1) > 0) {
        float accX = event.acceleration.x / GRAVITY;
        gSensorData[gSensorDataIndex] = accX;
        gSensorData[SENSOR_HISTORY_LENGTH+gSensorDataIndex] = accX;
    }
    gSensorDataIndex = (gSensorDataIndex + 1) % SENSOR_HISTORY_LENGTH;
}

void render() {
    glClearColor(0.f, 0.f, 0.f, 1.0f);
    checkGlError("glClearColor");
    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    checkGlError("glClear");

    glUseProgram(gProgram);
    checkGlError("glUseProgram");

    glVertexAttribPointer(gvPositionXHandle, 1, GL_FLOAT, GL_FALSE, 0, gPositionX);
    checkGlError("glVertexAttribPointer");
    glEnableVertexAttribArray(gvPositionXHandle);
    checkGlError("glEnableVertexAttribArray");
    glVertexAttribPointer(gvSensorValueHandle, 1, GL_FLOAT, GL_FALSE, 0, gSensorData+gSensorDataIndex);
    checkGlError("glVertexAttribPointer");
    glEnableVertexAttribArray(gvSensorValueHandle);
    checkGlError("glEnableVertexAttribArray");
    glDrawArrays(GL_LINE_STRIP, 0, SENSOR_HISTORY_LENGTH);
    checkGlError("glDrawArrays");
}

extern "C" {
    JNIEXPORT void JNICALL
    Java_com_android_gl2jni_GL2JNILib_init(JNIEnv *env, jclass type, jobject assetManager, jint width,
                                           jint height) {
        AAssetManager *nativeAssetManager = AAssetManager_fromJava(env, assetManager);
        init(nativeAssetManager, width, height);
    }

    JNIEXPORT void JNICALL
    Java_com_android_gl2jni_GL2JNILib_step(JNIEnv *env, jclass type) {
        update();
        render();
    }
}<|endoftext|>


<commit_before>// Copyright 2004-present Facebook. All Rights Reserved.

#include <memory>
#include <vector>

#include <gtest/gtest.h>

#include "yarpl/Flowable.h"
#include "yarpl/Refcounted.h"

using yarpl::Refcounted;
using yarpl::Reference;
using yarpl::flowable::Subscriber;

namespace {

template <class T>
class MySubscriber : public Subscriber<T> {};

}

TEST(ReferenceTest, Upcast) {
  Reference<MySubscriber<int>> derived(new MySubscriber<int>());
  Reference<Subscriber<int>> base1(derived);

  Reference<Subscriber<int>> base2;
  base2 = derived;

  Reference<MySubscriber<int>> derivedCopy1(derived);
  Reference<MySubscriber<int>> derivedCopy2(derived);

  Reference<Subscriber<int>> base3(std::move(derivedCopy1));

  Reference<Subscriber<int>> base4;
  base4 = std::move(derivedCopy2);
}

TEST(RefcountedTest, CopyAssign) {
  using Sub = Subscriber<int>;
  Reference<Sub> a(new Sub());
  Reference<Sub> b(a);
  EXPECT_EQ(2, a->count());
  Sub* ptr = nullptr;
  Reference<Sub> c(ptr = new Sub());
  b = c;
  EXPECT_EQ(1, a->count());
  EXPECT_EQ(ptr, b.get());
}

TEST(RefcountedTest, MoveAssign) {
  using Sub = Subscriber<int>;
  Reference<Sub> a(new Sub());
  Reference<Sub> b(a);
  EXPECT_EQ(2, a->count());
  Sub* ptr = nullptr;
  b = Reference<Sub>(ptr = new Sub());
  EXPECT_EQ(1, a->count());
  EXPECT_EQ(ptr, b.get());
}

TEST(RefcountedTest, CopyAssignTemplate) {
  using Sub = Subscriber<int>;
  Reference<Sub> a(new Sub());
  Reference<Sub> b(a);
  EXPECT_EQ(2, a->count());
  using Sub2 = MySubscriber<int>;
  Sub2* ptr = nullptr;
  Reference<Sub2> c(ptr = new Sub2());
  b = c;
  EXPECT_EQ(1, a->count());
  EXPECT_EQ(ptr, b.get());
}

TEST(RefcountedTest, MoveAssignTemplate) {
  using Sub = Subscriber<int>;
  Reference<Sub> a(new Sub());
  Reference<Sub> b(a);
  EXPECT_EQ(2, a->count());
  using Sub2 = MySubscriber<int>;
  Sub2* ptr = nullptr;
  b = Reference<Sub2>(ptr = new Sub2());
  EXPECT_EQ(1, a->count());
  EXPECT_EQ(ptr, b.get());
}
<commit_msg>Silence unsigned vs signed integer comparison warnings in ReferenceTest.cpp (#398)<commit_after>// Copyright 2004-present Facebook. All Rights Reserved.

#include <memory>
#include <vector>

#include <gtest/gtest.h>

#include "yarpl/Flowable.h"
#include "yarpl/Refcounted.h"

using yarpl::Refcounted;
using yarpl::Reference;
using yarpl::flowable::Subscriber;

namespace {

template <class T>
class MySubscriber : public Subscriber<T> {};

}

TEST(ReferenceTest, Upcast) {
  Reference<MySubscriber<int>> derived(new MySubscriber<int>());
  Reference<Subscriber<int>> base1(derived);

  Reference<Subscriber<int>> base2;
  base2 = derived;

  Reference<MySubscriber<int>> derivedCopy1(derived);
  Reference<MySubscriber<int>> derivedCopy2(derived);

  Reference<Subscriber<int>> base3(std::move(derivedCopy1));

  Reference<Subscriber<int>> base4;
  base4 = std::move(derivedCopy2);
}

TEST(RefcountedTest, CopyAssign) {
  using Sub = Subscriber<int>;
  Reference<Sub> a(new Sub());
  Reference<Sub> b(a);
  EXPECT_EQ(2u, a->count());
  Sub* ptr = nullptr;
  Reference<Sub> c(ptr = new Sub());
  b = c;
  EXPECT_EQ(1u, a->count());
  EXPECT_EQ(ptr, b.get());
}

TEST(RefcountedTest, MoveAssign) {
  using Sub = Subscriber<int>;
  Reference<Sub> a(new Sub());
  Reference<Sub> b(a);
  EXPECT_EQ(2u, a->count());
  Sub* ptr = nullptr;
  b = Reference<Sub>(ptr = new Sub());
  EXPECT_EQ(1u, a->count());
  EXPECT_EQ(ptr, b.get());
}

TEST(RefcountedTest, CopyAssignTemplate) {
  using Sub = Subscriber<int>;
  Reference<Sub> a(new Sub());
  Reference<Sub> b(a);
  EXPECT_EQ(2u, a->count());
  using Sub2 = MySubscriber<int>;
  Sub2* ptr = nullptr;
  Reference<Sub2> c(ptr = new Sub2());
  b = c;
  EXPECT_EQ(1u, a->count());
  EXPECT_EQ(ptr, b.get());
}

TEST(RefcountedTest, MoveAssignTemplate) {
  using Sub = Subscriber<int>;
  Reference<Sub> a(new Sub());
  Reference<Sub> b(a);
  EXPECT_EQ(2u, a->count());
  using Sub2 = MySubscriber<int>;
  Sub2* ptr = nullptr;
  b = Reference<Sub2>(ptr = new Sub2());
  EXPECT_EQ(1u, a->count());
  EXPECT_EQ(ptr, b.get());
}
<|endoftext|>


<commit_before>#include "worker.h"

#include <iostream>

namespace REST {

Worker::Worker(int i, std::queue< std::shared_ptr<Request> > *rq, std::mutex *re, std::mutex *rl) :
 id(i), requests_queue(rq), requests_empty(re), requests_lock(rl) {
  run();
}

void Worker::run() {
  should_run.store(true);

  thread = std::thread([this] () {
    // while worker is alive
    while (should_run.load()) {
      // wait for new requests
      if (requests_queue->empty())
        requests_empty->lock();

      // lock requests queue
      requests_lock->lock();

      // maybe empty even after unlocking - stop()
      if (requests_queue->empty())
        break;

      // get request
      std::shared_ptr<Request> request = requests_queue->front();
      requests_queue->pop();

      // ready
      requests_lock->unlock();

      // route
      // exec
      // send response
      // close
      //

      try {
        throw HTTP::NotFound();
      } catch (HTTP::Error &e) {
        std::string msg = "HTTP/1.0 " + std::to_string(e.code()) + " " + e.what() + "\r\nContent-Type: text/plain\r\nContent-Length: " + std::to_string(strlen(e.what())+2) + "\r\n\r\n" + e.what() + "\r\n";
        int len = msg.size();
        ssize_t bytes_sent;
        bytes_sent = send(request->handle, msg.c_str(), len, 0);
      }

      std::cout << request->handle << " is my handle\n";
      std::cout << id << ": got request\n";

      close(request->handle);
    }

    std::cout << "stopped worker" << id << std::endl;
  });
}

void Worker::stop() {
  should_run.store(false);
  thread.join();

  std::cout << "stopping worker " << id << std::endl;
}

}
<commit_msg>minor worker bug<commit_after>#include "worker.h"

#include <iostream>

namespace REST {

Worker::Worker(int i, std::queue< std::shared_ptr<Request> > *rq, std::mutex *re, std::mutex *rl) :
 id(i), requests_queue(rq), requests_empty(re), requests_lock(rl) {
  run();
}

void Worker::run() {
  should_run.store(true);

  thread = std::thread([this] () {
    // while worker is alive
    while (should_run.load()) {
      // wait for new requests
      if (requests_queue->empty())
        requests_empty->lock();

      // lock requests queue
      requests_lock->lock();

      // maybe empty even after unlocking, wait some more
      if (requests_queue->empty())
        continue;

      // get request
      std::shared_ptr<Request> request = requests_queue->front();
      requests_queue->pop();

      // ready
      requests_lock->unlock();

      // route
      // exec
      // send response
      // close
      //

      try {
        throw HTTP::NotFound();
      } catch (HTTP::Error &e) {
        // new Response(request, e)->send()
        std::string msg = "HTTP/1.0 " + std::to_string(e.code()) + " " + e.what() + "\r\nContent-Type: text/plain\r\nContent-Length: " + std::to_string(strlen(e.what())+2) + "\r\n\r\n" + e.what() + "\r\n";
        int len = msg.size();
        ssize_t bytes_sent;
        bytes_sent = send(request->handle, msg.c_str(), len, 0);
      }

      std::cout << request->handle << " is my handle\n";
      std::cout << id << ": got request\n";

      close(request->handle);
    }

    std::cout << "stopped worker" << id << std::endl;
  });
}

void Worker::stop() {
  should_run.store(false);
  thread.join();

  std::cout << "stopping worker " << id << std::endl;
}

}
<|endoftext|>


<commit_before>/*
The MIT License(MIT)

//Copyright (c) 2016-2017 Oleg Linkin <maledictusdemagog@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "utils.h"

#include <tuple>

#include <QList>
#include <QRegularExpression>
#include <QtDebug>

namespace Mnemosy
{
namespace Utils
{
void SetImagesWidth(QString& text, bool& hasArg)
{
    QRegularExpression imgRxp("\\",
            QRegularExpression::CaseInsensitiveOption);
    QList<QPair<QString, QString>> matched;
    QRegularExpressionMatchIterator matchIt = imgRxp.globalMatch(text);
    while (matchIt.hasNext())
    {
        QRegularExpressionMatch match = matchIt.next();
        const auto& imgTag = match.captured(0);
        if (!imgTag.contains("l-stat.livejournal.net"))
        {
            matched << QPair<QString, QString>(imgTag, match.captured(1));
        }
    }

    for (const auto& t : matched)
    {
        text.replace (t.first,
                ""));
        if (!hasArg)
        {
            hasArg = true;
        }
    }
}

void MoveFirstImageToTheTop(QString& text)
{
    QRegularExpression imgRxp("(\\)",
            QRegularExpression::CaseInsensitiveOption);
    QRegularExpressionMatch match = imgRxp.match(text);
    if (match.hasMatch())
    {
        QString matched = match.captured(0);
        text.remove(match.capturedStart(0), match.capturedLength(0));
        text.push_front(matched);
    }
}

void RemoveStyleTag(QString& text)
{
    QRegularExpression styleRxp ("style=\"(.+?)\"",
            QRegularExpression::CaseInsensitiveOption);
    text.remove(styleRxp);
}

void FixUntaggedUrls(QString& text)
{
    auto pattern = "(?<!='|\")((http|ftp|https):\\/\\/([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:\\/~+#-]*[\\w@?^=%&\\/~+#-])?)";
    QRegularExpression untaggedUrlRxp(pattern, QRegularExpression::CaseInsensitiveOption);
    text.replace(untaggedUrlRxp, "\\1");
}

void TryToFillEventFields(LJEvent& event)
{
    if (!event.GetPosterID() && !event.GetPosterPicUrl().isEmpty())
    {
        QString url = event.GetPosterPicUrl().toString();
        event.SetPosterID(url.mid(url.lastIndexOf("/") + 1)
                .toLongLong());
    }

    if (event.GetPosterName().isEmpty())
    {
        QString url = event.GetUrl().toString();
        QString name = url.mid(7, url.indexOf(".") - 7);
        name.replace('-', "_");
        event.SetPosterName(name);
    }
}

QString AccessToString(Access acc)
{
    switch (acc)
    {
    case APrivate:
        return "private";
    case APublic:
        return "public";
    case ACustom:
    default:
        return "usemask";
    }
}

QString AdultContentToString(AdultContent ac)
{
    switch (ac)
    {
    case ACAdultsFrom14:
        return "concepts";
    case ACAdultsFrom18:
        return "explicit";
    case ACWithoutAdultContent:
    default:
        return "none";
    }
}

QString ScreeningToString(CommentsManagement cm)
{
    switch (cm)
    {
    case CMShowFriendsComments:
        return "F";
    case CMScreenComments:
        return "A";
    case CMScreenAnonymouseComments:
        return "R";
    case CMScreenNotFromFriendsWithLinks:
        return "L";
    case CMShowComments:
    default:
        return "N";
    }
}
}
} // namespace Mnemosy

<commit_msg>Fix img tag regexp<commit_after>/*
The MIT License(MIT)

//Copyright (c) 2016-2017 Oleg Linkin <maledictusdemagog@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "utils.h"

#include <tuple>

#include <QList>
#include <QRegularExpression>
#include <QtDebug>

namespace Mnemosy
{
namespace Utils
{
void SetImagesWidth(QString& text, bool& hasArg)
{
    QRegularExpression imgRxp("\\",
            QRegularExpression::CaseInsensitiveOption);
    QList<QPair<QString, QString>> matched;
    QRegularExpressionMatchIterator matchIt = imgRxp.globalMatch(text);
    while (matchIt.hasNext())
    {
        QRegularExpressionMatch match = matchIt.next();
        const auto& imgTag = match.captured(0);
        if (!imgTag.contains("l-stat.livejournal.net"))
        {
            matched << QPair<QString, QString>(imgTag, match.captured(2));
        }
    }

    for (const auto& t : matched)
    {
        text.replace (t.first,
                ""));
        if (!hasArg)
        {
            hasArg = true;
        }
    }
}

void MoveFirstImageToTheTop(QString& text)
{
    QRegularExpression imgRxp("(\\)",
            QRegularExpression::CaseInsensitiveOption);
    QRegularExpressionMatch match = imgRxp.match(text);
    if (match.hasMatch())
    {
        QString matched = match.captured(0);
        text.remove(match.capturedStart(0), match.capturedLength(0));
        text.push_front(matched);
    }
}

void RemoveStyleTag(QString& text)
{
    QRegularExpression styleRxp ("style=\"(.+?)\"",
            QRegularExpression::CaseInsensitiveOption);
    text.remove(styleRxp);
}

void FixUntaggedUrls(QString& text)
{
    auto pattern = "(?<!='|\")((http|ftp|https):\\/\\/([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:\\/~+#-]*[\\w@?^=%&\\/~+#-])?)";
    QRegularExpression untaggedUrlRxp(pattern, QRegularExpression::CaseInsensitiveOption);
    text.replace(untaggedUrlRxp, "\\1");
}

void TryToFillEventFields(LJEvent& event)
{
    if (!event.GetPosterID() && !event.GetPosterPicUrl().isEmpty())
    {
        QString url = event.GetPosterPicUrl().toString();
        event.SetPosterID(url.mid(url.lastIndexOf("/") + 1)
                .toLongLong());
    }

    if (event.GetPosterName().isEmpty())
    {
        QString url = event.GetUrl().toString();
        QString name = url.mid(7, url.indexOf(".") - 7);
        name.replace('-', "_");
        event.SetPosterName(name);
    }
}

QString AccessToString(Access acc)
{
    switch (acc)
    {
    case APrivate:
        return "private";
    case APublic:
        return "public";
    case ACustom:
    default:
        return "usemask";
    }
}

QString AdultContentToString(AdultContent ac)
{
    switch (ac)
    {
    case ACAdultsFrom14:
        return "concepts";
    case ACAdultsFrom18:
        return "explicit";
    case ACWithoutAdultContent:
    default:
        return "none";
    }
}

QString ScreeningToString(CommentsManagement cm)
{
    switch (cm)
    {
    case CMShowFriendsComments:
        return "F";
    case CMScreenComments:
        return "A";
    case CMScreenAnonymouseComments:
        return "R";
    case CMScreenNotFromFriendsWithLinks:
        return "L";
    case CMShowComments:
    default:
        return "N";
    }
}
}
} // namespace Mnemosy

<|endoftext|>


<commit_before>#include "askpassphrasedialog.h"
#include "ui_askpassphrasedialog.h"

#include "guiconstants.h"
#include "walletmodel.h"

#include <QMessageBox>
#include <QPushButton>
#include <QKeyEvent>

AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AskPassphraseDialog),
    mode(mode),
    model(0),
    fCapsLock(false)
{
    ui->setupUi(this);
    ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
    ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
    ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);

    // Setup Caps Lock detection.
    ui->passEdit1->installEventFilter(this);
    ui->passEdit2->installEventFilter(this);
    ui->passEdit3->installEventFilter(this);

    switch(mode)
    {
        case Encrypt: // Ask passphrase x2
            ui->passLabel1->hide();
            ui->passEdit1->hide();
            ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.
Please use a passphrase of 10 or more random characters, or eight or more words."));
            setWindowTitle(tr("Encrypt wallet"));
            break;
        case Unlock: // Ask passphrase
            ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
            ui->passLabel2->hide();
            ui->passEdit2->hide();
            ui->passLabel3->hide();
            ui->passEdit3->hide();
            setWindowTitle(tr("Unlock wallet"));
            break;
        case Decrypt:   // Ask passphrase
            ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
            ui->passLabel2->hide();
            ui->passEdit2->hide();
            ui->passLabel3->hide();
            ui->passEdit3->hide();
            setWindowTitle(tr("Decrypt wallet"));
            break;
        case ChangePass: // Ask old passphrase + new passphrase x2
            setWindowTitle(tr("Change passphrase"));
            ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet."));
            break;
    }

    textChanged();
    connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
    connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
    connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
}

AskPassphraseDialog::~AskPassphraseDialog()
{
    // Attempt to overwrite text so that they do not linger around in memory
    ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
    ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
    ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
    delete ui;
}

void AskPassphraseDialog::setModel(WalletModel *model)
{
    this->model = model;
}

void AskPassphraseDialog::accept()
{
    SecureString oldpass, newpass1, newpass2;
    if(!model)
        return;
    oldpass.reserve(MAX_PASSPHRASE_SIZE);
    newpass1.reserve(MAX_PASSPHRASE_SIZE);
    newpass2.reserve(MAX_PASSPHRASE_SIZE);
    // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
    // Alternately, find a way to make this input mlock()'d to begin with.
    oldpass.assign(ui->passEdit1->text().toStdString().c_str());
    newpass1.assign(ui->passEdit2->text().toStdString().c_str());
    newpass2.assign(ui->passEdit3->text().toStdString().c_str());

    switch(mode)
    {
    case Encrypt: {
        if(newpass1.empty() || newpass2.empty())
        {
            // Cannot encrypt with empty passphrase
            break;
        }
        QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
                 tr("WARNING: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR SMALLCHANGE!\nAre you sure you wish to encrypt your wallet?"),
                 QMessageBox::Yes|QMessageBox::Cancel,
                 QMessageBox::Cancel);
        if(retval == QMessageBox::Yes)
        {
            if(newpass1 == newpass2)
            {
                if(model->setWalletEncrypted(true, newpass1))
                {
                    QMessageBox::warning(this, tr("Wallet encrypted"),
                                         tr("SmallChange will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your yxcoin from being stolen by malware infecting your computer."));
                    QApplication::quit();
                }
                else
                {
                    QMessageBox::critical(this, tr("Wallet encryption failed"),
                                         tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
                }
                QDialog::accept(); // Success
            }
            else
            {
                QMessageBox::critical(this, tr("Wallet encryption failed"),
                                     tr("The supplied passphrases do not match."));
            }
        }
        else
        {
            QDialog::reject(); // Cancelled
        }
        } break;
    case Unlock:
        if(!model->setWalletLocked(false, oldpass))
        {
            QMessageBox::critical(this, tr("Wallet unlock failed"),
                                  tr("The passphrase entered for the wallet decryption was incorrect."));
        }
        else
        {
            QDialog::accept(); // Success
        }
        break;
    case Decrypt:
        if(!model->setWalletEncrypted(false, oldpass))
        {
            QMessageBox::critical(this, tr("Wallet decryption failed"),
                                  tr("The passphrase entered for the wallet decryption was incorrect."));
        }
        else
        {
            QDialog::accept(); // Success
        }
        break;
    case ChangePass:
        if(newpass1 == newpass2)
        {
            if(model->changePassphrase(oldpass, newpass1))
            {
                QMessageBox::information(this, tr("Wallet encrypted"),
                                     tr("Wallet passphrase was successfully changed."));
                QDialog::accept(); // Success
            }
            else
            {
                QMessageBox::critical(this, tr("Wallet encryption failed"),
                                     tr("The passphrase entered for the wallet decryption was incorrect."));
            }
        }
        else
        {
            QMessageBox::critical(this, tr("Wallet encryption failed"),
                                 tr("The supplied passphrases do not match."));
        }
        break;
    }
}

void AskPassphraseDialog::textChanged()
{
    // Validate input, set Ok button to enabled when accepable
    bool acceptable = false;
    switch(mode)
    {
    case Encrypt: // New passphrase x2
        acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
        break;
    case Unlock: // Old passphrase x1
    case Decrypt:
        acceptable = !ui->passEdit1->text().isEmpty();
        break;
    case ChangePass: // Old passphrase x1, new passphrase x2
        acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
        break;
    }
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
}

bool AskPassphraseDialog::event(QEvent *event)
{
    // Detect Caps Lock key press.
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        if (ke->key() == Qt::Key_CapsLock) {
            fCapsLock = !fCapsLock;
        }
        if (fCapsLock) {
            ui->capsLabel->setText(tr("Warning: The Caps Lock key is on."));
        } else {
            ui->capsLabel->clear();
        }
    }
    return QWidget::event(event);
}

bool AskPassphraseDialog::eventFilter(QObject *, QEvent *event)
{
    /* Detect Caps Lock.
     * There is no good OS-independent way to check a key state in Qt, but we
     * can detect Caps Lock by checking for the following condition:
     * Shift key is down and the result is a lower case character, or
     * Shift key is not down and the result is an upper case character.
     */
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        QString str = ke->text();
        if (str.length() != 0) {
            const QChar *psz = str.unicode();
            bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0;
            if ((fShift && psz->isLower()) || (!fShift && psz->isUpper())) {
                fCapsLock = true;
                ui->capsLabel->setText(tr("Warning: The Caps Lock key is on."));
            } else if (psz->isLetter()) {
                fCapsLock = false;
                ui->capsLabel->clear();
            }
        }
    }
    return false;
}
<commit_msg>SMALLCHANGE/YXCOIN<commit_after>#include "askpassphrasedialog.h"
#include "ui_askpassphrasedialog.h"

#include "guiconstants.h"
#include "walletmodel.h"

#include <QMessageBox>
#include <QPushButton>
#include <QKeyEvent>

AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AskPassphraseDialog),
    mode(mode),
    model(0),
    fCapsLock(false)
{
    ui->setupUi(this);
    ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
    ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
    ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);

    // Setup Caps Lock detection.
    ui->passEdit1->installEventFilter(this);
    ui->passEdit2->installEventFilter(this);
    ui->passEdit3->installEventFilter(this);

    switch(mode)
    {
        case Encrypt: // Ask passphrase x2
            ui->passLabel1->hide();
            ui->passEdit1->hide();
            ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.
Please use a passphrase of 10 or more random characters, or eight or more words."));
            setWindowTitle(tr("Encrypt wallet"));
            break;
        case Unlock: // Ask passphrase
            ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
            ui->passLabel2->hide();
            ui->passEdit2->hide();
            ui->passLabel3->hide();
            ui->passEdit3->hide();
            setWindowTitle(tr("Unlock wallet"));
            break;
        case Decrypt:   // Ask passphrase
            ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
            ui->passLabel2->hide();
            ui->passEdit2->hide();
            ui->passLabel3->hide();
            ui->passEdit3->hide();
            setWindowTitle(tr("Decrypt wallet"));
            break;
        case ChangePass: // Ask old passphrase + new passphrase x2
            setWindowTitle(tr("Change passphrase"));
            ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet."));
            break;
    }

    textChanged();
    connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
    connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
    connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
}

AskPassphraseDialog::~AskPassphraseDialog()
{
    // Attempt to overwrite text so that they do not linger around in memory
    ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
    ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
    ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
    delete ui;
}

void AskPassphraseDialog::setModel(WalletModel *model)
{
    this->model = model;
}

void AskPassphraseDialog::accept()
{
    SecureString oldpass, newpass1, newpass2;
    if(!model)
        return;
    oldpass.reserve(MAX_PASSPHRASE_SIZE);
    newpass1.reserve(MAX_PASSPHRASE_SIZE);
    newpass2.reserve(MAX_PASSPHRASE_SIZE);
    // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
    // Alternately, find a way to make this input mlock()'d to begin with.
    oldpass.assign(ui->passEdit1->text().toStdString().c_str());
    newpass1.assign(ui->passEdit2->text().toStdString().c_str());
    newpass2.assign(ui->passEdit3->text().toStdString().c_str());

    switch(mode)
    {
    case Encrypt: {
        if(newpass1.empty() || newpass2.empty())
        {
            // Cannot encrypt with empty passphrase
            break;
        }
        QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
                 tr("WARNING: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR YXCOIN!\nAre you sure you wish to encrypt your wallet?"),
                 QMessageBox::Yes|QMessageBox::Cancel,
                 QMessageBox::Cancel);
        if(retval == QMessageBox::Yes)
        {
            if(newpass1 == newpass2)
            {
                if(model->setWalletEncrypted(true, newpass1))
                {
                    QMessageBox::warning(this, tr("Wallet encrypted"),
                                         tr("SmallChange will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your yxcoin from being stolen by malware infecting your computer."));
                    QApplication::quit();
                }
                else
                {
                    QMessageBox::critical(this, tr("Wallet encryption failed"),
                                         tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
                }
                QDialog::accept(); // Success
            }
            else
            {
                QMessageBox::critical(this, tr("Wallet encryption failed"),
                                     tr("The supplied passphrases do not match."));
            }
        }
        else
        {
            QDialog::reject(); // Cancelled
        }
        } break;
    case Unlock:
        if(!model->setWalletLocked(false, oldpass))
        {
            QMessageBox::critical(this, tr("Wallet unlock failed"),
                                  tr("The passphrase entered for the wallet decryption was incorrect."));
        }
        else
        {
            QDialog::accept(); // Success
        }
        break;
    case Decrypt:
        if(!model->setWalletEncrypted(false, oldpass))
        {
            QMessageBox::critical(this, tr("Wallet decryption failed"),
                                  tr("The passphrase entered for the wallet decryption was incorrect."));
        }
        else
        {
            QDialog::accept(); // Success
        }
        break;
    case ChangePass:
        if(newpass1 == newpass2)
        {
            if(model->changePassphrase(oldpass, newpass1))
            {
                QMessageBox::information(this, tr("Wallet encrypted"),
                                     tr("Wallet passphrase was successfully changed."));
                QDialog::accept(); // Success
            }
            else
            {
                QMessageBox::critical(this, tr("Wallet encryption failed"),
                                     tr("The passphrase entered for the wallet decryption was incorrect."));
            }
        }
        else
        {
            QMessageBox::critical(this, tr("Wallet encryption failed"),
                                 tr("The supplied passphrases do not match."));
        }
        break;
    }
}

void AskPassphraseDialog::textChanged()
{
    // Validate input, set Ok button to enabled when accepable
    bool acceptable = false;
    switch(mode)
    {
    case Encrypt: // New passphrase x2
        acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
        break;
    case Unlock: // Old passphrase x1
    case Decrypt:
        acceptable = !ui->passEdit1->text().isEmpty();
        break;
    case ChangePass: // Old passphrase x1, new passphrase x2
        acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
        break;
    }
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
}

bool AskPassphraseDialog::event(QEvent *event)
{
    // Detect Caps Lock key press.
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        if (ke->key() == Qt::Key_CapsLock) {
            fCapsLock = !fCapsLock;
        }
        if (fCapsLock) {
            ui->capsLabel->setText(tr("Warning: The Caps Lock key is on."));
        } else {
            ui->capsLabel->clear();
        }
    }
    return QWidget::event(event);
}

bool AskPassphraseDialog::eventFilter(QObject *, QEvent *event)
{
    /* Detect Caps Lock.
     * There is no good OS-independent way to check a key state in Qt, but we
     * can detect Caps Lock by checking for the following condition:
     * Shift key is down and the result is a lower case character, or
     * Shift key is not down and the result is an upper case character.
     */
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        QString str = ke->text();
        if (str.length() != 0) {
            const QChar *psz = str.unicode();
            bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0;
            if ((fShift && psz->isLower()) || (!fShift && psz->isUpper())) {
                fCapsLock = true;
                ui->capsLabel->setText(tr("Warning: The Caps Lock key is on."));
            } else if (psz->isLetter()) {
                fCapsLock = false;
                ui->capsLabel->clear();
            }
        }
    }
    return false;
}
<|endoftext|>