<commit_before>/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/*
  Get hostname for an IP.  Hostnames are checked with reverse name lookup and
  checked that they doesn't resemble an ip.
*/

#include "mysql_priv.h"
#include "hash_filo.h"
#include <m_ctype.h>
#ifdef	__cplusplus
extern "C" {					// Because of SCO 3.2V4.2
#endif
#if !defined( __WIN__) && !defined(OS2)
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#include <netdb.h>
#include <sys/utsname.h>
#endif // __WIN__
#ifdef	__cplusplus
}
#endif

class host_entry :public hash_filo_element
{
public:
  char	 ip[sizeof(((struct in_addr *) 0)->s_addr)];
  uint	 errors;
  char	 *hostname;
};

static hash_filo *hostname_cache;
static pthread_mutex_t LOCK_hostname;

void hostname_cache_refresh()
{
  hostname_cache->clear();
}

bool hostname_cache_init()
{
  host_entry tmp;
  uint offset= (uint) ((char*) (&tmp.ip) - (char*) &tmp);
  if (!(hostname_cache=new hash_filo(HOST_CACHE_SIZE, offset,
				     sizeof(struct in_addr),NULL,
				     (hash_free_key) free,
				     &my_charset_latin1)))
    return 1;
  hostname_cache->clear();
  (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
  return 0;
}

void hostname_cache_free()
{
  if (hostname_cache)
  {
    (void) pthread_mutex_destroy(&LOCK_hostname);
    delete hostname_cache;
    hostname_cache= 0;
  }
}

static void add_hostname(struct in_addr *in,const char *name)
{
  if (!(specialflag & SPECIAL_NO_HOST_CACHE))
  {
    VOID(pthread_mutex_lock(&hostname_cache->lock));
    host_entry *entry;
    if (!(entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    {
      uint length=name ? (uint) strlen(name) : 0;

      if ((entry=(host_entry*) malloc(sizeof(host_entry)+length+1)))
      {
	char *new_name;
	memcpy_fixed(&entry->ip, &in->s_addr, sizeof(in->s_addr));
	if (length)
	  memcpy(new_name= (char *) (entry+1), name, length+1);
	else
	  new_name=0;
	entry->hostname=new_name;
	entry->errors=0;
	(void) hostname_cache->add(entry);
      }
    }
    VOID(pthread_mutex_unlock(&hostname_cache->lock));
  }
}

inline void add_wrong_ip(struct in_addr *in)
{
  add_hostname(in,NullS);
}

void inc_host_errors(struct in_addr *in)
{
  VOID(pthread_mutex_lock(&hostname_cache->lock));
  host_entry *entry;
  if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    entry->errors++;
  VOID(pthread_mutex_unlock(&hostname_cache->lock));
}

void reset_host_errors(struct in_addr *in)
{
  VOID(pthread_mutex_lock(&hostname_cache->lock));
  host_entry *entry;
  if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    entry->errors=0;
  VOID(pthread_mutex_unlock(&hostname_cache->lock));
}

/* Deal with systems that don't defined INADDR_LOOPBACK */
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001UL
#endif

my_string ip_to_hostname(struct in_addr *in, uint *errors)
{
  uint i;
  host_entry *entry;
  DBUG_ENTER("ip_to_hostname");
  *errors=0;

  /* We always treat the loopback address as "localhost". */
  if (in->s_addr == INADDR_LOOPBACK)
    return (char *)my_localhost;

  /* Check first if we have name in cache */
  if (!(specialflag & SPECIAL_NO_HOST_CACHE))
  {
    VOID(pthread_mutex_lock(&hostname_cache->lock));
    if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    {
      char *name;
      if (!entry->hostname)
	name=0;					// Don't allow connection
      else
	name=my_strdup(entry->hostname,MYF(0));
      *errors= entry->errors;
      VOID(pthread_mutex_unlock(&hostname_cache->lock));
      DBUG_RETURN(name);
    }
    VOID(pthread_mutex_unlock(&hostname_cache->lock));
  }

  struct hostent *hp, *check;
  char *name;
  LINT_INIT(check);
#if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
  char buff[GETHOSTBYADDR_BUFF_SIZE],buff2[GETHOSTBYNAME_BUFF_SIZE];
  int tmp_errno;
  struct hostent tmp_hostent, tmp_hostent2;
#ifdef HAVE_purify
  bzero(buff,sizeof(buff));		// Bug in purify
#endif
  if (!(hp=gethostbyaddr_r((char*) in,sizeof(*in),
			   AF_INET,
			   &tmp_hostent,buff,sizeof(buff),&tmp_errno)))
  {
    DBUG_PRINT("error",("gethostbyaddr_r returned %d",tmp_errno));
    return 0;
  }
  if (!(check=my_gethostbyname_r(hp->h_name,&tmp_hostent2,buff2,sizeof(buff2),
				 &tmp_errno)))
  {
    DBUG_PRINT("error",("gethostbyname_r returned %d",tmp_errno));
    /*
      Don't cache responses when the DSN server is down, as otherwise
      transient DNS failure may leave any number of clients (those
      that attempted to connect during the outage) unable to connect
      indefinitely.
    */
    if (tmp_errno == HOST_NOT_FOUND || tmp_errno == NO_DATA)
      add_wrong_ip(in);
    my_gethostbyname_r_free();
    DBUG_RETURN(0);
  }
  if (!hp->h_name[0])
  {
    DBUG_PRINT("error",("Got an empty hostname"));
    add_wrong_ip(in);
    my_gethostbyname_r_free();
    DBUG_RETURN(0);				// Don't allow empty hostnames
  }
  if (!(name=my_strdup(hp->h_name,MYF(0))))
  {
    my_gethostbyname_r_free();
    DBUG_RETURN(0);				// out of memory
  }
  my_gethostbyname_r_free();
#else
  VOID(pthread_mutex_lock(&LOCK_hostname));
  if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET)))
  {
    VOID(pthread_mutex_unlock(&LOCK_hostname));
    DBUG_PRINT("error",("gethostbyaddr returned %d",errno));

    if (errno == HOST_NOT_FOUND || errno == NO_DATA)
      goto add_wrong_ip_and_return;
    /* Failure, don't cache responce */
    DBUG_RETURN(0);
  }
  if (!hp->h_name[0])				// Don't allow empty hostnames
  {
    VOID(pthread_mutex_unlock(&LOCK_hostname));
    DBUG_PRINT("error",("Got an empty hostname"));
    goto add_wrong_ip_and_return;
  }
  if (!(name=my_strdup(hp->h_name,MYF(0))))
  {
    VOID(pthread_mutex_unlock(&LOCK_hostname));
    DBUG_RETURN(0);				// out of memory
  }
  check=gethostbyname(name);
  VOID(pthread_mutex_unlock(&LOCK_hostname));
  if (!check)
  {
    DBUG_PRINT("error",("gethostbyname returned %d",errno));
    my_free(name,MYF(0));
    DBUG_RETURN(0);
  }
#endif

  /* Don't accept hostnames that starts with digits because they may be
     false ip:s */
  if (my_isdigit(&my_charset_latin1,name[0]))
  {
    char *pos;
    for (pos= name+1 ; my_isdigit(&my_charset_latin1,*pos); pos++) ;
    if (*pos == '.')
    {
      DBUG_PRINT("error",("mysqld doesn't accept hostnames that starts with a number followed by a '.'"));
      my_free(name,MYF(0));
      goto add_wrong_ip_and_return;
    }
  }

  /* Check that 'gethostbyname' returned the used ip */
  for (i=0; check->h_addr_list[i]; i++)
  {
    if (*(uint32*)(check->h_addr_list)[i] == in->s_addr)
    {
      add_hostname(in,name);
      DBUG_RETURN(name);
    }
  }
  DBUG_PRINT("error",("Couldn't verify hostname with gethostbyname"));
  my_free(name,MYF(0));

add_wrong_ip_and_return:
  add_wrong_ip(in);
  DBUG_RETURN(0);
}
<commit_msg>Manual merge of 5.0.10a back to the general tree.<commit_after>/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/*
  Get hostname for an IP.  Hostnames are checked with reverse name lookup and
  checked that they doesn't resemble an ip.
*/

#include "mysql_priv.h"
#include "hash_filo.h"
#include <m_ctype.h>
#ifdef	__cplusplus
extern "C" {					// Because of SCO 3.2V4.2
#endif
#if !defined( __WIN__) && !defined(OS2)
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#include <netdb.h>
#include <sys/utsname.h>
#endif // __WIN__
#ifdef	__cplusplus
}
#endif

class host_entry :public hash_filo_element
{
public:
  char	 ip[sizeof(((struct in_addr *) 0)->s_addr)];
  uint	 errors;
  char	 *hostname;
};

static hash_filo *hostname_cache;
static pthread_mutex_t LOCK_hostname;

void hostname_cache_refresh()
{
  hostname_cache->clear();
}

bool hostname_cache_init()
{
  host_entry tmp;
  uint offset= (uint) ((char*) (&tmp.ip) - (char*) &tmp);
  if (!(hostname_cache=new hash_filo(HOST_CACHE_SIZE, offset,
				     sizeof(struct in_addr),NULL,
				     (hash_free_key) free,
				     &my_charset_latin1)))
    return 1;
  hostname_cache->clear();
  (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
  return 0;
}

void hostname_cache_free()
{
  if (hostname_cache)
  {
    (void) pthread_mutex_destroy(&LOCK_hostname);
    delete hostname_cache;
    hostname_cache= 0;
  }
}

static void add_hostname(struct in_addr *in,const char *name)
{
  if (!(specialflag & SPECIAL_NO_HOST_CACHE))
  {
    VOID(pthread_mutex_lock(&hostname_cache->lock));
    host_entry *entry;
    if (!(entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    {
      uint length=name ? (uint) strlen(name) : 0;

      if ((entry=(host_entry*) malloc(sizeof(host_entry)+length+1)))
      {
	char *new_name;
	memcpy_fixed(&entry->ip, &in->s_addr, sizeof(in->s_addr));
	if (length)
	  memcpy(new_name= (char *) (entry+1), name, length+1);
	else
	  new_name=0;
	entry->hostname=new_name;
	entry->errors=0;
	(void) hostname_cache->add(entry);
      }
    }
    VOID(pthread_mutex_unlock(&hostname_cache->lock));
  }
}

inline void add_wrong_ip(struct in_addr *in)
{
  add_hostname(in,NullS);
}

void inc_host_errors(struct in_addr *in)
{
  VOID(pthread_mutex_lock(&hostname_cache->lock));
  host_entry *entry;
  if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    entry->errors++;
  VOID(pthread_mutex_unlock(&hostname_cache->lock));
}

void reset_host_errors(struct in_addr *in)
{
  VOID(pthread_mutex_lock(&hostname_cache->lock));
  host_entry *entry;
  if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    entry->errors=0;
  VOID(pthread_mutex_unlock(&hostname_cache->lock));
}

/* Deal with systems that don't defined INADDR_LOOPBACK */
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001UL
#endif

my_string ip_to_hostname(struct in_addr *in, uint *errors)
{
  uint i;
  host_entry *entry;
  DBUG_ENTER("ip_to_hostname");
  *errors=0;

  /* We always treat the loopback address as "localhost". */
  if (in->s_addr == htonl(INADDR_LOOPBACK))   // is expanded inline by gcc
    DBUG_RETURN((char *)my_localhost);

  /* Check first if we have name in cache */
  if (!(specialflag & SPECIAL_NO_HOST_CACHE))
  {
    VOID(pthread_mutex_lock(&hostname_cache->lock));
    if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    {
      char *name;
      if (!entry->hostname)
	name=0;					// Don't allow connection
      else
	name=my_strdup(entry->hostname,MYF(0));
      *errors= entry->errors;
      VOID(pthread_mutex_unlock(&hostname_cache->lock));
      DBUG_RETURN(name);
    }
    VOID(pthread_mutex_unlock(&hostname_cache->lock));
  }

  struct hostent *hp, *check;
  char *name;
  LINT_INIT(check);
#if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
  char buff[GETHOSTBYADDR_BUFF_SIZE],buff2[GETHOSTBYNAME_BUFF_SIZE];
  int tmp_errno;
  struct hostent tmp_hostent, tmp_hostent2;
#ifdef HAVE_purify
  bzero(buff,sizeof(buff));		// Bug in purify
#endif
  if (!(hp=gethostbyaddr_r((char*) in,sizeof(*in),
			   AF_INET,
			   &tmp_hostent,buff,sizeof(buff),&tmp_errno)))
  {
    DBUG_PRINT("error",("gethostbyaddr_r returned %d",tmp_errno));
    return 0;
  }
  if (!(check=my_gethostbyname_r(hp->h_name,&tmp_hostent2,buff2,sizeof(buff2),
				 &tmp_errno)))
  {
    DBUG_PRINT("error",("gethostbyname_r returned %d",tmp_errno));
    /*
      Don't cache responses when the DSN server is down, as otherwise
      transient DNS failure may leave any number of clients (those
      that attempted to connect during the outage) unable to connect
      indefinitely.
    */
    if (tmp_errno == HOST_NOT_FOUND || tmp_errno == NO_DATA)
      add_wrong_ip(in);
    my_gethostbyname_r_free();
    DBUG_RETURN(0);
  }
  if (!hp->h_name[0])
  {
    DBUG_PRINT("error",("Got an empty hostname"));
    add_wrong_ip(in);
    my_gethostbyname_r_free();
    DBUG_RETURN(0);				// Don't allow empty hostnames
  }
  if (!(name=my_strdup(hp->h_name,MYF(0))))
  {
    my_gethostbyname_r_free();
    DBUG_RETURN(0);				// out of memory
  }
  my_gethostbyname_r_free();
#else
  VOID(pthread_mutex_lock(&LOCK_hostname));
  if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET)))
  {
    VOID(pthread_mutex_unlock(&LOCK_hostname));
    DBUG_PRINT("error",("gethostbyaddr returned %d",errno));

    if (errno == HOST_NOT_FOUND || errno == NO_DATA)
      goto add_wrong_ip_and_return;
    /* Failure, don't cache responce */
    DBUG_RETURN(0);
  }
  if (!hp->h_name[0])				// Don't allow empty hostnames
  {
    VOID(pthread_mutex_unlock(&LOCK_hostname));
    DBUG_PRINT("error",("Got an empty hostname"));
    goto add_wrong_ip_and_return;
  }
  if (!(name=my_strdup(hp->h_name,MYF(0))))
  {
    VOID(pthread_mutex_unlock(&LOCK_hostname));
    DBUG_RETURN(0);				// out of memory
  }
  check=gethostbyname(name);
  VOID(pthread_mutex_unlock(&LOCK_hostname));
  if (!check)
  {
    DBUG_PRINT("error",("gethostbyname returned %d",errno));
    my_free(name,MYF(0));
    DBUG_RETURN(0);
  }
#endif

  /* Don't accept hostnames that starts with digits because they may be
     false ip:s */
  if (my_isdigit(&my_charset_latin1,name[0]))
  {
    char *pos;
    for (pos= name+1 ; my_isdigit(&my_charset_latin1,*pos); pos++) ;
    if (*pos == '.')
    {
      DBUG_PRINT("error",("mysqld doesn't accept hostnames that starts with a number followed by a '.'"));
      my_free(name,MYF(0));
      goto add_wrong_ip_and_return;
    }
  }

  /* Check that 'gethostbyname' returned the used ip */
  for (i=0; check->h_addr_list[i]; i++)
  {
    if (*(uint32*)(check->h_addr_list)[i] == in->s_addr)
    {
      add_hostname(in,name);
      DBUG_RETURN(name);
    }
  }
  DBUG_PRINT("error",("Couldn't verify hostname with gethostbyname"));
  my_free(name,MYF(0));

add_wrong_ip_and_return:
  add_wrong_ip(in);
  DBUG_RETURN(0);
}
<|endoftext|>


<commit_before>#include "settingswindow.h"
#include "ui_settingswindow.h"
#include "imagewidget.h"
#include <QFileDialog>

SettingsWindow::SettingsWindow(QSettings &Settings, QWidget *parent) : QDialog(parent), ui(new Ui::SettingsWindow), settings(Settings){
    ui->setupUi(this);

    ui->defaultRendererComboBox->addItems(ImageWidget::drawModeNames.keys());

    ui->defaultRendererComboBox->setCurrentIndex(ui->defaultRendererComboBox->findText(settings.value(defaultrender).toString()));
    ui->startFullscreenCheckBox->setChecked(settings.value(startfullscreen).toBool());
    ui->swapLeftRightCheckBox->setChecked(settings.value(swapLR).toBool());
    ui->startupDirectoryLineEdit->setText(settings.value(startupdirectory).toString());

    // check if it exists so that it will default to true if it does not.
    if(settings.contains(showmenubar)){
        ui->showMenuBarCheckBox->setChecked(settings.value(showmenubar).toBool());
    }
    if(settings.contains(filedialogstartup)){
        ui->fileDialogStartupCheckBox->setChecked(settings.value(filedialogstartup).toBool());
    }

    ui->disableDragDropCheckBox->setChecked(settings.value(disabledragdrop).toBool());
}

SettingsWindow::~SettingsWindow(){
    delete ui;
}

void SettingsWindow::accept(){
    settings.setValue(defaultrender, ui->defaultRendererComboBox->currentText());
    settings.setValue(startfullscreen, ui->startFullscreenCheckBox->isChecked());
    settings.setValue(swapLR, ui->swapLeftRightCheckBox->isChecked());
    settings.setValue(startupdirectory, ui->startupDirectoryLineEdit->text());
    settings.setValue(showmenubar, ui->showMenuBarCheckBox->isChecked());
    settings.setValue(filedialogstartup, ui->fileDialogStartupCheckBox->isChecked());
    settings.setValue(disabledragdrop, ui->disableDragDropCheckBox->isChecked());
    QDialog::accept();
}

void SettingsWindow::on_buttonBox_clicked(QAbstractButton *button){
    if(button->text() == "Restore Defaults"){
        QMessageBox msgbox(this);
        msgbox.setText("Are you sure you wish to reset to default settings?");
        msgbox.setWindowTitle("Are You Sure?");
        msgbox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
        msgbox.setDefaultButton(QMessageBox::Yes);
        msgbox.setIcon(QMessageBox::Warning);

        if(msgbox.exec() == QMessageBox::Yes){
            settings.clear();

            ui->defaultRendererComboBox->setCurrentIndex(-1);
            ui->startFullscreenCheckBox->setChecked(false);
            ui->swapLeftRightCheckBox->setChecked(false);
            ui->showMenuBarCheckBox->setChecked(true);
            ui->fileDialogStartupCheckBox->setChecked(true);
            ui->disableDragDropCheckBox->setChecked(false);
            ui->startupDirectoryLineEdit->setText("");
        }
    }
}

void SettingsWindow::on_startupDirectoryBrowsePushButton_clicked(){
    QString directory = QFileDialog::getExistingDirectory(this, tr("Choose Directory"), ui->startupDirectoryLineEdit->text());
    if(directory != ""){
        ui->startupDirectoryLineEdit->setText(directory);
    }
}

const QString SettingsWindow::defaultrender     = "defaultrender";
const QString SettingsWindow::startfullscreen   = "startfullscreen";
const QString SettingsWindow::swapLR            = "swapLR";
const QString SettingsWindow::startupdirectory  = "startupdirectory";
const QString SettingsWindow::showmenubar       = "showmenubar";
const QString SettingsWindow::filedialogstartup = "filedialogstartup";
const QString SettingsWindow::disabledragdrop   = "disabledragdrop";
<commit_msg>use QMessageBox::warning() for restore default settings warning message.<commit_after>#include "settingswindow.h"
#include "ui_settingswindow.h"
#include "imagewidget.h"
#include <QFileDialog>

SettingsWindow::SettingsWindow(QSettings &Settings, QWidget *parent) : QDialog(parent), ui(new Ui::SettingsWindow), settings(Settings){
    ui->setupUi(this);

    ui->defaultRendererComboBox->addItems(ImageWidget::drawModeNames.keys());

    ui->defaultRendererComboBox->setCurrentIndex(ui->defaultRendererComboBox->findText(settings.value(defaultrender).toString()));
    ui->startFullscreenCheckBox->setChecked(settings.value(startfullscreen).toBool());
    ui->swapLeftRightCheckBox->setChecked(settings.value(swapLR).toBool());
    ui->startupDirectoryLineEdit->setText(settings.value(startupdirectory).toString());

    // check if it exists so that it will default to true if it does not.
    if(settings.contains(showmenubar)){
        ui->showMenuBarCheckBox->setChecked(settings.value(showmenubar).toBool());
    }
    if(settings.contains(filedialogstartup)){
        ui->fileDialogStartupCheckBox->setChecked(settings.value(filedialogstartup).toBool());
    }

    ui->disableDragDropCheckBox->setChecked(settings.value(disabledragdrop).toBool());
}

SettingsWindow::~SettingsWindow(){
    delete ui;
}

void SettingsWindow::accept(){
    settings.setValue(defaultrender, ui->defaultRendererComboBox->currentText());
    settings.setValue(startfullscreen, ui->startFullscreenCheckBox->isChecked());
    settings.setValue(swapLR, ui->swapLeftRightCheckBox->isChecked());
    settings.setValue(startupdirectory, ui->startupDirectoryLineEdit->text());
    settings.setValue(showmenubar, ui->showMenuBarCheckBox->isChecked());
    settings.setValue(filedialogstartup, ui->fileDialogStartupCheckBox->isChecked());
    settings.setValue(disabledragdrop, ui->disableDragDropCheckBox->isChecked());
    QDialog::accept();
}

void SettingsWindow::on_buttonBox_clicked(QAbstractButton *button){
    if(button->text() == "Restore Defaults"){
        if(QMessageBox::warning(this, tr("Are You Sure?"), tr("Are you sure you wish to reset to default settings?"),
                                QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes){
            settings.clear();

            ui->defaultRendererComboBox->setCurrentIndex(-1);
            ui->startFullscreenCheckBox->setChecked(false);
            ui->swapLeftRightCheckBox->setChecked(false);
            ui->showMenuBarCheckBox->setChecked(true);
            ui->fileDialogStartupCheckBox->setChecked(true);
            ui->disableDragDropCheckBox->setChecked(false);
            ui->startupDirectoryLineEdit->setText("");
        }
    }
}

void SettingsWindow::on_startupDirectoryBrowsePushButton_clicked(){
    QString directory = QFileDialog::getExistingDirectory(this, tr("Choose Directory"), ui->startupDirectoryLineEdit->text());
    if(directory != ""){
        ui->startupDirectoryLineEdit->setText(directory);
    }
}

const QString SettingsWindow::defaultrender     = "defaultrender";
const QString SettingsWindow::startfullscreen   = "startfullscreen";
const QString SettingsWindow::swapLR            = "swapLR";
const QString SettingsWindow::startupdirectory  = "startupdirectory";
const QString SettingsWindow::showmenubar       = "showmenubar";
const QString SettingsWindow::filedialogstartup = "filedialogstartup";
const QString SettingsWindow::disabledragdrop   = "disabledragdrop";
<|endoftext|>


<commit_before>#include "Channel.hpp"
#include "Message.hpp"
#include "Network.hpp"
#include "PawnDispatcher.hpp"
#include "Logger.hpp"
#include "Guild.hpp"
#include "utils.hpp"

#include "fmt/format.h"

#undef SendMessage // Windows at its finest

Channel::Channel(ChannelId_t pawn_id, json const &data, GuildId_t guild_id) :
	m_PawnId(pawn_id)
{
	std::underlying_type<Type>::type type;
	if (!utils::TryGetJsonValue(data, type, "type")
		|| !utils::TryGetJsonValue(data, m_Id, "id"))
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"invalid JSON: expected \"type\" and \"id\" in \"{}\"", data.dump());
		return;
	}

	m_Type = static_cast<Type>(type);
	if (m_Type != Type::DM && m_Type != Type::GROUP_DM && m_Type < Type::GUILD_NEWS)
	{
		if (guild_id != 0)
		{
			m_GuildId = guild_id;
		}
		else
		{
			std::string guild_id_str;
			if (utils::TryGetJsonValue(data, guild_id_str, "guild_id"))
			{
				Guild_t const &guild = GuildManager::Get()->FindGuildById(guild_id_str);
				m_GuildId = guild->GetPawnId();
				guild->AddChannel(pawn_id);
			}
			else
			{
				Logger::Get()->Log(LogLevel::ERROR,
					"invalid JSON: expected \"guild_id\" in \"{}\"", data.dump());
			}
		}
		Update(data);
	}
}

void Channel::Update(json const &data)
{
	std::string name, topic;
	int position;
	bool is_nsfw;
	bool
		update_name = utils::TryGetJsonValue(data, name, "name"),
		update_topic = utils::TryGetJsonValue(data, topic, "topic"),
		update_position = utils::TryGetJsonValue(data, position, "position"),
		update_nsfw = utils::TryGetJsonValue(data, is_nsfw, "nsfw");

	if (update_name)
		m_Name = name;
	if (update_topic)
		m_Topic = topic;
	if (update_position)
		m_Position = position;
	if (update_nsfw)
		m_IsNsfw = is_nsfw;
}

void Channel::UpdateParentChannel(Snowflake_t const &parent_id)
{
	Channel_t const &channel = ChannelManager::Get()->FindChannelById(parent_id);
	if (!channel)
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"can't update parent channel \"parent_id\" not cached \"{}\"", parent_id);
		return;
	}
	m_ParentId = channel->GetPawnId();
}

void Channel::SendMessage(std::string &&msg, pawn_cb::Callback_t &&cb)
{
	json data = {
		{ "content", std::move(msg) }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Http::ResponseCb_t response_cb;
	if (cb)
	{
		response_cb = [cb](Http::Response response)
		{
			Logger::Get()->Log(LogLevel::DEBUG,
				"channel message create response: status {}; body: {}; add: {}",
				response.status, response.body, response.additional_data);
			if (response.status / 100 == 2) // success
			{
				auto msg_json = json::parse(response.body);
				PawnDispatcher::Get()->Dispatch([cb, msg_json]() mutable
				{
					auto msg = MessageManager::Get()->Create(msg_json);
					if (msg != INVALID_MESSAGE_ID)
					{
						MessageManager::Get()->SetCreatedMessageId(msg);
						cb->Execute();
						MessageManager::Get()->SetCreatedMessageId(INVALID_MESSAGE_ID);

						MessageManager::Get()->Delete(msg);
					}
				});
			}
		};
	}

	Network::Get()->Http().Post(fmt::format("/channels/{:s}/messages", GetId()), json_str,
		std::move(response_cb));
}

void Channel::SetChannelName(std::string const &name)
{
	json data = {
		{ "name", name }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelTopic(std::string const &topic)
{
	json data = {
		{ "topic", topic }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelPosition(int const position)
{
	json data = {
		{ "position", position }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelNsfw(bool const is_nsfw)
{
	json data = {
		{ "nsfw", is_nsfw }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelParentCategory(Channel_t const &parent)
{
	if (parent->GetType() != Type::GUILD_CATEGORY)
		return;

	json data = {
		{ "parent_id", parent->GetId() }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::DeleteChannel()
{
	Network::Get()->Http().Delete(fmt::format("/channels/{:s}", GetId()));
}

void ChannelManager::Initialize()
{
	assert(m_Initialized != m_InitValue);

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::CHANNEL_CREATE, [](json const &data)
	{
		PawnDispatcher::Get()->Dispatch([data]() mutable
		{
			auto const channel_id = ChannelManager::Get()->AddChannel(data);
			if (channel_id == INVALID_CHANNEL_ID)
				return;

			// forward DCC_OnChannelCreate(DCC_Channel:channel);
			pawn_cb::Error error;
			pawn_cb::Callback::CallFirst(error, "DCC_OnChannelCreate", channel_id);
		});
	});

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::CHANNEL_UPDATE, [](json const &data)
	{
		PawnDispatcher::Get()->Dispatch([data]() mutable
		{
			Snowflake_t sfid;
			if (!utils::TryGetJsonValue(data, sfid, "id"))
			{
				Logger::Get()->Log(LogLevel::ERROR,
					"invalid JSON: expected \"id\" in \"{}\"", data.dump());
				return;
			}

			Channel_t const &channel = ChannelManager::Get()->FindChannelById(sfid);
			if (!channel)
			{
				Logger::Get()->Log(LogLevel::ERROR,
					"can't update channel: channel id \"{}\" not cached", sfid);
				return;
			}

			channel->Update(data);
			if (channel->GetType() != Channel::Type::GUILD_CATEGORY)
			{
				Snowflake_t parent_id;
				if (!utils::TryGetJsonValue(data, parent_id, "parent_id"))
				{
					Logger::Get()->Log(LogLevel::ERROR, "invalid JSON: expected \"parent_id\" in \"{}\"", data.dump());
					return;
				}
				channel->UpdateParentChannel(parent_id);
			}

			// forward DCC_OnChannelUpdate(DCC_Channel:channel);
			pawn_cb::Error error;
			pawn_cb::Callback::CallFirst(error, "DCC_OnChannelUpdate", channel->GetPawnId());
		});
	});

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::CHANNEL_DELETE, [](json const &data)
	{
		ChannelManager::Get()->DeleteChannel(data);
	});

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::READY, [this](json const &data)
	{
		static const char *PRIVATE_CHANNEL_KEY = "private_channels";
		if (utils::IsValidJson(data, PRIVATE_CHANNEL_KEY, json::value_t::array))
		{
			for (auto const &c : data.at(PRIVATE_CHANNEL_KEY))
				AddChannel(c);
		}
		else
		{
			Logger::Get()->Log(LogLevel::ERROR,
				"invalid JSON: expected \"{}\" in \"{}\"", PRIVATE_CHANNEL_KEY, data.dump());
		}
		m_Initialized++;
	});
}

bool ChannelManager::IsInitialized()
{
	return m_Initialized == m_InitValue;
}

bool ChannelManager::CreateGuildChannel(Guild_t const &guild,
	std::string const &name, Channel::Type type, pawn_cb::Callback_t &&cb)
{
	json data = {
		{ "name", name },
		{ "type", static_cast<int>(type) }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
	{
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);
		return false;
	}

	Network::Get()->Http().Post(fmt::format("/guilds/{:s}/channels", guild->GetId()), json_str,
		[this, cb](Http::Response r)
	{
		Logger::Get()->Log(LogLevel::DEBUG,
			"channel create response: status {}; body: {}; add: {}",
			r.status, r.body, r.additional_data);
		if (r.status / 100 == 2) // success
		{
			auto const channel_id = ChannelManager::Get()->AddChannel(json::parse(r.body));
			if (channel_id == INVALID_CHANNEL_ID)
				return;

			if (cb)
			{
				PawnDispatcher::Get()->Dispatch([=]()
				{
					m_CreatedChannelId = channel_id;
					cb->Execute();
					m_CreatedChannelId = INVALID_CHANNEL_ID;
				});
			}
		}
	});

	return true;
}

ChannelId_t ChannelManager::AddChannel(json const &data, GuildId_t guild_id/* = 0*/)
{
	Snowflake_t sfid;
	if (!utils::TryGetJsonValue(data, sfid, "id"))
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"invalid JSON: expected \"id\" in \"{}\"", data.dump());
		return INVALID_CHANNEL_ID;
	}

	Channel_t const &channel = FindChannelById(sfid);
	if (channel)
		return channel->GetPawnId(); // channel already exists

	ChannelId_t id = 1;
	while (m_Channels.find(id) != m_Channels.end())
		++id;

	if (!m_Channels.emplace(id, Channel_t(new Channel(id, data, guild_id))).second)
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"can't create channel: duplicate key '{}'", id);
		return INVALID_CHANNEL_ID;
	}

	Logger::Get()->Log(LogLevel::INFO, "successfully added channel with id '{}'", id);
	return id;
}

void ChannelManager::DeleteChannel(json const &data)
{
	Snowflake_t sfid;
	if (!utils::TryGetJsonValue(data, sfid, "id"))
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"invalid JSON: expected \"id\" in \"{}\"", data.dump());
		return;
	}

	PawnDispatcher::Get()->Dispatch([this, sfid]()
	{
		Channel_t const &channel = FindChannelById(sfid);
		if (!channel)
		{
			Logger::Get()->Log(LogLevel::ERROR,
				"can't delete channel: channel id \"{}\" not cached", sfid);
			return;
		}

		// forward DCC_OnChannelDelete(DCC_Channel:channel);
		pawn_cb::Error error;
		pawn_cb::Callback::CallFirst(error, "DCC_OnChannelDelete", channel->GetPawnId());

		Guild_t const &guild = GuildManager::Get()->FindGuild(channel->GetGuildId());
		if (guild)
			guild->RemoveChannel(channel->GetPawnId());

		m_Channels.erase(channel->GetPawnId());
	});

}

Channel_t const &ChannelManager::FindChannel(ChannelId_t id)
{
	static Channel_t invalid_channel;
	auto it = m_Channels.find(id);
	if (it == m_Channels.end())
		return invalid_channel;
	return it->second;
}

Channel_t const &ChannelManager::FindChannelByName(std::string const &name)
{
	static Channel_t invalid_channel;
	for (auto const &c : m_Channels)
	{
		Channel_t const &channel = c.second;
		if (channel->GetName().compare(name) == 0)
			return channel;
	}
	return invalid_channel;
}

Channel_t const &ChannelManager::FindChannelById(Snowflake_t const &sfid)
{
	static Channel_t invalid_channel;
	for (auto const &c : m_Channels)
	{
		Channel_t const &channel = c.second;
		if (channel->GetId().compare(sfid) == 0)
			return channel;
	}
	return invalid_channel;
}
<commit_msg>Fix ambiguous type checking<commit_after>#include "Channel.hpp"
#include "Message.hpp"
#include "Network.hpp"
#include "PawnDispatcher.hpp"
#include "Logger.hpp"
#include "Guild.hpp"
#include "utils.hpp"

#include "fmt/format.h"

#undef SendMessage // Windows at its finest

Channel::Channel(ChannelId_t pawn_id, json const &data, GuildId_t guild_id) :
	m_PawnId(pawn_id)
{
	std::underlying_type<Type>::type type;
	if (!utils::TryGetJsonValue(data, type, "type")
		|| !utils::TryGetJsonValue(data, m_Id, "id"))
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"invalid JSON: expected \"type\" and \"id\" in \"{}\"", data.dump());
		return;
	}

	m_Type = static_cast<Type>(type);
	if (m_Type == Type::GUILD_TEXT || m_Type == Type::GUILD_VOICE || m_Type == Type::GUILD_CATEGORY)
	{
		if (guild_id != 0)
		{
			m_GuildId = guild_id;
		}
		else
		{
			std::string guild_id_str;
			if (utils::TryGetJsonValue(data, guild_id_str, "guild_id"))
			{
				Guild_t const &guild = GuildManager::Get()->FindGuildById(guild_id_str);
				m_GuildId = guild->GetPawnId();
				guild->AddChannel(pawn_id);
			}
			else
			{
				Logger::Get()->Log(LogLevel::ERROR,
					"invalid JSON: expected \"guild_id\" in \"{}\"", data.dump());
			}
		}
		Update(data);
	}
}

void Channel::Update(json const &data)
{
	std::string name, topic;
	int position;
	bool is_nsfw;
	bool
		update_name = utils::TryGetJsonValue(data, name, "name"),
		update_topic = utils::TryGetJsonValue(data, topic, "topic"),
		update_position = utils::TryGetJsonValue(data, position, "position"),
		update_nsfw = utils::TryGetJsonValue(data, is_nsfw, "nsfw");

	if (update_name)
		m_Name = name;
	if (update_topic)
		m_Topic = topic;
	if (update_position)
		m_Position = position;
	if (update_nsfw)
		m_IsNsfw = is_nsfw;
}

void Channel::UpdateParentChannel(Snowflake_t const &parent_id)
{
	Channel_t const &channel = ChannelManager::Get()->FindChannelById(parent_id);
	if (!channel)
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"can't update parent channel \"parent_id\" not cached \"{}\"", parent_id);
		return;
	}
	m_ParentId = channel->GetPawnId();
}

void Channel::SendMessage(std::string &&msg, pawn_cb::Callback_t &&cb)
{
	json data = {
		{ "content", std::move(msg) }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Http::ResponseCb_t response_cb;
	if (cb)
	{
		response_cb = [cb](Http::Response response)
		{
			Logger::Get()->Log(LogLevel::DEBUG,
				"channel message create response: status {}; body: {}; add: {}",
				response.status, response.body, response.additional_data);
			if (response.status / 100 == 2) // success
			{
				auto msg_json = json::parse(response.body);
				PawnDispatcher::Get()->Dispatch([cb, msg_json]() mutable
				{
					auto msg = MessageManager::Get()->Create(msg_json);
					if (msg != INVALID_MESSAGE_ID)
					{
						MessageManager::Get()->SetCreatedMessageId(msg);
						cb->Execute();
						MessageManager::Get()->SetCreatedMessageId(INVALID_MESSAGE_ID);

						MessageManager::Get()->Delete(msg);
					}
				});
			}
		};
	}

	Network::Get()->Http().Post(fmt::format("/channels/{:s}/messages", GetId()), json_str,
		std::move(response_cb));
}

void Channel::SetChannelName(std::string const &name)
{
	json data = {
		{ "name", name }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelTopic(std::string const &topic)
{
	json data = {
		{ "topic", topic }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelPosition(int const position)
{
	json data = {
		{ "position", position }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelNsfw(bool const is_nsfw)
{
	json data = {
		{ "nsfw", is_nsfw }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelParentCategory(Channel_t const &parent)
{
	if (parent->GetType() != Type::GUILD_CATEGORY)
		return;

	json data = {
		{ "parent_id", parent->GetId() }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::DeleteChannel()
{
	Network::Get()->Http().Delete(fmt::format("/channels/{:s}", GetId()));
}

void ChannelManager::Initialize()
{
	assert(m_Initialized != m_InitValue);

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::CHANNEL_CREATE, [](json const &data)
	{
		PawnDispatcher::Get()->Dispatch([data]() mutable
		{
			auto const channel_id = ChannelManager::Get()->AddChannel(data);
			if (channel_id == INVALID_CHANNEL_ID)
				return;

			// forward DCC_OnChannelCreate(DCC_Channel:channel);
			pawn_cb::Error error;
			pawn_cb::Callback::CallFirst(error, "DCC_OnChannelCreate", channel_id);
		});
	});

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::CHANNEL_UPDATE, [](json const &data)
	{
		PawnDispatcher::Get()->Dispatch([data]() mutable
		{
			Snowflake_t sfid;
			if (!utils::TryGetJsonValue(data, sfid, "id"))
			{
				Logger::Get()->Log(LogLevel::ERROR,
					"invalid JSON: expected \"id\" in \"{}\"", data.dump());
				return;
			}

			Channel_t const &channel = ChannelManager::Get()->FindChannelById(sfid);
			if (!channel)
			{
				Logger::Get()->Log(LogLevel::ERROR,
					"can't update channel: channel id \"{}\" not cached", sfid);
				return;
			}

			channel->Update(data);
			if (channel->GetType() != Channel::Type::GUILD_CATEGORY)
			{
				Snowflake_t parent_id;
				if (!utils::TryGetJsonValue(data, parent_id, "parent_id"))
				{
					Logger::Get()->Log(LogLevel::ERROR, "invalid JSON: expected \"parent_id\" in \"{}\"", data.dump());
					return;
				}
				channel->UpdateParentChannel(parent_id);
			}

			// forward DCC_OnChannelUpdate(DCC_Channel:channel);
			pawn_cb::Error error;
			pawn_cb::Callback::CallFirst(error, "DCC_OnChannelUpdate", channel->GetPawnId());
		});
	});

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::CHANNEL_DELETE, [](json const &data)
	{
		ChannelManager::Get()->DeleteChannel(data);
	});

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::READY, [this](json const &data)
	{
		static const char *PRIVATE_CHANNEL_KEY = "private_channels";
		if (utils::IsValidJson(data, PRIVATE_CHANNEL_KEY, json::value_t::array))
		{
			for (auto const &c : data.at(PRIVATE_CHANNEL_KEY))
				AddChannel(c);
		}
		else
		{
			Logger::Get()->Log(LogLevel::ERROR,
				"invalid JSON: expected \"{}\" in \"{}\"", PRIVATE_CHANNEL_KEY, data.dump());
		}
		m_Initialized++;
	});
}

bool ChannelManager::IsInitialized()
{
	return m_Initialized == m_InitValue;
}

bool ChannelManager::CreateGuildChannel(Guild_t const &guild,
	std::string const &name, Channel::Type type, pawn_cb::Callback_t &&cb)
{
	json data = {
		{ "name", name },
		{ "type", static_cast<int>(type) }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
	{
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);
		return false;
	}

	Network::Get()->Http().Post(fmt::format("/guilds/{:s}/channels", guild->GetId()), json_str,
		[this, cb](Http::Response r)
	{
		Logger::Get()->Log(LogLevel::DEBUG,
			"channel create response: status {}; body: {}; add: {}",
			r.status, r.body, r.additional_data);
		if (r.status / 100 == 2) // success
		{
			auto const channel_id = ChannelManager::Get()->AddChannel(json::parse(r.body));
			if (channel_id == INVALID_CHANNEL_ID)
				return;

			if (cb)
			{
				PawnDispatcher::Get()->Dispatch([=]()
				{
					m_CreatedChannelId = channel_id;
					cb->Execute();
					m_CreatedChannelId = INVALID_CHANNEL_ID;
				});
			}
		}
	});

	return true;
}

ChannelId_t ChannelManager::AddChannel(json const &data, GuildId_t guild_id/* = 0*/)
{
	Snowflake_t sfid;
	if (!utils::TryGetJsonValue(data, sfid, "id"))
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"invalid JSON: expected \"id\" in \"{}\"", data.dump());
		return INVALID_CHANNEL_ID;
	}

	Channel_t const &channel = FindChannelById(sfid);
	if (channel)
		return channel->GetPawnId(); // channel already exists

	ChannelId_t id = 1;
	while (m_Channels.find(id) != m_Channels.end())
		++id;

	if (!m_Channels.emplace(id, Channel_t(new Channel(id, data, guild_id))).second)
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"can't create channel: duplicate key '{}'", id);
		return INVALID_CHANNEL_ID;
	}

	Logger::Get()->Log(LogLevel::INFO, "successfully added channel with id '{}'", id);
	return id;
}

void ChannelManager::DeleteChannel(json const &data)
{
	Snowflake_t sfid;
	if (!utils::TryGetJsonValue(data, sfid, "id"))
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"invalid JSON: expected \"id\" in \"{}\"", data.dump());
		return;
	}

	PawnDispatcher::Get()->Dispatch([this, sfid]()
	{
		Channel_t const &channel = FindChannelById(sfid);
		if (!channel)
		{
			Logger::Get()->Log(LogLevel::ERROR,
				"can't delete channel: channel id \"{}\" not cached", sfid);
			return;
		}

		// forward DCC_OnChannelDelete(DCC_Channel:channel);
		pawn_cb::Error error;
		pawn_cb::Callback::CallFirst(error, "DCC_OnChannelDelete", channel->GetPawnId());

		Guild_t const &guild = GuildManager::Get()->FindGuild(channel->GetGuildId());
		if (guild)
			guild->RemoveChannel(channel->GetPawnId());

		m_Channels.erase(channel->GetPawnId());
	});

}

Channel_t const &ChannelManager::FindChannel(ChannelId_t id)
{
	static Channel_t invalid_channel;
	auto it = m_Channels.find(id);
	if (it == m_Channels.end())
		return invalid_channel;
	return it->second;
}

Channel_t const &ChannelManager::FindChannelByName(std::string const &name)
{
	static Channel_t invalid_channel;
	for (auto const &c : m_Channels)
	{
		Channel_t const &channel = c.second;
		if (channel->GetName().compare(name) == 0)
			return channel;
	}
	return invalid_channel;
}

Channel_t const &ChannelManager::FindChannelById(Snowflake_t const &sfid)
{
	static Channel_t invalid_channel;
	for (auto const &c : m_Channels)
	{
		Channel_t const &channel = c.second;
		if (channel->GetId().compare(sfid) == 0)
			return channel;
	}
	return invalid_channel;
}
<|endoftext|>


<commit_before>/*
===========================================================================

Daemon GPL Source Code
Copyright (C) 2013 Unvanquished Developers

This file is part of the Daemon GPL Source Code (Daemon Source Code).

Daemon Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Daemon Source Code 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with Daemon Source Code.  If not, see <http://www.gnu.org/licenses/>.

===========================================================================
*/

#include "Command.h"

#include "../engine/qcommon/qcommon.h"
#include "../engine/framework/CommandSystem.h"

namespace Cmd {

    static CmdBase* firstCommand = nullptr;

    std::string Escape(const std::string& text, bool quote) {
        std::string res;

        if (quote) {
            res = "\"";
        }

        for (int i = 0; i < text.size(); i ++) {
            char c = text[i];

            bool commentStart = (i < text.size() + 1) and (c == '/') and (text[i + 1] == '/' or text[i + 1] == '*');
            bool escapeNotQuote = (c <= ' ' and c > 0) or (c == ';') or commentStart;
            bool escape = (c == '$') or (c == '"') or (c == '\\');

            if ((not quote and escapeNotQuote) or escape) {
                res.push_back('\\');
            }
            res.push_back(c);
        }

        if (quote) {
            res += "\"";
        }

        return res;
    }

    void Tokenize(const std::string& text, std::vector<std::string>& tokens, std::vector<int>& tokenStarts) {
        const char* raw_text = text.c_str();
        std::string token;
        int tokenStart = 0;

        int pos = 0;
        bool inToken = false;

        while (pos < text.size()) {
            char c = text[pos ++];

            //Avoid whitespaces
            if (c <= ' ') {
                continue;
            }

            //Check for comments
            if (c == '/' and pos < text.size()) {
                char nextC = text[pos];

                // a // finishes the text and the token
                if (nextC == '/') {
                    break;

                // if it is a /* jump to the end of it
                } else if (nextC == '*'){
                    pos ++; //avoid /*/
                    while (pos < text.size() - 1 and not (text[pos] == '*' and text[pos + 1] == '/') ) {
                        pos ++;
                    }
                    pos += 2;

                    //The comment doesn't end
                    if (pos >= text.size()) {
                        break;
                    }
                    continue;
                }
            }

            //We have something that is not whitespace nor comments so it must be a token

            if (c == '"' and pos < text.size()) {
                //This is a quoted token
                bool escaped = false;

                c = text[pos ++]; //skips the "

                //Add all the characters (except the escape \) until the last unescaped "
                while (pos < text.size() and (escaped or c !='"')) {
                    if (escaped or c != '\\') {
                        token.push_back(c);
                        escaped = false;
                    } else if (not escaped) { // c = \ here
                        escaped = true;
                    }
                    c = text[pos ++];
                }

                tokens.push_back(token);
                tokenStarts.push_back(tokenStart);
                token = "";
                tokenStart = pos;

            } else {
                //An unquoted string, until the next " or comment start
                bool escaped = false;
                bool finished;
                bool startsSomethingElse;

                do {
                    if (escaped or c != '\\') {
                        token.push_back(c);
                        escaped = false;
                    } else if (not escaped) { // c = \ here
                        escaped = true;
                    }
                    c = text[pos ++];

                    startsSomethingElse = (
                        (pos < text.size() and c == '"') or //Start of a quote or start of a comment
                        (pos < text.size() and c == '/' and (text[pos] == '/' or text[pos] == '*'))
                    );

                    finished = not escaped and (c <= ' ' or startsSomethingElse);
                }while (pos < text.size() and not finished);

                //If we did not finish early (hitting another something)
                if(not escaped and not finished){
                    token.push_back(c);
                }

                tokens.push_back(token);
                tokenStarts.push_back(tokenStart);
                token = "";

                //Get back to the beginning of the seomthing
                if(startsSomethingElse){
                    pos--;
                }
                tokenStart = pos;
            }
        }

        //Handle the last token
        if (token != ""){
            tokens.push_back(token);
            tokenStarts.push_back(tokenStart);
        }
    }

    std::vector<int> StartsOfCommands(const std::string& text) {
        std::vector<int> res = {0};

        bool inQuotes = false;
        bool escaped = false;
        bool inComment = false;
        bool inInlineComment = false;

        for (int i = 0; i < text.size(); i++) {
            if (escaped) {
                escaped = false;
                continue;
            }

            char c = text[i];

            if (not inInlineComment) {
                // /* */ comments have precedence over everything
                if (c == '\n') {
                    inComment = false;
                    res.push_back(i + 1);
                    continue;
                }

                if (not inComment) {
                    if (c == '\\') {
                        escaped = true;
                        continue;
                    }

                    if (c == '"') {
                        inQuotes = not inQuotes;
                        continue;
                    }

                    if (c == ';' and not inQuotes) {
                        res.push_back(i + 1);
                        continue;
                    }
                }
            }

            if (not inQuotes and i < text.size() - 1) {
                //Search for 2 char delimiters
                char c2 = text[i + 1];

                if (inInlineComment and c == '*' and c2 == '/') {
                    inInlineComment = false;
                    i++;
                    continue;
                }

                if (not inInlineComment and c == '/' and c2 == '/') {
                    inComment = true;
                    continue;
                }

                if (not inComment and c == '/' and c2 == '*') {
                    inInlineComment = true;
                    continue;
                }
            }
        }

        return res;
    }

    std::list<std::string> SplitCommandText(const std::string& commands) {
        std::list<std::string> res;

        std::vector<int> start = StartsOfCommands(commands);
        if (start.back() < commands.size()) {
            start.push_back(commands.size() + 1);
        }

        for(int i = 0; i < start.size() - 1; i++) {
            //Get the command, except the command delimiter character
            res.push_back(std::string(commands.c_str() + start[i], start[i + 1] - start[i] - 1));
        }

        return res;
    }

    std::string SubstituteCvars(const std::string& text) {
        const char* raw_text = text.c_str();
        std::string result;

        bool isEscaped = false;
        bool inCvarName = false;
        int lastBlockStart = 0;

        //Cvar are delimited by $ so we parse a bloc at a time
        for(int i = 0; i < text.size(); i++){

            // a \ escapes the next letter so we don't use it for block delimitation
            if (isEscaped) {
                isEscaped = false;
                continue;
            }

            if (text[i] == '\\') {
                isEscaped = true;

            } else if (text[i] == '$') {
                //Found a block, every second block is a cvar name block
                std::string block(raw_text + lastBlockStart, i - lastBlockStart);

                if (inCvarName) {
                    //For now we use the cvar C api to get the cvar value but it should be replaced
                    //by Cvar::get(cvarName)->getString() or something
                    char cvarValue[ MAX_CVAR_VALUE_STRING ];
                    Cvar_VariableStringBuffer( block.c_str(), cvarValue, sizeof( cvarValue ) );
                    result += Escape(std::string(cvarValue));

                    inCvarName = false;

                } else {
                    result += block;
                    inCvarName = true;
                }

                lastBlockStart = i + 1;
            }
        }

        //Handle the last block
        if (inCvarName) {
            Com_Printf("Warning: last CVar substitution block not closed in %s\n", raw_text);
        } else {
            std::string block(raw_text + lastBlockStart, text.size() - lastBlockStart);
            result += block;
        }

        return result;
    }

    /*
    ===============================================================================

    Cmd::CmdArgs

    ===============================================================================
    */

    Args::Args() {
    }

    Args::Args(std::string command) {
        cmd = std::move(command);
        Tokenize(cmd, args, argsStarts);
    }

    int Args::Argc() const {
        return args.size();
    }

    const std::string& Args::Argv(int argNum) const {
        return args[argNum];
    }

    std::string Args::QuotedArgs(int start, int end) const {
        std::string res;

        if (end < 0) {
            end = args.size() - 1;
        }

        for (int i = start; i < end + 1; i++) {
            if (i != start) {
                res += " ";
            }
            res += Escape(args[i], true);
        }

        return res;
    }

    const std::string& Args::RawArgs() const {
        return cmd;
    }

    const std::string& Args::RawArgsFrom(int start) const {
        return cmd.c_str() + argsStarts[start];
    }

    int Args::PosToArg(int pos) {
        for (int i = argsStarts.size(); i-->0;) {
            if (argsStarts[i] <= pos) {
                return i;
            }
        }

        return -1;
    }

    int Args::ArgStartPos(int argNum) {
        return argsStarts[argNum];
    }

    /*
    ===============================================================================

    Cmd::CmdBase

    ===============================================================================
    */

    CmdBase::CmdBase(const cmdFlags_t flags): flags(flags) {
    }

    std::vector<std::string> CmdBase::Complete(int argNum, const Args& args) const {
        return {};
    }

    cmdFlags_t CmdBase::GetFlags() const {
        return flags;
    }

    StaticCmd::StaticCmd(std::string name, const cmdFlags_t flags, std::string description)
    :CmdBase(flags){
        //Register this command statically
        AddCommand(std::move(name), *this, std::move(description));
    }

}
<commit_msg>Drop empty commands at the earliest opportunity.<commit_after>/*
===========================================================================

Daemon GPL Source Code
Copyright (C) 2013 Unvanquished Developers

This file is part of the Daemon GPL Source Code (Daemon Source Code).

Daemon Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Daemon Source Code 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with Daemon Source Code.  If not, see <http://www.gnu.org/licenses/>.

===========================================================================
*/

#include "Command.h"

#include "../engine/qcommon/qcommon.h"
#include "../engine/framework/CommandSystem.h"

namespace Cmd {

    static CmdBase* firstCommand = nullptr;

    std::string Escape(const std::string& text, bool quote) {
        std::string res;

        if (quote) {
            res = "\"";
        }

        for (int i = 0; i < text.size(); i ++) {
            char c = text[i];

            bool commentStart = (i < text.size() + 1) and (c == '/') and (text[i + 1] == '/' or text[i + 1] == '*');
            bool escapeNotQuote = (c <= ' ' and c > 0) or (c == ';') or commentStart;
            bool escape = (c == '$') or (c == '"') or (c == '\\');

            if ((not quote and escapeNotQuote) or escape) {
                res.push_back('\\');
            }
            res.push_back(c);
        }

        if (quote) {
            res += "\"";
        }

        return res;
    }

    void Tokenize(const std::string& text, std::vector<std::string>& tokens, std::vector<int>& tokenStarts) {
        const char* raw_text = text.c_str();
        std::string token;
        int tokenStart = 0;

        int pos = 0;
        bool inToken = false;

        while (pos < text.size()) {
            char c = text[pos ++];

            //Avoid whitespaces
            if (c <= ' ') {
                continue;
            }

            //Check for comments
            if (c == '/' and pos < text.size()) {
                char nextC = text[pos];

                // a // finishes the text and the token
                if (nextC == '/') {
                    break;

                // if it is a /* jump to the end of it
                } else if (nextC == '*'){
                    pos ++; //avoid /*/
                    while (pos < text.size() - 1 and not (text[pos] == '*' and text[pos + 1] == '/') ) {
                        pos ++;
                    }
                    pos += 2;

                    //The comment doesn't end
                    if (pos >= text.size()) {
                        break;
                    }
                    continue;
                }
            }

            //We have something that is not whitespace nor comments so it must be a token

            if (c == '"' and pos < text.size()) {
                //This is a quoted token
                bool escaped = false;

                c = text[pos ++]; //skips the "

                //Add all the characters (except the escape \) until the last unescaped "
                while (pos < text.size() and (escaped or c !='"')) {
                    if (escaped or c != '\\') {
                        token.push_back(c);
                        escaped = false;
                    } else if (not escaped) { // c = \ here
                        escaped = true;
                    }
                    c = text[pos ++];
                }

                tokens.push_back(token);
                tokenStarts.push_back(tokenStart);
                token = "";
                tokenStart = pos;

            } else {
                //An unquoted string, until the next " or comment start
                bool escaped = false;
                bool finished;
                bool startsSomethingElse;

                do {
                    if (escaped or c != '\\') {
                        token.push_back(c);
                        escaped = false;
                    } else if (not escaped) { // c = \ here
                        escaped = true;
                    }
                    c = text[pos ++];

                    startsSomethingElse = (
                        (pos < text.size() and c == '"') or //Start of a quote or start of a comment
                        (pos < text.size() and c == '/' and (text[pos] == '/' or text[pos] == '*'))
                    );

                    finished = not escaped and (c <= ' ' or startsSomethingElse);
                }while (pos < text.size() and not finished);

                //If we did not finish early (hitting another something)
                if(not escaped and not finished){
                    token.push_back(c);
                }

                tokens.push_back(token);
                tokenStarts.push_back(tokenStart);
                token = "";

                //Get back to the beginning of the seomthing
                if(startsSomethingElse){
                    pos--;
                }
                tokenStart = pos;
            }
        }

        //Handle the last token
        if (token != ""){
            tokens.push_back(token);
            tokenStarts.push_back(tokenStart);
        }
    }

    std::vector<int> StartsOfCommands(const std::string& text) {
        std::vector<int> res = {0};

        bool inQuotes = false;
        bool escaped = false;
        bool inComment = false;
        bool inInlineComment = false;

        for (int i = 0; i < text.size(); i++) {
            if (escaped) {
                escaped = false;
                continue;
            }

            char c = text[i];

            if (not inInlineComment) {
                // /* */ comments have precedence over everything
                if (c == '\n') {
                    inComment = false;
                    res.push_back(i + 1);
                    continue;
                }

                if (not inComment) {
                    if (c == '\\') {
                        escaped = true;
                        continue;
                    }

                    if (c == '"') {
                        inQuotes = not inQuotes;
                        continue;
                    }

                    if (c == ';' and not inQuotes) {
                        res.push_back(i + 1);
                        continue;
                    }
                }
            }

            if (not inQuotes and i < text.size() - 1) {
                //Search for 2 char delimiters
                char c2 = text[i + 1];

                if (inInlineComment and c == '*' and c2 == '/') {
                    inInlineComment = false;
                    i++;
                    continue;
                }

                if (not inInlineComment and c == '/' and c2 == '/') {
                    inComment = true;
                    continue;
                }

                if (not inComment and c == '/' and c2 == '*') {
                    inInlineComment = true;
                    continue;
                }
            }
        }

        return res;
    }

    std::list<std::string> SplitCommandText(const std::string& commands) {
        std::list<std::string> res;
        const char *data = commands.data();

        std::vector<int> start = StartsOfCommands(commands);
        if (start.back() < commands.size()) {
            start.push_back(commands.size() + 1);
        }

        for(int i = 0; i < start.size() - 1; i++) {
            //Get the command, except the command delimiter character (if there is one)
            int p = start[i];
            //Strip leading white space
            while (p < start[i + 1] && data[p] >= 0 && data[p] <= ' ')
                ++p;
            //If the result is not "", add it to the list
            if (p < start[i + 1] && data[p] != ';')
                res.push_back(std::string(commands.c_str() + p, start[i + 1] - p - 1));
        }

        return res;
    }

    std::string SubstituteCvars(const std::string& text) {
        const char* raw_text = text.c_str();
        std::string result;

        bool isEscaped = false;
        bool inCvarName = false;
        int lastBlockStart = 0;

        //Cvar are delimited by $ so we parse a bloc at a time
        for(int i = 0; i < text.size(); i++){

            // a \ escapes the next letter so we don't use it for block delimitation
            if (isEscaped) {
                isEscaped = false;
                continue;
            }

            if (text[i] == '\\') {
                isEscaped = true;

            } else if (text[i] == '$') {
                //Found a block, every second block is a cvar name block
                std::string block(raw_text + lastBlockStart, i - lastBlockStart);

                if (inCvarName) {
                    //For now we use the cvar C api to get the cvar value but it should be replaced
                    //by Cvar::get(cvarName)->getString() or something
                    char cvarValue[ MAX_CVAR_VALUE_STRING ];
                    Cvar_VariableStringBuffer( block.c_str(), cvarValue, sizeof( cvarValue ) );
                    result += Escape(std::string(cvarValue));

                    inCvarName = false;

                } else {
                    result += block;
                    inCvarName = true;
                }

                lastBlockStart = i + 1;
            }
        }

        //Handle the last block
        if (inCvarName) {
            Com_Printf("Warning: last CVar substitution block not closed in %s\n", raw_text);
        } else {
            std::string block(raw_text + lastBlockStart, text.size() - lastBlockStart);
            result += block;
        }

        return result;
    }

    /*
    ===============================================================================

    Cmd::CmdArgs

    ===============================================================================
    */

    Args::Args() {
    }

    Args::Args(std::string command) {
        cmd = std::move(command);
        Tokenize(cmd, args, argsStarts);
    }

    int Args::Argc() const {
        return args.size();
    }

    const std::string& Args::Argv(int argNum) const {
        return args[argNum];
    }

    std::string Args::QuotedArgs(int start, int end) const {
        std::string res;

        if (end < 0) {
            end = args.size() - 1;
        }

        for (int i = start; i < end + 1; i++) {
            if (i != start) {
                res += " ";
            }
            res += Escape(args[i], true);
        }

        return res;
    }

    const std::string& Args::RawArgs() const {
        return cmd;
    }

    const std::string& Args::RawArgsFrom(int start) const {
        return cmd.c_str() + argsStarts[start];
    }

    int Args::PosToArg(int pos) {
        for (int i = argsStarts.size(); i-->0;) {
            if (argsStarts[i] <= pos) {
                return i;
            }
        }

        return -1;
    }

    int Args::ArgStartPos(int argNum) {
        return argsStarts[argNum];
    }

    /*
    ===============================================================================

    Cmd::CmdBase

    ===============================================================================
    */

    CmdBase::CmdBase(const cmdFlags_t flags): flags(flags) {
    }

    std::vector<std::string> CmdBase::Complete(int argNum, const Args& args) const {
        return {};
    }

    cmdFlags_t CmdBase::GetFlags() const {
        return flags;
    }

    StaticCmd::StaticCmd(std::string name, const cmdFlags_t flags, std::string description)
    :CmdBase(flags){
        //Register this command statically
        AddCommand(std::move(name), *this, std::move(description));
    }

}
<|endoftext|>


<commit_before>/**
 *  \file RMF/Category.h
 *  \brief Handle read/write of Model data from/to files.
 *
 *  Copyright 2007-2014 IMP Inventors. All rights reserved.
 *
 */

#include "RMF/show_hierarchy.h"
#include "RMF/NodeConstHandle.h"
#include "RMF/Nullable.h"
#include "RMF/compiler_macros.h"
#include "RMF/decorator/feature.h"
#include "RMF/decorator/physics.h"
#include "RMF/decorator/sequence.h"
#include "RMF/decorator/bond.h"
#include "RMF/decorator/representation.h"
#include "RMF/decorator/alternatives.h"
#include "RMF/decorator/shape.h"
#include "RMF/enums.h"
#include "RMF/infrastructure_macros.h"
#include "RMF/types.h"

RMF_ENABLE_WARNINGS

namespace RMF {

namespace {

template <class TypeT>
std::vector<ID<TypeT> > get_keys(FileConstHandle f) {
  Categories kcs = f.get_categories();
  std::vector<ID<TypeT> > ret;
  for (unsigned int i = 0; i < kcs.size(); ++i) {
    std::vector<ID<TypeT> > curp = f.get_keys<TypeT>(kcs[i]);
    ret.insert(ret.end(), curp.begin(), curp.end());
  }
  return ret;
}

template <class Traits>
void show_data(NodeConstHandle n, std::ostream& out,
               const std::vector<ID<Traits> >& ks, std::string prefix) {
  using std::operator<<;
  FileConstHandle f = n.get_file();
  RMF_FOREACH(ID<Traits> k, ks) {
    if (n.get_file().get_current_frame() != FrameID() &&
        !n.get_frame_value(k).get_is_null()) {
      out << std::endl << prefix << n.get_file().get_name(k) << ": "
          << Showable(n.get_frame_value(k));
    } else {
      Nullable<typename Traits::Type> ts = n.get_static_value(k);
      if (!ts.get_is_null()) {
        out << std::endl << prefix << f.get_name(k) << " ("
            << f.get_name(f.get_category(k)) << ")"
            << ": " << Showable(ts.get()) << "(s)";
      }
    }
  }
}

template <class Show>
void print_tree(std::ostream& out, RMF::NodeConstHandle start, Show show) {
  decorator::AlternativesFactory altcf(start.get_file());
  typedef boost::tuple<std::string, std::string, std::string, NodeConstHandle>
      QI;
  std::vector<QI> queue;
  queue.push_back(QI(std::string(), std::string(), std::string(), start));
  do {
    const QI& back = queue.back();
    NodeConstHandle n = back.get<3>();
    std::string prefix0 = back.get<0>();
    std::string prefix1 = back.get<1>();
    std::string node_suffix = back.get<2>();
    queue.pop_back();
    if (altcf.get_is(n)) {
      decorator::AlternativesConst ad = altcf.get(n);
      {
        NodeConstHandles alts = ad.get_alternatives(GAUSSIAN_PARTICLE);
        std::reverse(alts.begin(), alts.end());
        RMF_FOREACH(NodeConstHandle cur, alts) {
          RMF_INTERNAL_CHECK(cur != n, "Node can't be a gaussian one");
          std::ostringstream oss;
          oss << "[G" << decorator::get_resolution(cur) << "]";
          queue.push_back(QI(prefix0, prefix1, oss.str(), cur));
        }
      }
      {
        NodeConstHandles alts = ad.get_alternatives(PARTICLE);
        RMF_INTERNAL_CHECK(alts.front() == n,
                           "The node itself is not in front");
        std::reverse(alts.begin(), alts.end());
        RMF_FOREACH(NodeConstHandle cur, alts) {
          if (cur == n) continue;
          std::ostringstream oss;
          oss << "[" << decorator::get_resolution(cur) << "]";
          queue.push_back(QI(prefix0, prefix1, oss.str(), cur));
        }
        std::ostringstream oss;
        oss << "[" << decorator::get_resolution(n) << "]";
        node_suffix = oss.str();
      }
    }
    out << prefix0;
    NodeConstHandles children = n.get_children();
    if (children.size() > 0)
      out << " + ";
    else
      out << " - ";
    show(n, prefix1, node_suffix, out);
    out << std::endl;
    for (int i = static_cast<int>(children.size()) - 1; i >= 0; --i) {
      queue.push_back(
          QI(prefix1 + "  ", prefix1 + "  ", node_suffix, children[i]));
    }
  } while (!queue.empty());
}

struct LessName {
  FileConstHandle fh_;
  LessName(FileConstHandle fh) : fh_(fh) {}
  template <class Traits>
  bool operator()(ID<Traits> a, ID<Traits> b) const {
    return fh_.get_name(a) < fh_.get_name(b);
  }
};

void show_frames_impl(FileConstHandle fh, FrameID root, std::string prefix,
                      std::ostream& out) {
  FrameIDs ch = fh.get_children(root);
  out << prefix;
  if (ch.empty()) {
    out << " - ";
  } else {
    out << " + ";
  }
  out << fh.get_name(root) << " [" << fh.get_type(root) << "]" << std::endl;
  RMF_FOREACH(FrameID id, ch) { show_frames_impl(fh, id, prefix + "   ", out); }
}

void simple_show_node(NodeConstHandle n, std::string /*prefix*/,
                      std::string node_suffix, std::ostream& out) {
  using std::operator<<;
  out << "\"" << n.get_name() << "\"" << node_suffix << " [" << n.get_type()
      << "]";
}
void show_node(NodeConstHandle n, std::string node_suffix, std::ostream& out,
               FloatKeys fks, FloatsKeys fsks, IntKeys iks, IntsKeys isks,
               StringKeys sks, StringsKeys ssks, Vector3Keys v3ks,
               Vector4Keys v4ks, Vector3sKeys v3sks, std::string prefix) {
  using std::operator<<;
  if (true) {
    simple_show_node(n, "", node_suffix, out);
    show_data(n, out, fks, prefix + "  ");
    show_data(n, out, iks, prefix + "  ");
    show_data(n, out, sks, prefix + "  ");
    show_data(n, out, fsks, prefix + "  ");
    show_data(n, out, isks, prefix + "  ");
    show_data(n, out, ssks, prefix + "  ");
    show_data(n, out, v3ks, prefix + "  ");
    show_data(n, out, v4ks, prefix + "  ");
    show_data(n, out, v3sks, prefix + "  ");
  }
}

void show_node_decorators(
    NodeConstHandle n, std::string node_suffix, std::ostream& out,
    decorator::BondFactory bdcf, decorator::ColoredFactory ccf,
    decorator::ParticleFactory pcf, decorator::IntermediateParticleFactory ipcf,
    decorator::RigidParticleFactory rpcf, decorator::ScoreFactory scf,
    decorator::RepresentationFactory repcf, decorator::BallFactory bcf,
    decorator::CylinderFactory cycf, decorator::SegmentFactory segcf,
    decorator::ResidueFactory rcf, decorator::AtomFactory acf,
    decorator::ChainFactory chaincf, decorator::DomainFactory fragcf,
    decorator::CopyFactory copycf, decorator::DiffuserFactory diffusercf,
    decorator::TypedFactory typedcf, std::string) {
  using std::operator<<;
  out << "\"" << n.get_name() << "\"" << node_suffix << " [" << n.get_type()
      << ":";
  if (bdcf.get_is(n)) out << " bond";
  if (ccf.get_is(n)) out << " color";
  if (pcf.get_is(n))
    out << " particle";
  else if (ipcf.get_is(n))
    out << " iparticle";
  if (rpcf.get_is(n)) out << " rigid";
  if (scf.get_is(n)) out << " score";
  if (repcf.get_is(n)) out << " representation";
  if (bcf.get_is(n)) out << " ball";
  if (cycf.get_is(n)) out << " cylinder";
  if (segcf.get_is(n)) out << " segment";
  if (rcf.get_is(n)) out << " residue";
  if (acf.get_is(n)) out << " atom";
  if (chaincf.get_is(n)) out << " chain";
  if (fragcf.get_is(n)) out << " domain";
  if (copycf.get_is(n)) out << " copy";
  if (typedcf.get_is(n)) out << " typed";
  if (diffusercf.get_is(n)) out << " diffuser";
  out << "]";
}

struct ShowValues {
  FloatKeys fks;
  IntKeys iks;
  StringKeys sks;
  FloatsKeys fsks;
  IntsKeys isks;
  StringsKeys ssks;
  Vector3Keys v3ks;
  Vector4Keys v4ks;
  Vector3sKeys v3sks;
  ShowValues(FileConstHandle fh) {
    fks = get_keys<FloatTraits>(fh);
    std::sort(fks.begin(), fks.end(), LessName(fh));
    iks = get_keys<IntTraits>(fh);
    std::sort(iks.begin(), iks.end(), LessName(fh));
    sks = get_keys<StringTraits>(fh);
    std::sort(sks.begin(), sks.end(), LessName(fh));
    fsks = get_keys<FloatsTraits>(fh);
    std::sort(fsks.begin(), fsks.end(), LessName(fh));
    isks = get_keys<IntsTraits>(fh);
    std::sort(isks.begin(), isks.end(), LessName(fh));
    ssks = get_keys<StringsTraits>(fh);
    std::sort(ssks.begin(), ssks.end(), LessName(fh));
    v3ks = get_keys<Vector3Traits>(fh);
    std::sort(v3ks.begin(), v3ks.end(), LessName(fh));
    v4ks = get_keys<Vector4Traits>(fh);
    std::sort(v4ks.begin(), v4ks.end(), LessName(fh));
    v3sks = get_keys<Vector3sTraits>(fh);
    std::sort(v3sks.begin(), v3sks.end(), LessName(fh));
  }
  void operator()(NodeConstHandle cur, std::string prefix, std::string suffix,
                  std::ostream& out) {
    show_node(cur, suffix, out, fks, fsks, iks, isks, sks, ssks, v3ks, v4ks,
              v3sks, prefix + "   ");
  }
};

struct ShowDecorators {
  decorator::BondFactory bdf;
  decorator::ColoredFactory ccf;
  decorator::ParticleFactory pcf;
  decorator::IntermediateParticleFactory ipcf;
  decorator::RigidParticleFactory rpcf;
  decorator::ScoreFactory scf;
  decorator::RepresentationFactory repcf;
  decorator::BallFactory bcf;
  decorator::CylinderFactory cycf;
  decorator::SegmentFactory segcf;
  decorator::ResidueFactory rcf;
  decorator::AtomFactory acf;
  decorator::ChainFactory chaincf;
  decorator::DomainFactory fragcf;
  decorator::CopyFactory copycf;
  decorator::DiffuserFactory diffusercf;
  decorator::TypedFactory typedcf;
  ShowDecorators(FileConstHandle fh)
      : bdf(fh),
        ccf(fh),
        pcf(fh),
        ipcf(fh),
        rpcf(fh),
        scf(fh),
        repcf(fh),
        bcf(fh),
        cycf(fh),
        segcf(fh),
        rcf(fh),
        acf(fh),
        chaincf(fh),
        fragcf(fh),
        copycf(fh),
        diffusercf(fh),
        typedcf(fh) {}
  void operator()(NodeConstHandle cur, std::string prefix, std::string suffix,
                  std::ostream& out) {
    show_node_decorators(cur, suffix, out, bdf, ccf, pcf, ipcf, rpcf, scf,
                         repcf, bcf, cycf, segcf, rcf, acf, chaincf, fragcf,
                         copycf, diffusercf, typedcf, prefix + "   ");
  }
};
}

void show_hierarchy(NodeConstHandle root, std::ostream& out) {
  using std::operator<<;
  decorator::AlternativesFactory altcf(root.get_file());
  print_tree(out, root, simple_show_node);
}

void show_hierarchy_with_values(NodeConstHandle root, std::ostream& out) {
  print_tree(out, root, ShowValues(root.get_file()));
}

void show_hierarchy_with_decorators(NodeConstHandle root, bool,
                                    std::ostream& out) {
  print_tree(out, root, ShowDecorators(root.get_file()));
}

void show_frames(FileConstHandle fh, std::ostream& out) {
  RMF_FOREACH(FrameID fr, fh.get_root_frames()) {
    show_frames_impl(fh, fr, std::string(), out);
  }
}

} /* namespace RMF */

RMF_DISABLE_WARNINGS
<commit_msg>add ability to show whether decorators are static or not<commit_after>/**
 *  \file RMF/Category.h
 *  \brief Handle read/write of Model data from/to files.
 *
 *  Copyright 2007-2014 IMP Inventors. All rights reserved.
 *
 */

#include "RMF/show_hierarchy.h"
#include "RMF/NodeConstHandle.h"
#include "RMF/Nullable.h"
#include "RMF/compiler_macros.h"
#include "RMF/decorator/feature.h"
#include "RMF/decorator/physics.h"
#include "RMF/decorator/sequence.h"
#include "RMF/decorator/bond.h"
#include "RMF/decorator/representation.h"
#include "RMF/decorator/alternatives.h"
#include "RMF/decorator/shape.h"
#include "RMF/enums.h"
#include "RMF/infrastructure_macros.h"
#include "RMF/types.h"

RMF_ENABLE_WARNINGS

namespace RMF {

namespace {

template <class TypeT>
std::vector<ID<TypeT> > get_keys(FileConstHandle f) {
  Categories kcs = f.get_categories();
  std::vector<ID<TypeT> > ret;
  for (unsigned int i = 0; i < kcs.size(); ++i) {
    std::vector<ID<TypeT> > curp = f.get_keys<TypeT>(kcs[i]);
    ret.insert(ret.end(), curp.begin(), curp.end());
  }
  return ret;
}

template <class Traits>
void show_data(NodeConstHandle n, std::ostream& out,
               const std::vector<ID<Traits> >& ks, std::string prefix) {
  using std::operator<<;
  FileConstHandle f = n.get_file();
  RMF_FOREACH(ID<Traits> k, ks) {
    if (n.get_file().get_current_frame() != FrameID() &&
        !n.get_frame_value(k).get_is_null()) {
      out << std::endl << prefix << n.get_file().get_name(k) << ": "
          << Showable(n.get_frame_value(k));
    } else {
      Nullable<typename Traits::Type> ts = n.get_static_value(k);
      if (!ts.get_is_null()) {
        out << std::endl << prefix << f.get_name(k) << " ("
            << f.get_name(f.get_category(k)) << ")"
            << ": " << Showable(ts.get()) << "(s)";
      }
    }
  }
}

template <class Show>
void print_tree(std::ostream& out, RMF::NodeConstHandle start, Show show) {
  decorator::AlternativesFactory altcf(start.get_file());
  typedef boost::tuple<std::string, std::string, std::string, NodeConstHandle>
      QI;
  std::vector<QI> queue;
  queue.push_back(QI(std::string(), std::string(), std::string(), start));
  do {
    const QI& back = queue.back();
    NodeConstHandle n = back.get<3>();
    std::string prefix0 = back.get<0>();
    std::string prefix1 = back.get<1>();
    std::string node_suffix = back.get<2>();
    queue.pop_back();
    if (altcf.get_is(n)) {
      decorator::AlternativesConst ad = altcf.get(n);
      {
        NodeConstHandles alts = ad.get_alternatives(GAUSSIAN_PARTICLE);
        std::reverse(alts.begin(), alts.end());
        RMF_FOREACH(NodeConstHandle cur, alts) {
          RMF_INTERNAL_CHECK(cur != n, "Node can't be a gaussian one");
          std::ostringstream oss;
          oss << "[G" << decorator::get_resolution(cur) << "]";
          queue.push_back(QI(prefix0, prefix1, oss.str(), cur));
        }
      }
      {
        NodeConstHandles alts = ad.get_alternatives(PARTICLE);
        RMF_INTERNAL_CHECK(alts.front() == n,
                           "The node itself is not in front");
        std::reverse(alts.begin(), alts.end());
        RMF_FOREACH(NodeConstHandle cur, alts) {
          if (cur == n) continue;
          std::ostringstream oss;
          oss << "[" << decorator::get_resolution(cur) << "]";
          queue.push_back(QI(prefix0, prefix1, oss.str(), cur));
        }
        std::ostringstream oss;
        oss << "[" << decorator::get_resolution(n) << "]";
        node_suffix = oss.str();
      }
    }
    out << prefix0;
    NodeConstHandles children = n.get_children();
    if (children.size() > 0)
      out << " + ";
    else
      out << " - ";
    show(n, prefix1, node_suffix, out);
    out << std::endl;
    for (int i = static_cast<int>(children.size()) - 1; i >= 0; --i) {
      queue.push_back(
          QI(prefix1 + "  ", prefix1 + "  ", node_suffix, children[i]));
    }
  } while (!queue.empty());
}

struct LessName {
  FileConstHandle fh_;
  LessName(FileConstHandle fh) : fh_(fh) {}
  template <class Traits>
  bool operator()(ID<Traits> a, ID<Traits> b) const {
    return fh_.get_name(a) < fh_.get_name(b);
  }
};

void show_frames_impl(FileConstHandle fh, FrameID root, std::string prefix,
                      std::ostream& out) {
  FrameIDs ch = fh.get_children(root);
  out << prefix;
  if (ch.empty()) {
    out << " - ";
  } else {
    out << " + ";
  }
  out << fh.get_name(root) << " [" << fh.get_type(root) << "]" << std::endl;
  RMF_FOREACH(FrameID id, ch) { show_frames_impl(fh, id, prefix + "   ", out); }
}

void simple_show_node(NodeConstHandle n, std::string /*prefix*/,
                      std::string node_suffix, std::ostream& out) {
  using std::operator<<;
  out << "\"" << n.get_name() << "\"" << node_suffix << " [" << n.get_type()
      << "]";
}
void show_node(NodeConstHandle n, std::string node_suffix, std::ostream& out,
               FloatKeys fks, FloatsKeys fsks, IntKeys iks, IntsKeys isks,
               StringKeys sks, StringsKeys ssks, Vector3Keys v3ks,
               Vector4Keys v4ks, Vector3sKeys v3sks, std::string prefix) {
  using std::operator<<;
  if (true) {
    simple_show_node(n, "", node_suffix, out);
    show_data(n, out, fks, prefix + "  ");
    show_data(n, out, iks, prefix + "  ");
    show_data(n, out, sks, prefix + "  ");
    show_data(n, out, fsks, prefix + "  ");
    show_data(n, out, isks, prefix + "  ");
    show_data(n, out, ssks, prefix + "  ");
    show_data(n, out, v3ks, prefix + "  ");
    show_data(n, out, v4ks, prefix + "  ");
    show_data(n, out, v3sks, prefix + "  ");
  }
}

void show_node_decorators(
    NodeConstHandle n, std::string node_suffix, std::ostream& out,
    decorator::BondFactory bdcf, decorator::ColoredFactory ccf,
    decorator::ParticleFactory pcf, decorator::IntermediateParticleFactory ipcf,
    decorator::RigidParticleFactory rpcf, decorator::ScoreFactory scf,
    decorator::RepresentationFactory repcf, decorator::BallFactory bcf,
    decorator::CylinderFactory cycf, decorator::SegmentFactory segcf,
    decorator::ResidueFactory rcf, decorator::AtomFactory acf,
    decorator::ChainFactory chaincf, decorator::DomainFactory fragcf,
    decorator::CopyFactory copycf, decorator::DiffuserFactory diffusercf,
    decorator::TypedFactory typedcf, std::string) {
  using std::operator<<;
  out << "\"" << n.get_name() << "\"" << node_suffix << " [" << n.get_type()
      << ":";
  if (bdcf.get_is_static(n)) out << " bond(s)";
  else if (bdcf.get_is(n)) out << " bond";
  if (ccf.get_is_static(n)) out << " color(s)";
  else if (ccf.get_is(n)) out << " color";
  if (pcf.get_is_static(n))
    out << " particle(s)";
  else if (ipcf.get_is_static(n))
    out << " iparticle(s)";
  else if (pcf.get_is(n))
    out << " particle";
  else if (ipcf.get_is(n))
    out << " iparticle";
  if (rpcf.get_is_static(n)) out << " rigid(s)";
  else if (rpcf.get_is(n)) out << " rigid";
  if (scf.get_is_static(n)) out << " score(s)";
  else if (scf.get_is(n)) out << " score";
  if (repcf.get_is_static(n)) out << " representation(s)";
  else if (repcf.get_is(n)) out << " representation";
  if (bcf.get_is_static(n)) out << " ball(s)";
  else if (bcf.get_is(n)) out << " ball";
  if (cycf.get_is_static(n)) out << " cylinder(s)";
  else if (cycf.get_is(n)) out << " cylinder";
  if (segcf.get_is_static(n)) out << " segment(s)";
  else if (segcf.get_is(n)) out << " segment";
  if (rcf.get_is_static(n)) out << " residue(s)";
  else if (rcf.get_is(n)) out << " residue";
  if (acf.get_is_static(n)) out << " atom(s)";
  else if (acf.get_is(n)) out << " atom";
  if (chaincf.get_is_static(n)) out << " chain(s)";
  else if (chaincf.get_is(n)) out << " chain";
  if (fragcf.get_is_static(n)) out << " domain(s)";
  else if (fragcf.get_is(n)) out << " domain";
  if (copycf.get_is_static(n)) out << " copy(s)";
  else if (copycf.get_is(n)) out << " copy";
  if (typedcf.get_is_static(n)) out << " typed(s)";
  else if (typedcf.get_is(n)) out << " typed";
  if (diffusercf.get_is_static(n)) out << " diffuser(s)";
  else if (diffusercf.get_is(n)) out << " diffuser";
  out << "]";
}

struct ShowValues {
  FloatKeys fks;
  IntKeys iks;
  StringKeys sks;
  FloatsKeys fsks;
  IntsKeys isks;
  StringsKeys ssks;
  Vector3Keys v3ks;
  Vector4Keys v4ks;
  Vector3sKeys v3sks;
  ShowValues(FileConstHandle fh) {
    fks = get_keys<FloatTraits>(fh);
    std::sort(fks.begin(), fks.end(), LessName(fh));
    iks = get_keys<IntTraits>(fh);
    std::sort(iks.begin(), iks.end(), LessName(fh));
    sks = get_keys<StringTraits>(fh);
    std::sort(sks.begin(), sks.end(), LessName(fh));
    fsks = get_keys<FloatsTraits>(fh);
    std::sort(fsks.begin(), fsks.end(), LessName(fh));
    isks = get_keys<IntsTraits>(fh);
    std::sort(isks.begin(), isks.end(), LessName(fh));
    ssks = get_keys<StringsTraits>(fh);
    std::sort(ssks.begin(), ssks.end(), LessName(fh));
    v3ks = get_keys<Vector3Traits>(fh);
    std::sort(v3ks.begin(), v3ks.end(), LessName(fh));
    v4ks = get_keys<Vector4Traits>(fh);
    std::sort(v4ks.begin(), v4ks.end(), LessName(fh));
    v3sks = get_keys<Vector3sTraits>(fh);
    std::sort(v3sks.begin(), v3sks.end(), LessName(fh));
  }
  void operator()(NodeConstHandle cur, std::string prefix, std::string suffix,
                  std::ostream& out) {
    show_node(cur, suffix, out, fks, fsks, iks, isks, sks, ssks, v3ks, v4ks,
              v3sks, prefix + "   ");
  }
};

struct ShowDecorators {
  decorator::BondFactory bdf;
  decorator::ColoredFactory ccf;
  decorator::ParticleFactory pcf;
  decorator::IntermediateParticleFactory ipcf;
  decorator::RigidParticleFactory rpcf;
  decorator::ScoreFactory scf;
  decorator::RepresentationFactory repcf;
  decorator::BallFactory bcf;
  decorator::CylinderFactory cycf;
  decorator::SegmentFactory segcf;
  decorator::ResidueFactory rcf;
  decorator::AtomFactory acf;
  decorator::ChainFactory chaincf;
  decorator::DomainFactory fragcf;
  decorator::CopyFactory copycf;
  decorator::DiffuserFactory diffusercf;
  decorator::TypedFactory typedcf;
  ShowDecorators(FileConstHandle fh)
      : bdf(fh),
        ccf(fh),
        pcf(fh),
        ipcf(fh),
        rpcf(fh),
        scf(fh),
        repcf(fh),
        bcf(fh),
        cycf(fh),
        segcf(fh),
        rcf(fh),
        acf(fh),
        chaincf(fh),
        fragcf(fh),
        copycf(fh),
        diffusercf(fh),
        typedcf(fh) {}
  void operator()(NodeConstHandle cur, std::string prefix, std::string suffix,
                  std::ostream& out) {
    show_node_decorators(cur, suffix, out, bdf, ccf, pcf, ipcf, rpcf, scf,
                         repcf, bcf, cycf, segcf, rcf, acf, chaincf, fragcf,
                         copycf, diffusercf, typedcf, prefix + "   ");
  }
};
}

void show_hierarchy(NodeConstHandle root, std::ostream& out) {
  using std::operator<<;
  decorator::AlternativesFactory altcf(root.get_file());
  print_tree(out, root, simple_show_node);
}

void show_hierarchy_with_values(NodeConstHandle root, std::ostream& out) {
  print_tree(out, root, ShowValues(root.get_file()));
}

void show_hierarchy_with_decorators(NodeConstHandle root, bool,
                                    std::ostream& out) {
  print_tree(out, root, ShowDecorators(root.get_file()));
}

void show_frames(FileConstHandle fh, std::ostream& out) {
  RMF_FOREACH(FrameID fr, fh.get_root_frames()) {
    show_frames_impl(fh, fr, std::string(), out);
  }
}

} /* namespace RMF */

RMF_DISABLE_WARNINGS
<|endoftext|>


<commit_before>//
// EigenJS.cpp
// ~~~~~~~~~~~
//
// Copyright (c) 2014 Rick Yang (rick68 at gmail dot com)
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

#ifndef EIGENJS_COMPLEX_HPP
#define EIGENJS_COMPLEX_HPP

#include <node.h>
#include <v8.h>

#include <nan.h>

#include <complex>
#include <sstream>

namespace EigenJS {

template <typename ValueType>
class Complex : public node::ObjectWrap {
  typedef ValueType element_type;
  typedef std::complex<element_type> complex_type;

 public:
  static void Init(v8::Handle<v8::Object> exports) {
    NanScope();

    v8::Local<v8::FunctionTemplate> tpl = NanNew<v8::FunctionTemplate>(New);
    tpl->SetClassName(NanNew("Complex"));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    NODE_SET_PROTOTYPE_METHOD(tpl, "abs", abs);
    NODE_SET_PROTOTYPE_METHOD(tpl, "arg", arg);

    NODE_SET_PROTOTYPE_METHOD(tpl, "toString", toString);

    v8::Local<v8::ObjectTemplate> proto = tpl->PrototypeTemplate();
    proto->SetAccessor(NanNew("real"), get_real, set_real);
    proto->SetAccessor(NanNew("imag"), get_imag, set_imag);

    NanAssignPersistent(constructor, tpl->GetFunction());
    exports->Set(NanNew("Complex"), tpl->GetFunction());

    NanAssignPersistent(function_template, tpl);
  }

  static NAN_METHOD(abs) {
    const Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());
    NanScope();

    NanReturnValue(NanNew(std::abs(obj->complex_)));
  }

  static NAN_METHOD(arg) {
    const Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());
    NanScope();

    NanReturnValue(NanNew(std::arg(obj->complex_)));
  }

  static NAN_METHOD(toString) {
    const Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());
    NanScope();

    std::ostringstream result;
    result << obj->complex_;

    NanReturnValue(NanNew(result.str().c_str()));

    NanReturnUndefined();
  }

  static NAN_GETTER(get_real) {
    NanScope();

    if (!NanGetInternalFieldPointer(args.This(), 0))
      NanReturnValue(args.This());

    const Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());

    NanReturnValue(NanNew(obj->complex_.real()));
  }

  static NAN_SETTER(set_real) {
    if (value->IsNumber()) {
      Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());
      obj->complex_ = complex_type(
          value->NumberValue()
        , obj->complex_.imag()
      );
    }
  }

  static NAN_GETTER(get_imag) {
    NanScope();

    if (!NanGetInternalFieldPointer(args.This(), 0))
      NanReturnValue(args.This());

    const Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());

    NanReturnValue(NanNew(obj->complex_.imag()));
  }

  static NAN_SETTER(set_imag) {
    if (value->IsNumber()) {
      Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());
      obj->complex_ = complex_type(
          obj->complex_.real()
        , value->NumberValue()
      );
    }
  }

 private:
  Complex(const element_type& real, const element_type& imag)
    : complex_(real, imag)
  {}
  ~Complex() {}

  static NAN_METHOD(New) {
    NanScope();

    if (args.Length() < 2) {
      NanThrowError("Tried creating complex without real and imag arguments");
      NanReturnUndefined();
    }

    if (args.IsConstructCall()) {
      const element_type& real = args[0]->NumberValue();
      const element_type& imag = args[1]->NumberValue();
      Complex* obj = new Complex(real, imag);
      obj->Wrap(args.This());
      NanReturnValue(args.This());
    } else {
      v8::Local<v8::Function> ctr = NanNew(constructor);
      v8::Local<v8::Value> argv[] = {args[0], args[1]};
      NanReturnValue(
        ctr->NewInstance(
            sizeof(argv) / sizeof(v8::Local<v8::Value>)
          , argv
        )
      );
    }
  }

 private:
  static v8::Persistent<v8::FunctionTemplate> function_template;
  static v8::Persistent<v8::Function> constructor;

 private:
  complex_type complex_;
};

template<typename ValueType>
v8::Persistent<v8::FunctionTemplate> Complex<ValueType>::function_template;

template<typename ValueType>
v8::Persistent<v8::Function> Complex<ValueType>::constructor;

}  // namespace EigenJS

#endif  // EIGENJS_COMPLEX_HPP
<commit_msg>src: added 'Complex.norm()'<commit_after>//
// EigenJS.cpp
// ~~~~~~~~~~~
//
// Copyright (c) 2014 Rick Yang (rick68 at gmail dot com)
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

#ifndef EIGENJS_COMPLEX_HPP
#define EIGENJS_COMPLEX_HPP

#include <node.h>
#include <v8.h>

#include <nan.h>

#include <complex>
#include <sstream>

namespace EigenJS {

template <typename ValueType>
class Complex : public node::ObjectWrap {
  typedef ValueType element_type;
  typedef std::complex<element_type> complex_type;

 public:
  static void Init(v8::Handle<v8::Object> exports) {
    NanScope();

    v8::Local<v8::FunctionTemplate> tpl = NanNew<v8::FunctionTemplate>(New);
    tpl->SetClassName(NanNew("Complex"));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    NODE_SET_PROTOTYPE_METHOD(tpl, "abs", abs);
    NODE_SET_PROTOTYPE_METHOD(tpl, "arg", arg);
    NODE_SET_PROTOTYPE_METHOD(tpl, "norm", norm);

    NODE_SET_PROTOTYPE_METHOD(tpl, "toString", toString);

    v8::Local<v8::ObjectTemplate> proto = tpl->PrototypeTemplate();
    proto->SetAccessor(NanNew("real"), get_real, set_real);
    proto->SetAccessor(NanNew("imag"), get_imag, set_imag);

    NanAssignPersistent(constructor, tpl->GetFunction());
    exports->Set(NanNew("Complex"), tpl->GetFunction());

    NanAssignPersistent(function_template, tpl);
  }

  static NAN_METHOD(abs) {
    const Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());
    NanScope();

    NanReturnValue(NanNew(std::abs(obj->complex_)));
  }

  static NAN_METHOD(arg) {
    const Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());
    NanScope();

    NanReturnValue(NanNew(std::arg(obj->complex_)));
  }

  static NAN_METHOD(norm) {
    const Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());
    NanScope();

    NanReturnValue(NanNew(std::norm(obj->complex_)));
  }

  static NAN_METHOD(toString) {
    const Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());
    NanScope();

    std::ostringstream result;
    result << obj->complex_;

    NanReturnValue(NanNew(result.str().c_str()));

    NanReturnUndefined();
  }

  static NAN_GETTER(get_real) {
    NanScope();

    if (!NanGetInternalFieldPointer(args.This(), 0))
      NanReturnValue(args.This());

    const Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());

    NanReturnValue(NanNew(obj->complex_.real()));
  }

  static NAN_SETTER(set_real) {
    if (value->IsNumber()) {
      Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());
      obj->complex_ = complex_type(
          value->NumberValue()
        , obj->complex_.imag()
      );
    }
  }

  static NAN_GETTER(get_imag) {
    NanScope();

    if (!NanGetInternalFieldPointer(args.This(), 0))
      NanReturnValue(args.This());

    const Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());

    NanReturnValue(NanNew(obj->complex_.imag()));
  }

  static NAN_SETTER(set_imag) {
    if (value->IsNumber()) {
      Complex* obj = node::ObjectWrap::Unwrap<Complex>(args.This());
      obj->complex_ = complex_type(
          obj->complex_.real()
        , value->NumberValue()
      );
    }
  }

 private:
  Complex(const element_type& real, const element_type& imag)
    : complex_(real, imag)
  {}
  ~Complex() {}

  static NAN_METHOD(New) {
    NanScope();

    if (args.Length() < 2) {
      NanThrowError("Tried creating complex without real and imag arguments");
      NanReturnUndefined();
    }

    if (args.IsConstructCall()) {
      const element_type& real = args[0]->NumberValue();
      const element_type& imag = args[1]->NumberValue();
      Complex* obj = new Complex(real, imag);
      obj->Wrap(args.This());
      NanReturnValue(args.This());
    } else {
      v8::Local<v8::Function> ctr = NanNew(constructor);
      v8::Local<v8::Value> argv[] = {args[0], args[1]};
      NanReturnValue(
        ctr->NewInstance(
            sizeof(argv) / sizeof(v8::Local<v8::Value>)
          , argv
        )
      );
    }
  }

 private:
  static v8::Persistent<v8::FunctionTemplate> function_template;
  static v8::Persistent<v8::Function> constructor;

 private:
  complex_type complex_;
};

template<typename ValueType>
v8::Persistent<v8::FunctionTemplate> Complex<ValueType>::function_template;

template<typename ValueType>
v8::Persistent<v8::Function> Complex<ValueType>::constructor;

}  // namespace EigenJS

#endif  // EIGENJS_COMPLEX_HPP
<|endoftext|>