<commit_before>/*
 * Copyright (c) 2003-2009, John Wiegley.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * - Neither the name of New Artisans LLC nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <system.hh>

#include "output.h"
#include "xact.h"
#include "post.h"
#include "account.h"
#include "session.h"
#include "report.h"

namespace ledger {

format_posts::format_posts(report_t&	 _report,
			   const string& format,
			   bool		 _print_raw)
  : report(_report), last_xact(NULL), last_post(NULL),
    print_raw(_print_raw)
{
  TRACE_CTOR(format_posts, "report&, const string&, bool");

  const char * f = format.c_str();

  if (const char * p = std::strstr(f, "%/")) {
    first_line_format.parse(string(f, 0, p - f));
    const char * n = p + 2;
    if (const char * p = std::strstr(n, "%/")) {
      next_lines_format.parse(string(n, 0, p - n));
      between_format.parse(string(p + 2));
    } else {
      next_lines_format.parse(n);
    }
  } else {
    first_line_format.parse(format);
    next_lines_format.parse(format);
  }
}

void format_posts::flush()
{
  report.output_stream.flush();
}

void format_posts::operator()(post_t& post)
{
  std::ostream& out(report.output_stream);

  if (print_raw) {
    if (! post.has_xdata() ||
	! post.xdata().has_flags(POST_EXT_DISPLAYED)) {
      if (last_xact != post.xact) {
	if (last_xact) {
	  bind_scope_t xact_scope(report, *last_xact);
	  between_format.format(out, xact_scope);
	}
	print_item(out, *post.xact);
	out << '\n';
	last_xact = post.xact;
      }
      post.xdata().add_flags(POST_EXT_DISPLAYED);
      last_post = &post;
    }
  }
  else if (! post.has_xdata() ||
	   ! post.xdata().has_flags(POST_EXT_DISPLAYED)) {
    bind_scope_t bound_scope(report, post);
    if (last_xact != post.xact) {
      if (last_xact) {
	bind_scope_t xact_scope(report, *last_xact);
	between_format.format(out, xact_scope);
      }
      first_line_format.format(out, bound_scope);
      last_xact = post.xact;
    }
    else if (last_post && last_post->date() != post.date()) {
      first_line_format.format(out, bound_scope);
    }
    else {
      next_lines_format.format(out, bound_scope);
    }

    post.xdata().add_flags(POST_EXT_DISPLAYED);
    last_post = &post;
  }
}

format_accounts::format_accounts(report_t&     _report,
				 const string& format)
  : report(_report), disp_pred()
{
  TRACE_CTOR(format_accounts, "report&, const string&");

  const char * f = format.c_str();

  if (const char * p = std::strstr(f, "%/")) {
    account_line_format.parse(string(f, 0, p - f));
    const char * n = p + 2;
    if (const char * p = std::strstr(n, "%/")) {
      total_line_format.parse(string(n, 0, p - n));
      separator_format.parse(string(p + 2));
    } else {
      total_line_format.parse(n);
    }
  } else {
    account_line_format.parse(format);
    total_line_format.parse(format);
  }
}

std::size_t format_accounts::post_account(account_t& account)
{
  if (account.xdata().has_flags(ACCOUNT_EXT_TO_DISPLAY)) {
    if (account.parent &&
	account.parent->xdata().has_flags(ACCOUNT_EXT_TO_DISPLAY) &&
	! account.parent->xdata().has_flags(ACCOUNT_EXT_DISPLAYED))
      post_account(*account.parent);

    account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);

    bind_scope_t bound_scope(report, account);
    account_line_format.format(report.output_stream, bound_scope);

    return 1;
  }
  return 0;
}

std::pair<std::size_t, std::size_t>
format_accounts::mark_accounts(account_t& account, const bool flat)
{
  std::size_t visited	 = 0;
  std::size_t to_display = 0;

  foreach (accounts_map::value_type& pair, account.accounts) {
    std::pair<std::size_t, std::size_t> i = mark_accounts(*pair.second, flat);
    visited    += i.first;
    to_display += i.second;
  }

#if defined(DEBUG_ON)
  DEBUG("account.display", "Considering account: " << account.fullname());
  if (account.has_flags(ACCOUNT_EXT_VISITED))
    DEBUG("account.display", "  it was visited itself");
  DEBUG("account.display", "  it has " << visited << " visited children");
  DEBUG("account.display",
	"  it has " << to_display << " children to display");
#endif

  if (account.parent &&
      (account.has_flags(ACCOUNT_EXT_VISITED) || (! flat && visited > 0))) {
    bind_scope_t bound_scope(report, account);
    if ((! flat && to_display > 1) ||
	((flat || to_display != 1 ||
	  account.has_flags(ACCOUNT_EXT_VISITED)) &&
	 disp_pred(bound_scope))) {
      account.xdata().add_flags(ACCOUNT_EXT_TO_DISPLAY);
      DEBUG("account.display", "Marking account as TO_DISPLAY");
      to_display = 1;
    }
    visited = 1;
  }

  return std::pair<std::size_t, std::size_t>(visited, to_display);
}

void format_accounts::flush()
{
  std::ostream& out(report.output_stream);

  if (report.HANDLED(display_)) {
    DEBUG("account.display",
	  "Account display predicate: " << report.HANDLER(display_).str());
    disp_pred.predicate.parse(report.HANDLER(display_).str());
  }

  mark_accounts(*report.session.master, report.HANDLED(flat));

  std::size_t displayed = 0;

  foreach (account_t * account, posted_accounts)
    displayed += post_account(*account);

  if (displayed > 1 &&
      ! report.HANDLED(no_total) && ! report.HANDLED(percent)) {
    bind_scope_t bound_scope(report, *report.session.master);
    separator_format.format(out, bound_scope);
    total_line_format.format(out, bound_scope);
  }

  out.flush();
}

void format_accounts::operator()(account_t& account)
{
  posted_accounts.push_back(&account);
}

} // namespace ledger
<commit_msg>In the balance report, don't output any account twice<commit_after>/*
 * Copyright (c) 2003-2009, John Wiegley.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * - Neither the name of New Artisans LLC nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <system.hh>

#include "output.h"
#include "xact.h"
#include "post.h"
#include "account.h"
#include "session.h"
#include "report.h"

namespace ledger {

format_posts::format_posts(report_t&	 _report,
			   const string& format,
			   bool		 _print_raw)
  : report(_report), last_xact(NULL), last_post(NULL),
    print_raw(_print_raw)
{
  TRACE_CTOR(format_posts, "report&, const string&, bool");

  const char * f = format.c_str();

  if (const char * p = std::strstr(f, "%/")) {
    first_line_format.parse(string(f, 0, p - f));
    const char * n = p + 2;
    if (const char * p = std::strstr(n, "%/")) {
      next_lines_format.parse(string(n, 0, p - n));
      between_format.parse(string(p + 2));
    } else {
      next_lines_format.parse(n);
    }
  } else {
    first_line_format.parse(format);
    next_lines_format.parse(format);
  }
}

void format_posts::flush()
{
  report.output_stream.flush();
}

void format_posts::operator()(post_t& post)
{
  std::ostream& out(report.output_stream);

  if (print_raw) {
    if (! post.has_xdata() ||
	! post.xdata().has_flags(POST_EXT_DISPLAYED)) {
      if (last_xact != post.xact) {
	if (last_xact) {
	  bind_scope_t xact_scope(report, *last_xact);
	  between_format.format(out, xact_scope);
	}
	print_item(out, *post.xact);
	out << '\n';
	last_xact = post.xact;
      }
      post.xdata().add_flags(POST_EXT_DISPLAYED);
      last_post = &post;
    }
  }
  else if (! post.has_xdata() ||
	   ! post.xdata().has_flags(POST_EXT_DISPLAYED)) {
    bind_scope_t bound_scope(report, post);
    if (last_xact != post.xact) {
      if (last_xact) {
	bind_scope_t xact_scope(report, *last_xact);
	between_format.format(out, xact_scope);
      }
      first_line_format.format(out, bound_scope);
      last_xact = post.xact;
    }
    else if (last_post && last_post->date() != post.date()) {
      first_line_format.format(out, bound_scope);
    }
    else {
      next_lines_format.format(out, bound_scope);
    }

    post.xdata().add_flags(POST_EXT_DISPLAYED);
    last_post = &post;
  }
}

format_accounts::format_accounts(report_t&     _report,
				 const string& format)
  : report(_report), disp_pred()
{
  TRACE_CTOR(format_accounts, "report&, const string&");

  const char * f = format.c_str();

  if (const char * p = std::strstr(f, "%/")) {
    account_line_format.parse(string(f, 0, p - f));
    const char * n = p + 2;
    if (const char * p = std::strstr(n, "%/")) {
      total_line_format.parse(string(n, 0, p - n));
      separator_format.parse(string(p + 2));
    } else {
      total_line_format.parse(n);
    }
  } else {
    account_line_format.parse(format);
    total_line_format.parse(format);
  }
}

std::size_t format_accounts::post_account(account_t& account)
{
  if (account.xdata().has_flags(ACCOUNT_EXT_TO_DISPLAY) &&
      ! account.xdata().has_flags(ACCOUNT_EXT_DISPLAYED)) {
    if (account.parent &&
	account.parent->xdata().has_flags(ACCOUNT_EXT_TO_DISPLAY) &&
	! account.parent->xdata().has_flags(ACCOUNT_EXT_DISPLAYED))
      post_account(*account.parent);

    account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);

    bind_scope_t bound_scope(report, account);
    account_line_format.format(report.output_stream, bound_scope);

    return 1;
  }
  return 0;
}

std::pair<std::size_t, std::size_t>
format_accounts::mark_accounts(account_t& account, const bool flat)
{
  std::size_t visited	 = 0;
  std::size_t to_display = 0;

  foreach (accounts_map::value_type& pair, account.accounts) {
    std::pair<std::size_t, std::size_t> i = mark_accounts(*pair.second, flat);
    visited    += i.first;
    to_display += i.second;
  }

#if defined(DEBUG_ON)
  DEBUG("account.display", "Considering account: " << account.fullname());
  if (account.has_flags(ACCOUNT_EXT_VISITED))
    DEBUG("account.display", "  it was visited itself");
  DEBUG("account.display", "  it has " << visited << " visited children");
  DEBUG("account.display",
	"  it has " << to_display << " children to display");
#endif

  if (account.parent &&
      (account.has_flags(ACCOUNT_EXT_VISITED) || (! flat && visited > 0))) {
    bind_scope_t bound_scope(report, account);
    if ((! flat && to_display > 1) ||
	((flat || to_display != 1 ||
	  account.has_flags(ACCOUNT_EXT_VISITED)) &&
	 disp_pred(bound_scope))) {
      account.xdata().add_flags(ACCOUNT_EXT_TO_DISPLAY);
      DEBUG("account.display", "Marking account as TO_DISPLAY");
      to_display = 1;
    }
    visited = 1;
  }

  return std::pair<std::size_t, std::size_t>(visited, to_display);
}

void format_accounts::flush()
{
  std::ostream& out(report.output_stream);

  if (report.HANDLED(display_)) {
    DEBUG("account.display",
	  "Account display predicate: " << report.HANDLER(display_).str());
    disp_pred.predicate.parse(report.HANDLER(display_).str());
  }

  mark_accounts(*report.session.master, report.HANDLED(flat));

  std::size_t displayed = 0;

  foreach (account_t * account, posted_accounts)
    displayed += post_account(*account);

  if (displayed > 1 &&
      ! report.HANDLED(no_total) && ! report.HANDLED(percent)) {
    bind_scope_t bound_scope(report, *report.session.master);
    separator_format.format(out, bound_scope);
    total_line_format.format(out, bound_scope);
  }

  out.flush();
}

void format_accounts::operator()(account_t& account)
{
  posted_accounts.push_back(&account);
}

} // namespace ledger
<|endoftext|>


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

#pragma hdrstop

#ifndef _WINDOW_HXX //autogen
#include <vcl/window.hxx>
#endif

#ifndef _EDITSH_HXX
#include <editsh.hxx>
#endif
#ifndef _DOC_HXX
#include <doc.hxx>
#endif
#ifndef _PAM_HXX
#include <pam.hxx>
#endif
#ifndef _DOCARY_HXX
#include <docary.hxx>
#endif
#ifndef _ACORRECT_HXX
#include <acorrect.hxx>
#endif
#ifndef _SWTABLE_HXX
#include <swtable.hxx>
#endif
#ifndef _NDTXT_HXX
#include <ndtxt.hxx>
#endif
#ifndef _SWUNDO_HXX
#include <swundo.hxx>
#endif
#ifndef _SW_REWRITER_HXX
#include <SwRewriter.hxx>
#endif

/********************************************************
 * Ctor/Dtor
 ********************************************************/
// verkleideter Copy-Constructor

SwEditShell::SwEditShell( SwEditShell& rEdSH, Window *pWin )
    : SwCrsrShell( rEdSH, pWin )
{
}

// ctor/dtor

SwEditShell::SwEditShell( SwDoc& rDoc, Window *pWin, SwRootFrm *pRootFrm,
                            const SwViewOption *pOpt )
    : SwCrsrShell( rDoc, pWin, pRootFrm, pOpt)
{
    GetDoc()->DoUndo();
}

SwEditShell::~SwEditShell() // USED
{
}

/******************************************************************************
 *                  sal_Bool SwEditShell::IsModified() const
 ******************************************************************************/

sal_Bool SwEditShell::IsModified() const
{
    return GetDoc()->IsModified();
}
/******************************************************************************
 *                    void SwEditShell::SetModified()
 ******************************************************************************/

void SwEditShell::SetModified()
{
    GetDoc()->SetModified();
}
/******************************************************************************
 *                   void SwEditShell::ResetModified()
 ******************************************************************************/

void SwEditShell::ResetModified()
{
    GetDoc()->ResetModified();
}

void SwEditShell::SetUndoNoResetModified()
{
    GetDoc()->SetModified();
    GetDoc()->SetUndoNoResetModified();
}

#ifdef USED
/******************************************************************************
 *                    void SwEditShell::StartAction()
 ******************************************************************************/

void SwEditShell::StartAction() // OPT: ganz wech
{
    SwCrsrShell::StartAction();
}
/******************************************************************************
 *                    void SwEditShell::EndAction()
 ******************************************************************************/

void SwEditShell::EndAction()
{
    SwCrsrShell::EndAction();
}
#endif
/******************************************************************************
 *                 void SwEditShell::StartAllAction()
 ******************************************************************************/

void SwEditShell::StartAllAction()
{
    ViewShell *pSh = this;
    do {
        if( pSh->IsA( TYPE( SwEditShell ) ) )
            ((SwEditShell*)pSh)->StartAction();
        else
            pSh->StartAction();
        pSh = (ViewShell *)pSh->GetNext();
    } while(pSh != this);
}
/******************************************************************************
 *                  void SwEditShell::EndAllAction()
 ******************************************************************************/

void SwEditShell::EndAllAction()
{
    ViewShell *pSh = this;
    do {
        if( pSh->IsA( TYPE( SwEditShell ) ) )
            ((SwEditShell*)pSh)->EndAction();
        else
            pSh->EndAction();
        pSh = (ViewShell *)pSh->GetNext();
    } while(pSh != this);
}

/******************************************************************************
 *                  void SwEditShell::CalcLayout()
 ******************************************************************************/

void SwEditShell::CalcLayout()
{
    StartAllAction();
    ViewShell::CalcLayout();

    ViewShell *pSh = this;
    do
    {
        if ( pSh->GetWin() )
            pSh->GetWin()->Invalidate();
        pSh = (ViewShell*)pSh->GetNext();

    } while ( pSh != this );

    EndAllAction();
}

/******************************************************************************
 *                      Inhaltsform bestimmen, holen
 ******************************************************************************/
// OPT: wird fuer jedes Attribut gerufen?

sal_uInt16 SwEditShell::GetCntType() const
{
    // nur noch am SPoint ist der Inhalt interessant
    sal_uInt16 nRet = 0;
    if( IsTableMode() )
        nRet = CNT_TXT;
    else
        switch( GetCrsr()->GetNode()->GetNodeType() )
        {
        case ND_TEXTNODE:   nRet = CNT_TXT; break;
        case ND_GRFNODE:    nRet = CNT_GRF; break;
        case ND_OLENODE:    nRet = CNT_OLE; break;
        }

    ASSERT( nRet, ERR_OUTOFSCOPE );
    return nRet;
}

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

sal_Bool SwEditShell::HasOtherCnt() const
{
    const SwNodes &rNds = GetDoc()->GetNodes();
    const SwNode *pNd;
    return GetDoc()->GetSpzFrmFmts()->Count() ||
            1 != (( pNd = &rNds.GetEndOfInserts() )->GetIndex() -
                pNd->StartOfSectionIndex() ) ||
            1 != (( pNd = &rNds.GetEndOfAutotext() )->GetIndex() -
                pNd->StartOfSectionIndex() );
}

/******************************************************************************
 *              Zugriffsfunktionen fuer Filename-Behandlung
 ******************************************************************************/

SwActKontext::SwActKontext(SwEditShell *pShell)
    : pSh(pShell)
{
    pSh->StartAction();
}

SwActKontext::~SwActKontext()
{
    pSh->EndAction();
}

/******************************************************************************
 *          Klasse fuer den automatisierten Aufruf von Start- und
 *                              EndCrsrMove();
 ******************************************************************************/

SwMvKontext::SwMvKontext(SwEditShell *pShell ) : pSh(pShell)
{
    pSh->SttCrsrMove();
}

SwMvKontext::~SwMvKontext()
{
    pSh->EndCrsrMove();
}

SwFrmFmt *SwEditShell::GetTableFmt()    // OPT: schnellster Test auf Tabelle?
{
    const SwTableNode* pTblNd = IsCrsrInTbl();
    return pTblNd ? (SwFrmFmt*)pTblNd->GetTable().GetFrmFmt() : 0;
}

// OPT: wieso 3x beim neuen Dokument

sal_uInt16 SwEditShell::GetTOXTypeCount(TOXTypes eTyp) const
{
    return pDoc->GetTOXTypeCount(eTyp);
}

void SwEditShell::InsertTOXType(const SwTOXType& rTyp)
{
    pDoc->InsertTOXType(rTyp);
}

void SwEditShell::DoUndo( sal_Bool bOn )
{ GetDoc()->DoUndo( bOn ); }

sal_Bool SwEditShell::DoesUndo() const
{ return GetDoc()->DoesUndo(); }

void SwEditShell::DoGroupUndo( sal_Bool bOn )
{ GetDoc()->DoGroupUndo( bOn ); }

sal_Bool SwEditShell::DoesGroupUndo() const
{ return GetDoc()->DoesGroupUndo(); }

void SwEditShell::DelAllUndoObj()
{
    GetDoc()->DelAllUndoObj();
}

// Zusammenfassen von Kontinuierlichen Insert/Delete/Overwrite von
// Charaktern. Default ist sdbcx::Group-Undo.

// setzt Undoklammerung auf, liefert nUndoId der Klammerung

sal_uInt16 SwEditShell::StartUndo( sal_uInt16 nUndoId,
                                   const SwRewriter *pRewriter )
{ return GetDoc()->StartUndo( nUndoId, pRewriter ); }

// schliesst Klammerung der nUndoId, nicht vom UI benutzt

sal_uInt16 SwEditShell::EndUndo(sal_uInt16 nUndoId)
{ return GetDoc()->EndUndo(nUndoId); }

// liefert die Id der letzten undofaehigen Aktion zurueck
// fuellt ggf. VARARR mit sdbcx::User-UndoIds

sal_uInt16 SwEditShell::GetUndoIds(String* pStr,SwUndoIds *pUndoIds) const
{ return GetDoc()->GetUndoIds(pStr,pUndoIds); }

String SwEditShell::GetUndoIdsStr(String* pStr,SwUndoIds *pUndoIds) const
{ return GetDoc()->GetUndoIdsStr(pStr,pUndoIds); }

// liefert die Id der letzten Redofaehigen Aktion zurueck
// fuellt ggf. VARARR mit RedoIds

sal_uInt16 SwEditShell::GetRedoIds(String* pStr,SwUndoIds *pRedoIds) const
{ return GetDoc()->GetRedoIds(pStr,pRedoIds); }

String SwEditShell::GetRedoIdsStr(String* pStr,SwUndoIds *pRedoIds) const
{ return GetDoc()->GetRedoIdsStr(pStr,pRedoIds); }

// liefert die Id der letzten Repeatfaehigen Aktion zurueck
// fuellt ggf. VARARR mit RedoIds

sal_uInt16 SwEditShell::GetRepeatIds(String* pStr, SwUndoIds *pRedoIds) const
{ return GetDoc()->GetRepeatIds(pStr,pRedoIds); }

String SwEditShell::GetRepeatIdsStr(String* pStr, SwUndoIds *pRedoIds) const
{ return GetDoc()->GetRepeatIdsStr(pStr,pRedoIds); }

// AutoKorrektur - JP 27.01.94
void SwEditShell::AutoCorrect( SvxAutoCorrect& rACorr, sal_Bool bInsert,
                                sal_Unicode cChar )
{
    SET_CURR_SHELL( this );

    StartAllAction();

    SwPaM* pCrsr = GetCrsr();
    SwTxtNode* pTNd = pCrsr->GetNode()->GetTxtNode();

    SwAutoCorrDoc aSwAutoCorrDoc( *this, *pCrsr, cChar );
    rACorr.AutoCorrect( aSwAutoCorrDoc,
                    pTNd->GetTxt(), pCrsr->GetPoint()->nContent.GetIndex(),
                    cChar, bInsert );
    if( cChar )
        SaveTblBoxCntnt( pCrsr->GetPoint() );
    EndAllAction();
}

void SwEditShell::SetNewDoc(sal_Bool bNew)
{
    GetDoc()->SetNewDoc(bNew);
}

sal_Bool SwEditShell::GetPrevAutoCorrWord( SvxAutoCorrect& rACorr, String& rWord )
{
    SET_CURR_SHELL( this );

    sal_Bool bRet;
    SwPaM* pCrsr = GetCrsr();
    xub_StrLen nPos = pCrsr->GetPoint()->nContent.GetIndex();
    SwTxtNode* pTNd = pCrsr->GetNode()->GetTxtNode();
    if( pTNd && nPos )
    {
        SwAutoCorrDoc aSwAutoCorrDoc( *this, *pCrsr, 0 );
        bRet = rACorr.GetPrevAutoCorrWord( aSwAutoCorrDoc,
                                            pTNd->GetTxt(), nPos, rWord );
    }
    else
        bRet = sal_False;
    return bRet;
}

SwAutoCompleteWord& SwEditShell::GetAutoCompleteWords()
{
    return SwDoc::GetAutoCompleteWords();
}

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

#pragma hdrstop

#ifndef _WINDOW_HXX //autogen
#include <vcl/window.hxx>
#endif

#ifndef _EDITSH_HXX
#include <editsh.hxx>
#endif
#ifndef _DOC_HXX
#include <doc.hxx>
#endif
#ifndef _PAM_HXX
#include <pam.hxx>
#endif
#ifndef _DOCARY_HXX
#include <docary.hxx>
#endif
#ifndef _ACORRECT_HXX
#include <acorrect.hxx>
#endif
#ifndef _SWTABLE_HXX
#include <swtable.hxx>
#endif
#ifndef _NDTXT_HXX
#include <ndtxt.hxx>
#endif
#ifndef _SWUNDO_HXX
#include <swundo.hxx>
#endif
#ifndef _SW_REWRITER_HXX
#include <SwRewriter.hxx>
#endif

/********************************************************
 * Ctor/Dtor
 ********************************************************/
// verkleideter Copy-Constructor

SwEditShell::SwEditShell( SwEditShell& rEdSH, Window *pWin )
    : SwCrsrShell( rEdSH, pWin )
{
}

// ctor/dtor

SwEditShell::SwEditShell( SwDoc& rDoc, Window *pWin, SwRootFrm *pRootFrm,
                            const SwViewOption *pOpt )
    : SwCrsrShell( rDoc, pWin, pRootFrm, pOpt)
{
    GetDoc()->DoUndo();
}

SwEditShell::~SwEditShell() // USED
{
}

/******************************************************************************
 *                  sal_Bool SwEditShell::IsModified() const
 ******************************************************************************/

sal_Bool SwEditShell::IsModified() const
{
    return GetDoc()->IsModified();
}
/******************************************************************************
 *                    void SwEditShell::SetModified()
 ******************************************************************************/

void SwEditShell::SetModified()
{
    GetDoc()->SetModified();
}
/******************************************************************************
 *                   void SwEditShell::ResetModified()
 ******************************************************************************/

void SwEditShell::ResetModified()
{
    GetDoc()->ResetModified();
}

void SwEditShell::SetUndoNoResetModified()
{
    GetDoc()->SetModified();
    GetDoc()->SetUndoNoResetModified();
}

/******************************************************************************
 *                 void SwEditShell::StartAllAction()
 ******************************************************************************/

void SwEditShell::StartAllAction()
{
    ViewShell *pSh = this;
    do {
        if( pSh->IsA( TYPE( SwEditShell ) ) )
            ((SwEditShell*)pSh)->StartAction();
        else
            pSh->StartAction();
        pSh = (ViewShell *)pSh->GetNext();
    } while(pSh != this);
}
/******************************************************************************
 *                  void SwEditShell::EndAllAction()
 ******************************************************************************/

void SwEditShell::EndAllAction()
{
    ViewShell *pSh = this;
    do {
        if( pSh->IsA( TYPE( SwEditShell ) ) )
            ((SwEditShell*)pSh)->EndAction();
        else
            pSh->EndAction();
        pSh = (ViewShell *)pSh->GetNext();
    } while(pSh != this);
}

/******************************************************************************
 *                  void SwEditShell::CalcLayout()
 ******************************************************************************/

void SwEditShell::CalcLayout()
{
    StartAllAction();
    ViewShell::CalcLayout();

    ViewShell *pSh = this;
    do
    {
        if ( pSh->GetWin() )
            pSh->GetWin()->Invalidate();
        pSh = (ViewShell*)pSh->GetNext();

    } while ( pSh != this );

    EndAllAction();
}

/******************************************************************************
 *                      Inhaltsform bestimmen, holen
 ******************************************************************************/
// OPT: wird fuer jedes Attribut gerufen?

sal_uInt16 SwEditShell::GetCntType() const
{
    // nur noch am SPoint ist der Inhalt interessant
    sal_uInt16 nRet = 0;
    if( IsTableMode() )
        nRet = CNT_TXT;
    else
        switch( GetCrsr()->GetNode()->GetNodeType() )
        {
        case ND_TEXTNODE:   nRet = CNT_TXT; break;
        case ND_GRFNODE:    nRet = CNT_GRF; break;
        case ND_OLENODE:    nRet = CNT_OLE; break;
        }

    ASSERT( nRet, ERR_OUTOFSCOPE );
    return nRet;
}

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

sal_Bool SwEditShell::HasOtherCnt() const
{
    const SwNodes &rNds = GetDoc()->GetNodes();
    const SwNode *pNd;
    return GetDoc()->GetSpzFrmFmts()->Count() ||
            1 != (( pNd = &rNds.GetEndOfInserts() )->GetIndex() -
                pNd->StartOfSectionIndex() ) ||
            1 != (( pNd = &rNds.GetEndOfAutotext() )->GetIndex() -
                pNd->StartOfSectionIndex() );
}

/******************************************************************************
 *              Zugriffsfunktionen fuer Filename-Behandlung
 ******************************************************************************/

SwActKontext::SwActKontext(SwEditShell *pShell)
    : pSh(pShell)
{
    pSh->StartAction();
}

SwActKontext::~SwActKontext()
{
    pSh->EndAction();
}

/******************************************************************************
 *          Klasse fuer den automatisierten Aufruf von Start- und
 *                              EndCrsrMove();
 ******************************************************************************/

SwMvKontext::SwMvKontext(SwEditShell *pShell ) : pSh(pShell)
{
    pSh->SttCrsrMove();
}

SwMvKontext::~SwMvKontext()
{
    pSh->EndCrsrMove();
}

SwFrmFmt *SwEditShell::GetTableFmt()    // OPT: schnellster Test auf Tabelle?
{
    const SwTableNode* pTblNd = IsCrsrInTbl();
    return pTblNd ? (SwFrmFmt*)pTblNd->GetTable().GetFrmFmt() : 0;
}

// OPT: wieso 3x beim neuen Dokument

sal_uInt16 SwEditShell::GetTOXTypeCount(TOXTypes eTyp) const
{
    return pDoc->GetTOXTypeCount(eTyp);
}

void SwEditShell::InsertTOXType(const SwTOXType& rTyp)
{
    pDoc->InsertTOXType(rTyp);
}

void SwEditShell::DoUndo( sal_Bool bOn )
{ GetDoc()->DoUndo( bOn ); }

sal_Bool SwEditShell::DoesUndo() const
{ return GetDoc()->DoesUndo(); }

void SwEditShell::DoGroupUndo( sal_Bool bOn )
{ GetDoc()->DoGroupUndo( bOn ); }

sal_Bool SwEditShell::DoesGroupUndo() const
{ return GetDoc()->DoesGroupUndo(); }

void SwEditShell::DelAllUndoObj()
{
    GetDoc()->DelAllUndoObj();
}

// Zusammenfassen von Kontinuierlichen Insert/Delete/Overwrite von
// Charaktern. Default ist sdbcx::Group-Undo.

// setzt Undoklammerung auf, liefert nUndoId der Klammerung

sal_uInt16 SwEditShell::StartUndo( sal_uInt16 nUndoId,
                                   const SwRewriter *pRewriter )
{ return GetDoc()->StartUndo( nUndoId, pRewriter ); }

// schliesst Klammerung der nUndoId, nicht vom UI benutzt

sal_uInt16 SwEditShell::EndUndo(sal_uInt16 nUndoId)
{ return GetDoc()->EndUndo(nUndoId); }

// liefert die Id der letzten undofaehigen Aktion zurueck
// fuellt ggf. VARARR mit sdbcx::User-UndoIds

sal_uInt16 SwEditShell::GetUndoIds(String* pStr,SwUndoIds *pUndoIds) const
{ return GetDoc()->GetUndoIds(pStr,pUndoIds); }

String SwEditShell::GetUndoIdsStr(String* pStr,SwUndoIds *pUndoIds) const
{ return GetDoc()->GetUndoIdsStr(pStr,pUndoIds); }

// liefert die Id der letzten Redofaehigen Aktion zurueck
// fuellt ggf. VARARR mit RedoIds

sal_uInt16 SwEditShell::GetRedoIds(String* pStr,SwUndoIds *pRedoIds) const
{ return GetDoc()->GetRedoIds(pStr,pRedoIds); }

String SwEditShell::GetRedoIdsStr(String* pStr,SwUndoIds *pRedoIds) const
{ return GetDoc()->GetRedoIdsStr(pStr,pRedoIds); }

// liefert die Id der letzten Repeatfaehigen Aktion zurueck
// fuellt ggf. VARARR mit RedoIds

sal_uInt16 SwEditShell::GetRepeatIds(String* pStr, SwUndoIds *pRedoIds) const
{ return GetDoc()->GetRepeatIds(pStr,pRedoIds); }

String SwEditShell::GetRepeatIdsStr(String* pStr, SwUndoIds *pRedoIds) const
{ return GetDoc()->GetRepeatIdsStr(pStr,pRedoIds); }

// AutoKorrektur - JP 27.01.94
void SwEditShell::AutoCorrect( SvxAutoCorrect& rACorr, sal_Bool bInsert,
                                sal_Unicode cChar )
{
    SET_CURR_SHELL( this );

    StartAllAction();

    SwPaM* pCrsr = GetCrsr();
    SwTxtNode* pTNd = pCrsr->GetNode()->GetTxtNode();

    SwAutoCorrDoc aSwAutoCorrDoc( *this, *pCrsr, cChar );
    rACorr.AutoCorrect( aSwAutoCorrDoc,
                    pTNd->GetTxt(), pCrsr->GetPoint()->nContent.GetIndex(),
                    cChar, bInsert );
    if( cChar )
        SaveTblBoxCntnt( pCrsr->GetPoint() );
    EndAllAction();
}

void SwEditShell::SetNewDoc(sal_Bool bNew)
{
    GetDoc()->SetNewDoc(bNew);
}

sal_Bool SwEditShell::GetPrevAutoCorrWord( SvxAutoCorrect& rACorr, String& rWord )
{
    SET_CURR_SHELL( this );

    sal_Bool bRet;
    SwPaM* pCrsr = GetCrsr();
    xub_StrLen nPos = pCrsr->GetPoint()->nContent.GetIndex();
    SwTxtNode* pTNd = pCrsr->GetNode()->GetTxtNode();
    if( pTNd && nPos )
    {
        SwAutoCorrDoc aSwAutoCorrDoc( *this, *pCrsr, 0 );
        bRet = rACorr.GetPrevAutoCorrWord( aSwAutoCorrDoc,
                                            pTNd->GetTxt(), nPos, rWord );
    }
    else
        bRet = sal_False;
    return bRet;
}

SwAutoCompleteWord& SwEditShell::GetAutoCompleteWords()
{
    return SwDoc::GetAutoCompleteWords();
}

<|endoftext|>


<commit_before>#include "ShaderCompiler.h"

#include <cassert>

#include <iostream>
#include <vector>
#include <algorithm>

#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>

#include <iozeug/filename.h>
#include <iozeug/directorytraversal.h>

#include <glbinding/gl/functions.h>

#include <globjects/globjects.h>
#include <globjects/base/File.h>
#include <globjects/NamedString.h>
#include <globjects/Program.h>
#include <globjects/Shader.h>
#include <globjects/logging.h>
#include <globjects/base/File.h>
#include <globjects/base/StringTemplate.h>

#include "OpenGLContext.h"

bool ShaderCompiler::process(const QJsonDocument & configDocument)
{
    return ShaderCompiler{}.parse(configDocument);
}

bool ShaderCompiler::parse(const QJsonDocument & configDocument)
{
    if (!configDocument.isObject())
    {
        error(JsonParseError::DocumentNotAnObject);
        return false;
    }

    const auto config = configDocument.object();
    const auto jsonOpenGLConfig = config.value("opengl");

    if (!jsonOpenGLConfig.isObject())
    {
        error(JsonParseError::PropertyNotFoundOrNotAnObject, "opengl");
        return false;
    }

    auto parseError = JsonParseError{};
    auto context = OpenGLContext::fromJsonConfig(jsonOpenGLConfig.toObject(), &parseError);

    if (parseError)
    {
        error(parseError);
        return false;
    }

    if (!context.create())
    {
        error(JsonParseError::ContextCreationFailed);
        return false;
    }

    if (!context.makeCurrent())
    {
        error(JsonParseError::ContextActivationFailed);
        return false;
    }

    globjects::init();

    info(Info::Driver);

    const auto jsonNamedStringPaths = config.value("namedStringPaths");

    if (jsonNamedStringPaths.isArray())
    {
        if (!parseNamedStringPaths(jsonNamedStringPaths.toArray()))
            return false;
    }

    const auto jsonPrograms = config.value("programs");

    if (!jsonPrograms.isArray())
    {
        error(JsonParseError::ArrayNotFoundOrEmpty, "programs");
        return false;
    }

    auto ok = parsePrograms(jsonPrograms.toArray());

    context.doneCurrent();

    info(Info::Failures);

    return ok;
}

bool ShaderCompiler::parseNamedStringPaths(const QJsonArray & paths)
{
    std::vector<std::string> namedStrings{};

    for (const auto & namedStringPath : paths)
    {
        if (!namedStringPath.isObject())
        {
            error(JsonParseError::ElementNotObject, "namedStringPaths");
            return false;
        }

        const auto pathObject = namedStringPath.toObject();

        const auto pathString = pathObject.value("path").toString();

        if (pathString.isNull())
        {
            error(JsonParseError::PropertyNotFoundOrWrongFormat, "path");
            return false;
        }

        const auto extensionsArray = pathObject.value("extensions").toArray();

        if (extensionsArray.isEmpty())
        {
            error(JsonParseError::ArrayNotFoundOrEmpty, "extensions" );
            return false;
        }

        bool ok{};
        const auto extensions = parseExtensions(extensionsArray, ok);

        if (!ok)
        {
            error(JsonParseError::ElementWrongFormat, "extensions");
            return false;
        }

        auto files = scanDirectory(pathString.toStdString(), extensions);

        if (files.empty())
        {
            error(JsonParseError::NoFilesWithExtensionFound, pathString);
            return false;
        }

        const auto aliasString = pathObject.value("alias").toString();

        auto aliases = files;

        if (!aliasString.isNull())
        {
            aliases = createAliases(files,
                pathString.toStdString(),
                aliasString.toStdString());
        }

        std::copy(aliases.begin(), aliases.end(), std::back_inserter(namedStrings));

        createNamedStrings(files, aliases);
    }

    qDebug() << "Registered Named Strings:";
    for (const auto & namedString : namedStrings)
        qDebug().nospace() << "    " << QString::fromStdString(namedString);

    return true;
}

std::set<std::string> ShaderCompiler::parseExtensions(
    const QJsonArray & extensionsArray,
    bool & ok)
{
    auto extensions = std::set<std::string>{};

    for (const auto & extensionValue : extensionsArray)
    {
        if (!extensionValue.isString())
        {
            ok = false;
            return extensions;
        }

        extensions.insert(extensionValue.toString().toStdString());
    }

    ok = true;
    return extensions;
}

std::vector<std::string> ShaderCompiler::scanDirectory(
    const std::string & path,
    const std::set<std::string> & extensions)
{
    auto files = std::vector<std::string>{};

    iozeug::scanDirectory(path, "*", true,
        [&extensions, &files] (const std::string & fileName)
        {
          const auto fileExtension = iozeug::getExtension(fileName);

          if (!extensions.count(fileExtension))
              return;

          files.push_back(fileName);
        });

    return files;
}

std::vector<std::string> ShaderCompiler::createAliases(
    const std::vector<std::string> & files,
    const std::string & path,
    const std::string & alias)
{
    std::vector<std::string> aliasedFiles{};

    for (const auto & file : files)
    {
        auto aliasedFile = alias;

        assert(file.size() >= path.size());
        std::copy(file.begin() + path.size(), file.end(), std::back_inserter(aliasedFile));

        aliasedFiles.push_back(aliasedFile);
    }

    return aliasedFiles;
}

void ShaderCompiler::createNamedStrings(
    const std::vector<std::string> & files,
    const std::vector<std::string> & aliases)
{
    assert(files.size() == aliases.size());

    for (auto i = 0u; i < files.size(); ++i)
    {
        const auto file = files[i];
        const auto alias = aliases[i];

        const auto fileObject = new globjects::File(file);

        globjects::NamedString::create(alias, fileObject);
    }
}

bool ShaderCompiler::parsePrograms(const QJsonArray & programs)
{
    bool ok{};

    for (const auto programValue : programs)
    {
        if (!programValue.isObject())
        {
            error(JsonParseError::ElementNotObject, "programs");
            return false;
        }

        const auto programObject = programValue.toObject();

        const auto name = programObject.value("name").toString();

        if (name.isNull())
        {
            error(JsonParseError::PropertyNotFoundOrWrongFormat, "name");
            return false;
        }

        qDebug() << "";
        qDebug().noquote() << "Process" << name;

        const auto shadersArray = programObject.value("shaders");

        if (!shadersArray.isArray())
        {
            error(JsonParseError::ArrayNotFoundOrEmpty, "shaders");
            return false;
        }

        const auto shaders = parseShaders(shadersArray.toArray(), ok);

        if (!ok)
        {
            m_linkFailures.push_back(name.toStdString());
            continue;
        }

        qDebug().noquote() << "Link" << name;

        ok = createAndLinkProgram(shaders);

        if (!ok)
            m_linkFailures.push_back(name.toStdString());
    }

    return true;
}

std::vector<globjects::ref_ptr<globjects::Shader>> ShaderCompiler::parseShaders(
    const QJsonArray & shadersArray,
    bool & ok)
{
    std::vector<globjects::ref_ptr<globjects::Shader>> shaders{};

    for (const auto & shaderValue : shadersArray)
    {
        if (!shaderValue.isObject())
        {
            error(JsonParseError::ElementNotObject, "shaders");
            ok = false;
            return shaders;
        }

        const auto shaderObject = shaderValue.toObject();

        const auto fileName = shaderObject.value("file").toString();

        if (fileName.isNull())
        {
            error(JsonParseError::PropertyNotFoundOrWrongFormat, "file");
            ok = false;
            return shaders;
        }

        const auto name = shaderObject.value("name").toString();

        if (name.isNull())
            qDebug().noquote() << QString{"Compile %1"}.arg(fileName);
        else
            qDebug().noquote() << QString{"Compile %1 ('%2')"}.arg(name).arg(fileName);

        const auto typeString = shaderObject.value("type").toString();

        if (typeString.isNull())
        {
            error(JsonParseError::PropertyNotFoundOrWrongFormat, "type");
            ok = false;
            return shaders;
        }

        const auto type = typeFromString(typeString);

        if (type == gl::GL_NONE)
        {
            error(JsonParseError::ShaderTypeNotFound, typeString);
            ok = false;
            return shaders;
        }

        globjects::ref_ptr<globjects::AbstractStringSource> shaderFile = new globjects::File{fileName.toStdString()};

        const auto replacementsValue = shaderObject.value("replacements");

        if (!replacementsValue.isUndefined())
        {
            if (replacementsValue.isObject())
            {
                if (!replaceStrings(replacementsValue.toObject(), shaderFile))
                {
                    ok = false;
                    return shaders;
                }
            }
            else
            {
                error(JsonParseError::PropertyWrongFormat, "replacements");
                ok = false;
                return shaders;
            }
        }

        auto shader = globjects::make_ref<globjects::Shader>(type, shaderFile);

        if (!shader->compile())
        {
            m_compileFailures.push_back(fileName.toStdString());

            ok = false;
            return shaders;
        }

        shaders.push_back(globjects::ref_ptr<globjects::Shader>(shader));
    }

    ok = true;
    return shaders;
}

bool ShaderCompiler::replaceStrings(
    const QJsonObject & replacements,
    globjects::ref_ptr<globjects::AbstractStringSource> & stringSource)
{
    auto sourceTemplate = globjects::make_ref<globjects::StringTemplate>(stringSource);

    for (auto it = replacements.begin(); it != replacements.end(); ++it)
    {
        const auto valueString = it.value().toString();

        if (valueString.isNull())
        {
            error(JsonParseError::PropertyWrongFormat, it.key());
            return false;
        }

        sourceTemplate->replace(it.key().toStdString(), valueString.toStdString());
    }

    stringSource = sourceTemplate;
    return true;
}

gl::GLenum ShaderCompiler::typeFromString(const QString & typeString)
{
    if (typeString == "GL_VERTEX_SHADER")
    {
        return gl::GL_VERTEX_SHADER;
    }
    else if (typeString == "GL_VERTEX_SHADER")
    {
        return gl::GL_TESS_CONTROL_SHADER;
    }
    else if (typeString == "GL_TESS_EVALUATION_SHADER")
    {
        return gl::GL_TESS_EVALUATION_SHADER;
    }
    else if (typeString == "GL_GEOMETRY_SHADER")
    {
        return gl::GL_GEOMETRY_SHADER;
    }
    else if (typeString == "GL_FRAGMENT_SHADER")
    {
        return gl::GL_FRAGMENT_SHADER;
    }
    else if (typeString == "GL_COMPUTE_SHADER")
    {
        return gl::GL_COMPUTE_SHADER;
    }

    return gl::GL_NONE;
}

bool ShaderCompiler::createAndLinkProgram(
    const std::vector<globjects::ref_ptr<globjects::Shader>> & shaders)
{
    auto program = globjects::make_ref<globjects::Program>();

    for (auto & shader : shaders)
        program->attach(shader);

    program->link();

    if (!program->isLinked())
        return false;

    return true;
}

void ShaderCompiler::info(Info type)
{
    if (type == Info::Driver)
    {
        globjects::info() << "Driver: " << globjects::vendor();
        globjects::info() << "Renderer: " << globjects::renderer();
    }
    else if (type == Info::Failures)
    {
        if (!m_compileFailures.empty())
        {
            globjects::info();
            globjects::info() << "Compile Failures:";
            for (const auto failure : m_compileFailures)
                globjects::info() << "    " << failure;
        }

        if (!m_linkFailures.empty())
        {
            globjects::info();
            globjects::info() << "Link Failures:";
            for (const auto failure : m_linkFailures)
                globjects::info() << "    " << failure;
        }
    }
}

void ShaderCompiler::error(JsonParseError error)
{
    m_errorLog.error(error);
}

void ShaderCompiler::error(JsonParseError::Type type, const QString & info)
{
    m_errorLog.error({ type, info });
}
<commit_msg>Rename aliasedFiles to aliases<commit_after>#include "ShaderCompiler.h"

#include <cassert>

#include <iostream>
#include <vector>
#include <algorithm>

#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>

#include <iozeug/filename.h>
#include <iozeug/directorytraversal.h>

#include <glbinding/gl/functions.h>

#include <globjects/globjects.h>
#include <globjects/base/File.h>
#include <globjects/NamedString.h>
#include <globjects/Program.h>
#include <globjects/Shader.h>
#include <globjects/logging.h>
#include <globjects/base/File.h>
#include <globjects/base/StringTemplate.h>

#include "OpenGLContext.h"

bool ShaderCompiler::process(const QJsonDocument & configDocument)
{
    return ShaderCompiler{}.parse(configDocument);
}

bool ShaderCompiler::parse(const QJsonDocument & configDocument)
{
    if (!configDocument.isObject())
    {
        error(JsonParseError::DocumentNotAnObject);
        return false;
    }

    const auto config = configDocument.object();
    const auto jsonOpenGLConfig = config.value("opengl");

    if (!jsonOpenGLConfig.isObject())
    {
        error(JsonParseError::PropertyNotFoundOrNotAnObject, "opengl");
        return false;
    }

    auto parseError = JsonParseError{};
    auto context = OpenGLContext::fromJsonConfig(jsonOpenGLConfig.toObject(), &parseError);

    if (parseError)
    {
        error(parseError);
        return false;
    }

    if (!context.create())
    {
        error(JsonParseError::ContextCreationFailed);
        return false;
    }

    if (!context.makeCurrent())
    {
        error(JsonParseError::ContextActivationFailed);
        return false;
    }

    globjects::init();

    info(Info::Driver);

    const auto jsonNamedStringPaths = config.value("namedStringPaths");

    if (jsonNamedStringPaths.isArray())
    {
        if (!parseNamedStringPaths(jsonNamedStringPaths.toArray()))
            return false;
    }

    const auto jsonPrograms = config.value("programs");

    if (!jsonPrograms.isArray())
    {
        error(JsonParseError::ArrayNotFoundOrEmpty, "programs");
        return false;
    }

    auto ok = parsePrograms(jsonPrograms.toArray());

    context.doneCurrent();

    info(Info::Failures);

    return ok;
}

bool ShaderCompiler::parseNamedStringPaths(const QJsonArray & paths)
{
    std::vector<std::string> namedStrings{};

    for (const auto & namedStringPath : paths)
    {
        if (!namedStringPath.isObject())
        {
            error(JsonParseError::ElementNotObject, "namedStringPaths");
            return false;
        }

        const auto pathObject = namedStringPath.toObject();

        const auto pathString = pathObject.value("path").toString();

        if (pathString.isNull())
        {
            error(JsonParseError::PropertyNotFoundOrWrongFormat, "path");
            return false;
        }

        const auto extensionsArray = pathObject.value("extensions").toArray();

        if (extensionsArray.isEmpty())
        {
            error(JsonParseError::ArrayNotFoundOrEmpty, "extensions" );
            return false;
        }

        bool ok{};
        const auto extensions = parseExtensions(extensionsArray, ok);

        if (!ok)
        {
            error(JsonParseError::ElementWrongFormat, "extensions");
            return false;
        }

        auto files = scanDirectory(pathString.toStdString(), extensions);

        if (files.empty())
        {
            error(JsonParseError::NoFilesWithExtensionFound, pathString);
            return false;
        }

        const auto aliasString = pathObject.value("alias").toString();

        auto aliases = files;

        if (!aliasString.isNull())
        {
            aliases = createAliases(files,
                pathString.toStdString(),
                aliasString.toStdString());
        }

        std::copy(aliases.begin(), aliases.end(), std::back_inserter(namedStrings));

        createNamedStrings(files, aliases);
    }

    qDebug() << "Registered Named Strings:";
    for (const auto & namedString : namedStrings)
        qDebug().nospace() << "    " << QString::fromStdString(namedString);

    return true;
}

std::set<std::string> ShaderCompiler::parseExtensions(
    const QJsonArray & extensionsArray,
    bool & ok)
{
    auto extensions = std::set<std::string>{};

    for (const auto & extensionValue : extensionsArray)
    {
        if (!extensionValue.isString())
        {
            ok = false;
            return extensions;
        }

        extensions.insert(extensionValue.toString().toStdString());
    }

    ok = true;
    return extensions;
}

std::vector<std::string> ShaderCompiler::scanDirectory(
    const std::string & path,
    const std::set<std::string> & extensions)
{
    auto files = std::vector<std::string>{};

    iozeug::scanDirectory(path, "*", true,
        [&extensions, &files] (const std::string & fileName)
        {
          const auto fileExtension = iozeug::getExtension(fileName);

          if (!extensions.count(fileExtension))
              return;

          files.push_back(fileName);
        });

    return files;
}

std::vector<std::string> ShaderCompiler::createAliases(
    const std::vector<std::string> & files,
    const std::string & path,
    const std::string & alias)
{
    std::vector<std::string> aliases{};

    for (const auto & file : files)
    {
        auto aliasedFile = alias;

        assert(file.size() >= path.size());
        std::copy(file.begin() + path.size(), file.end(), std::back_inserter(aliasedFile));

        aliases.push_back(aliasedFile);
    }

    return aliases;
}

void ShaderCompiler::createNamedStrings(
    const std::vector<std::string> & files,
    const std::vector<std::string> & aliases)
{
    assert(files.size() == aliases.size());

    for (auto i = 0u; i < files.size(); ++i)
    {
        const auto file = files[i];
        const auto alias = aliases[i];

        const auto fileObject = new globjects::File(file);

        globjects::NamedString::create(alias, fileObject);
    }
}

bool ShaderCompiler::parsePrograms(const QJsonArray & programs)
{
    bool ok{};

    for (const auto programValue : programs)
    {
        if (!programValue.isObject())
        {
            error(JsonParseError::ElementNotObject, "programs");
            return false;
        }

        const auto programObject = programValue.toObject();

        const auto name = programObject.value("name").toString();

        if (name.isNull())
        {
            error(JsonParseError::PropertyNotFoundOrWrongFormat, "name");
            return false;
        }

        qDebug() << "";
        qDebug().noquote() << "Process" << name;

        const auto shadersArray = programObject.value("shaders");

        if (!shadersArray.isArray())
        {
            error(JsonParseError::ArrayNotFoundOrEmpty, "shaders");
            return false;
        }

        const auto shaders = parseShaders(shadersArray.toArray(), ok);

        if (!ok)
        {
            m_linkFailures.push_back(name.toStdString());
            continue;
        }

        qDebug().noquote() << "Link" << name;

        ok = createAndLinkProgram(shaders);

        if (!ok)
            m_linkFailures.push_back(name.toStdString());
    }

    return true;
}

std::vector<globjects::ref_ptr<globjects::Shader>> ShaderCompiler::parseShaders(
    const QJsonArray & shadersArray,
    bool & ok)
{
    std::vector<globjects::ref_ptr<globjects::Shader>> shaders{};

    for (const auto & shaderValue : shadersArray)
    {
        if (!shaderValue.isObject())
        {
            error(JsonParseError::ElementNotObject, "shaders");
            ok = false;
            return shaders;
        }

        const auto shaderObject = shaderValue.toObject();

        const auto fileName = shaderObject.value("file").toString();

        if (fileName.isNull())
        {
            error(JsonParseError::PropertyNotFoundOrWrongFormat, "file");
            ok = false;
            return shaders;
        }

        const auto name = shaderObject.value("name").toString();

        if (name.isNull())
            qDebug().noquote() << QString{"Compile %1"}.arg(fileName);
        else
            qDebug().noquote() << QString{"Compile %1 ('%2')"}.arg(name).arg(fileName);

        const auto typeString = shaderObject.value("type").toString();

        if (typeString.isNull())
        {
            error(JsonParseError::PropertyNotFoundOrWrongFormat, "type");
            ok = false;
            return shaders;
        }

        const auto type = typeFromString(typeString);

        if (type == gl::GL_NONE)
        {
            error(JsonParseError::ShaderTypeNotFound, typeString);
            ok = false;
            return shaders;
        }

        globjects::ref_ptr<globjects::AbstractStringSource> shaderFile = new globjects::File{fileName.toStdString()};

        const auto replacementsValue = shaderObject.value("replacements");

        if (!replacementsValue.isUndefined())
        {
            if (replacementsValue.isObject())
            {
                if (!replaceStrings(replacementsValue.toObject(), shaderFile))
                {
                    ok = false;
                    return shaders;
                }
            }
            else
            {
                error(JsonParseError::PropertyWrongFormat, "replacements");
                ok = false;
                return shaders;
            }
        }

        auto shader = globjects::make_ref<globjects::Shader>(type, shaderFile);

        if (!shader->compile())
        {
            m_compileFailures.push_back(fileName.toStdString());

            ok = false;
            return shaders;
        }

        shaders.push_back(globjects::ref_ptr<globjects::Shader>(shader));
    }

    ok = true;
    return shaders;
}

bool ShaderCompiler::replaceStrings(
    const QJsonObject & replacements,
    globjects::ref_ptr<globjects::AbstractStringSource> & stringSource)
{
    auto sourceTemplate = globjects::make_ref<globjects::StringTemplate>(stringSource);

    for (auto it = replacements.begin(); it != replacements.end(); ++it)
    {
        const auto valueString = it.value().toString();

        if (valueString.isNull())
        {
            error(JsonParseError::PropertyWrongFormat, it.key());
            return false;
        }

        sourceTemplate->replace(it.key().toStdString(), valueString.toStdString());
    }

    stringSource = sourceTemplate;
    return true;
}

gl::GLenum ShaderCompiler::typeFromString(const QString & typeString)
{
    if (typeString == "GL_VERTEX_SHADER")
    {
        return gl::GL_VERTEX_SHADER;
    }
    else if (typeString == "GL_VERTEX_SHADER")
    {
        return gl::GL_TESS_CONTROL_SHADER;
    }
    else if (typeString == "GL_TESS_EVALUATION_SHADER")
    {
        return gl::GL_TESS_EVALUATION_SHADER;
    }
    else if (typeString == "GL_GEOMETRY_SHADER")
    {
        return gl::GL_GEOMETRY_SHADER;
    }
    else if (typeString == "GL_FRAGMENT_SHADER")
    {
        return gl::GL_FRAGMENT_SHADER;
    }
    else if (typeString == "GL_COMPUTE_SHADER")
    {
        return gl::GL_COMPUTE_SHADER;
    }

    return gl::GL_NONE;
}

bool ShaderCompiler::createAndLinkProgram(
    const std::vector<globjects::ref_ptr<globjects::Shader>> & shaders)
{
    auto program = globjects::make_ref<globjects::Program>();

    for (auto & shader : shaders)
        program->attach(shader);

    program->link();

    if (!program->isLinked())
        return false;

    return true;
}

void ShaderCompiler::info(Info type)
{
    if (type == Info::Driver)
    {
        globjects::info() << "Driver: " << globjects::vendor();
        globjects::info() << "Renderer: " << globjects::renderer();
    }
    else if (type == Info::Failures)
    {
        if (!m_compileFailures.empty())
        {
            globjects::info();
            globjects::info() << "Compile Failures:";
            for (const auto failure : m_compileFailures)
                globjects::info() << "    " << failure;
        }

        if (!m_linkFailures.empty())
        {
            globjects::info();
            globjects::info() << "Link Failures:";
            for (const auto failure : m_linkFailures)
                globjects::info() << "    " << failure;
        }
    }
}

void ShaderCompiler::error(JsonParseError error)
{
    m_errorLog.error(error);
}

void ShaderCompiler::error(JsonParseError::Type type, const QString & info)
{
    m_errorLog.error({ type, info });
}
<|endoftext|>


<commit_before>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011  Martin Raiber
*
*    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 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#ifndef CLIENT_ONLY

#include "server.h"
#include "../Interface/Server.h"
#include "../Interface/Database.h"
#include "../Interface/ThreadPool.h"
#include "server_get.h"
#include "database.h"
#include "../Interface/SettingsReader.h"
#include "server_status.h"
#include "../stringtools.h"
#include "../urbackupcommon/os_functions.h"
#include "InternetServiceConnector.h"
#include "../Interface/PipeThrottler.h"
#include <memory.h>

const unsigned int waittime=50*1000; //1 min
const int max_offline=5;

IPipeThrottler *BackupServer::global_internet_throttler=NULL;
IPipeThrottler *BackupServer::global_local_throttler=NULL;
IMutex *BackupServer::throttle_mutex=NULL;

BackupServer::BackupServer(IPipe *pExitpipe)
{
	throttle_mutex=Server->createMutex();
	exitpipe=pExitpipe;

	if(Server->getServerParameter("internet_test_mode")=="true")
		internet_test_mode=true;
	else
		internet_test_mode=false;
}

BackupServer::~BackupServer()
{
	Server->destroy(throttle_mutex);
}

void BackupServer::operator()(void)
{
	IDatabase *db=Server->getDatabase(Server->getThreadID(),URBACKUPDB_SERVER);
	ISettingsReader *settings=Server->createDBSettingsReader(Server->getDatabase(Server->getThreadID(),URBACKUPDB_SERVER), "settings_db.settings");

#ifdef _WIN32
	std::wstring tmpdir;
	if(settings->getValue(L"tmpdir", &tmpdir) && !tmpdir.empty())
	{
		os_remove_nonempty_dir(tmpdir+os_file_sep()+L"urbackup_tmp");
		if(!os_create_dir(tmpdir+os_file_sep()+L"urbackup_tmp"))
		{
			Server->wait(5000);
			os_create_dir(tmpdir+os_file_sep()+L"urbackup_tmp");
		}
		Server->setTemporaryDirectory(tmpdir+os_file_sep()+L"urbackup_tmp");
	}
	else
	{
		wchar_t tmpp[MAX_PATH];
		DWORD l;
		if((l=GetTempPathW(MAX_PATH, tmpp))==0 || l>MAX_PATH )
		{
			wcscpy_s(tmpp,L"C:\\");
		}

		std::wstring w_tmp=tmpp;

		if(!w_tmp.empty() && w_tmp[w_tmp.size()-1]=='\\')
		{
			w_tmp.erase(w_tmp.size()-1, 1);		}

		os_remove_nonempty_dir(w_tmp+os_file_sep()+L"urbackup_tmp");
		if(!os_create_dir(w_tmp+os_file_sep()+L"urbackup_tmp"))
		{
			Server->wait(5000);
			os_create_dir(tmpdir+os_file_sep()+L"urbackup_tmp");
		}
		Server->setTemporaryDirectory(w_tmp+os_file_sep()+L"urbackup_tmp");
	}
#endif

	q_get_extra_hostnames=db->Prepare("SELECT id,hostname FROM settings_db.extra_clients");
	q_update_extra_ip=db->Prepare("UPDATE settings_db.extra_clients SET lastip=? WHERE id=?");

	FileClient fc;

	Server->wait(1000);

	while(true)
	{
		findClients(fc);
		startClients(fc);

		if(!ServerStatus::isActive() && settings->getValue("autoshutdown", "false")=="true")
		{
			writestring("true", "urbackup/shutdown_now");
#ifdef _WIN32
			ExitWindowsEx(EWX_POWEROFF|EWX_FORCEIFHUNG, SHTDN_REASON_MAJOR_APPLICATION|SHTDN_REASON_MINOR_OTHER );
#endif
		}

		std::string r;
		exitpipe->Read(&r, waittime);
		if(r=="exit")
		{
			removeAllClients();
			exitpipe->Write("ok");
			Server->destroy(settings);
			db->destroyAllQueries();
			delete this;
			return;
		}
	}
}

void BackupServer::findClients(FileClient &fc)
{
	db_results res=q_get_extra_hostnames->Read();
	q_get_extra_hostnames->Reset();

	std::vector<in_addr> addr_hints;

	for(size_t i=0;i<res.size();++i)
	{
		unsigned int dest;
		bool b=os_lookuphostname(Server->ConvertToUTF8(res[i][L"hostname"]), &dest);
		if(b)
		{
			q_update_extra_ip->Bind((_i64)dest);
			q_update_extra_ip->Bind(res[i][L"id"]);
			q_update_extra_ip->Write();
			q_update_extra_ip->Reset();

			in_addr tmp;
			tmp.s_addr=dest;
			addr_hints.push_back(tmp);
		}
	}

	_u32 rc=fc.GetServers(true, addr_hints);
	while(rc==ERR_CONTINUE)
	{
		Server->wait(50);
		rc=fc.GetServers(false, addr_hints);
	}

	if(rc==ERR_ERROR)
	{
		Server->Log("Error in BackupServer::findClients rc==ERR_ERROR",LL_ERROR);
	}
}

void BackupServer::startClients(FileClient &fc)
{
	std::vector<std::wstring> names;
	std::vector<sockaddr_in> servers;

	if(!internet_test_mode)
	{
		names=fc.getServerNames();
		servers=fc.getServers();
	}

	std::vector<bool> inetclient;
	inetclient.resize(names.size());
	std::fill(inetclient.begin(), inetclient.end(), false);
	std::vector<std::string> anames=InternetServiceConnector::getOnlineClients();
	for(size_t i=0;i<anames.size();++i)
	{
		names.push_back(Server->ConvertToUnicode(anames[i]));
		inetclient.push_back(true);
		sockaddr_in n;
		memset(&n, 0, sizeof(sockaddr_in));
		servers.push_back(n);
	}

	for(size_t i=0;i<names.size();++i)
	{
		names[i]=Server->ConvertToUnicode(conv_filename(Server->ConvertToUTF8(names[i])));
		std::map<std::wstring, SClient>::iterator it=clients.find(names[i]);
		if( it==clients.end() )
		{
			if(inetclient[i]==true)
			{
				bool skip=false;
				for(size_t j=0;j<names.size();++j)
				{
					if(i!=j && names[i]==names[j] && inetclient[j]==false)
					{
						skip=true;
						break;
					}
				}
				if(skip)
					continue;
			}

			Server->Log(L"New Backupclient: "+names[i]);
			ServerStatus::setOnline(names[i], true);
			IPipe *np=Server->createMemoryPipe();

			BackupServerGet *client=new BackupServerGet(np, servers[i], names[i], inetclient[i]);
			Server->getThreadPool()->execute(client);

			SClient c;
			c.pipe=np;
			c.offlinecount=0;
			c.addr=servers[i];
			c.internet_connection=inetclient[i];

			ServerStatus::setIP(names[i], c.addr.sin_addr.s_addr);

			clients.insert(std::pair<std::wstring, SClient>(names[i], c) );
		}
		else if(it->second.offlinecount<max_offline)
		{
			bool found_lan=false;
			if(inetclient[i]==false && it->second.internet_connection==true)
			{
				found_lan=true;
			}

			if(it->second.addr.sin_addr.s_addr==servers[i].sin_addr.s_addr && !found_lan)
			{
				it->second.offlinecount=0;
			}
			else
			{
				bool none_fits=true;
				for(size_t j=0;j<names.size();++j)
				{
					if(i!=j && names[j]==names[i] && it->second.addr.sin_addr.s_addr==servers[j].sin_addr.s_addr)
					{
						none_fits=false;
						break;
					}
				}
				if(none_fits || found_lan)
				{
					it->second.addr=servers[i];
					std::string msg;
					msg.resize(7+sizeof(sockaddr_in)+1);
					msg[0]='a'; msg[1]='d'; msg[2]='d'; msg[3]='r'; msg[4]='e'; msg[5]='s'; msg[6]='s';
					memcpy(&msg[7], &it->second.addr, sizeof(sockaddr_in));
					msg[7+sizeof(sockaddr_in)]=(inetclient[i]==true?1:0);
					it->second.pipe->Write(msg);

					char *ip=(char*)&it->second.addr.sin_addr.s_addr;

					Server->Log("New client address: "+nconvert((unsigned char)ip[0])+"."+nconvert((unsigned char)ip[1])+"."+nconvert((unsigned char)ip[2])+"."+nconvert((unsigned char)ip[3]), LL_INFO);

					ServerStatus::setIP(names[i], it->second.addr.sin_addr.s_addr);

					it->second.offlinecount=0;
				}
			}
		}
	}

	bool c=true;
	size_t maxi=0;
	while(c && !clients.empty())
	{
		c=false;

		size_t i_c=0;
		for(std::map<std::wstring, SClient>::iterator it=clients.begin();it!=clients.end();++it)
		{
			bool found=false;
			for(size_t i=0;i<names.size();++i)
			{
				if( it->first==names[i] )
				{
					found=true;
					break;
				}
			}
			if( found==false || it->second.offlinecount>max_offline)
			{
				if(it->second.offlinecount==max_offline)
				{
					Server->Log(L"Client exitet: "+it->first);
					it->second.pipe->Write("exit");
					++it->second.offlinecount;
					ServerStatus::setOnline(it->first, false);
				}
				else if(it->second.offlinecount>max_offline)
				{
					std::string msg;
					std::vector<std::string> msgs;
					while(it->second.pipe->Read(&msg,0)>0)
					{
						if(msg!="ok")
						{
							msgs.push_back(msg);
						}
						else
						{
							Server->Log(L"Client finished: "+it->first);
							ServerStatus::setDone(it->first, true);
							Server->destroy(it->second.pipe);
							clients.erase(it);
							maxi=i_c;
							c=true;
							break;
						}
					}
					if( c==false )
					{
						for(size_t i=0;i<msgs.size();++i)
						{
							it->second.pipe->Write(msgs[i]);
						}
					}
					else
					{
						break;
					}
				}
				else if(i_c>=maxi)
				{
					SStatusAction s_action=ServerStatus::getStatus(it->first).statusaction;

					if(s_action==sa_none)
					{
						++it->second.offlinecount;
					}
				}
			}
			++i_c;
		}
	}
}

void BackupServer::removeAllClients(void)
{
	for(std::map<std::wstring, SClient>::iterator it=clients.begin();it!=clients.end();++it)
	{
		it->second.pipe->Write("exitnow");
		std::string msg;
		while(msg!="ok")
		{
			it->second.pipe->Read(&msg);
			it->second.pipe->Write(msg.c_str());
			Server->wait(500);
		}
		Server->destroy(it->second.pipe);
	}
}

IPipeThrottler *BackupServer::getGlobalInternetThrottler(size_t speed_bps)
{
	IScopedLock lock(throttle_mutex);

	if(global_internet_throttler==NULL && speed_bps==0 )
		return NULL;

	if(global_internet_throttler==NULL)
	{
		global_internet_throttler=Server->createPipeThrottler(speed_bps);
	}
	else
	{
		global_internet_throttler->changeThrottleLimit(speed_bps);
	}
	return global_internet_throttler;
}

IPipeThrottler *BackupServer::getGlobalLocalThrottler(size_t speed_bps)
{
	IScopedLock lock(throttle_mutex);

	if(global_local_throttler==NULL && speed_bps==0 )
		return NULL;

	if(global_local_throttler==NULL)
	{
		global_local_throttler=Server->createPipeThrottler(speed_bps);
	}
	else
	{
		global_local_throttler->changeThrottleLimit(speed_bps);
	}
	return global_local_throttler;
}

void BackupServer::cleanupThrottlers(void)
{
	if(global_internet_throttler!=NULL)
	{
		Server->destroy(global_internet_throttler);
	}
	if(global_local_throttler!=NULL)
	{
		Server->destroy(global_local_throttler);
	}
}

#endif //CLIENT_ONLY
<commit_msg>Correctly skip internet connections if the client is available locally<commit_after>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011  Martin Raiber
*
*    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 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#ifndef CLIENT_ONLY

#include "server.h"
#include "../Interface/Server.h"
#include "../Interface/Database.h"
#include "../Interface/ThreadPool.h"
#include "server_get.h"
#include "database.h"
#include "../Interface/SettingsReader.h"
#include "server_status.h"
#include "../stringtools.h"
#include "../urbackupcommon/os_functions.h"
#include "InternetServiceConnector.h"
#include "../Interface/PipeThrottler.h"
#include <memory.h>

const unsigned int waittime=50*1000; //1 min
const int max_offline=5;

IPipeThrottler *BackupServer::global_internet_throttler=NULL;
IPipeThrottler *BackupServer::global_local_throttler=NULL;
IMutex *BackupServer::throttle_mutex=NULL;

BackupServer::BackupServer(IPipe *pExitpipe)
{
	throttle_mutex=Server->createMutex();
	exitpipe=pExitpipe;

	if(Server->getServerParameter("internet_test_mode")=="true")
		internet_test_mode=true;
	else
		internet_test_mode=false;
}

BackupServer::~BackupServer()
{
	Server->destroy(throttle_mutex);
}

void BackupServer::operator()(void)
{
	IDatabase *db=Server->getDatabase(Server->getThreadID(),URBACKUPDB_SERVER);
	ISettingsReader *settings=Server->createDBSettingsReader(Server->getDatabase(Server->getThreadID(),URBACKUPDB_SERVER), "settings_db.settings");

#ifdef _WIN32
	std::wstring tmpdir;
	if(settings->getValue(L"tmpdir", &tmpdir) && !tmpdir.empty())
	{
		os_remove_nonempty_dir(tmpdir+os_file_sep()+L"urbackup_tmp");
		if(!os_create_dir(tmpdir+os_file_sep()+L"urbackup_tmp"))
		{
			Server->wait(5000);
			os_create_dir(tmpdir+os_file_sep()+L"urbackup_tmp");
		}
		Server->setTemporaryDirectory(tmpdir+os_file_sep()+L"urbackup_tmp");
	}
	else
	{
		wchar_t tmpp[MAX_PATH];
		DWORD l;
		if((l=GetTempPathW(MAX_PATH, tmpp))==0 || l>MAX_PATH )
		{
			wcscpy_s(tmpp,L"C:\\");
		}

		std::wstring w_tmp=tmpp;

		if(!w_tmp.empty() && w_tmp[w_tmp.size()-1]=='\\')
		{
			w_tmp.erase(w_tmp.size()-1, 1);		}

		os_remove_nonempty_dir(w_tmp+os_file_sep()+L"urbackup_tmp");
		if(!os_create_dir(w_tmp+os_file_sep()+L"urbackup_tmp"))
		{
			Server->wait(5000);
			os_create_dir(tmpdir+os_file_sep()+L"urbackup_tmp");
		}
		Server->setTemporaryDirectory(w_tmp+os_file_sep()+L"urbackup_tmp");
	}
#endif

	q_get_extra_hostnames=db->Prepare("SELECT id,hostname FROM settings_db.extra_clients");
	q_update_extra_ip=db->Prepare("UPDATE settings_db.extra_clients SET lastip=? WHERE id=?");

	FileClient fc;

	Server->wait(1000);

	while(true)
	{
		findClients(fc);
		startClients(fc);

		if(!ServerStatus::isActive() && settings->getValue("autoshutdown", "false")=="true")
		{
			writestring("true", "urbackup/shutdown_now");
#ifdef _WIN32
			ExitWindowsEx(EWX_POWEROFF|EWX_FORCEIFHUNG, SHTDN_REASON_MAJOR_APPLICATION|SHTDN_REASON_MINOR_OTHER );
#endif
		}

		std::string r;
		exitpipe->Read(&r, waittime);
		if(r=="exit")
		{
			removeAllClients();
			exitpipe->Write("ok");
			Server->destroy(settings);
			db->destroyAllQueries();
			delete this;
			return;
		}
	}
}

void BackupServer::findClients(FileClient &fc)
{
	db_results res=q_get_extra_hostnames->Read();
	q_get_extra_hostnames->Reset();

	std::vector<in_addr> addr_hints;

	for(size_t i=0;i<res.size();++i)
	{
		unsigned int dest;
		bool b=os_lookuphostname(Server->ConvertToUTF8(res[i][L"hostname"]), &dest);
		if(b)
		{
			q_update_extra_ip->Bind((_i64)dest);
			q_update_extra_ip->Bind(res[i][L"id"]);
			q_update_extra_ip->Write();
			q_update_extra_ip->Reset();

			in_addr tmp;
			tmp.s_addr=dest;
			addr_hints.push_back(tmp);
		}
	}

	_u32 rc=fc.GetServers(true, addr_hints);
	while(rc==ERR_CONTINUE)
	{
		Server->wait(50);
		rc=fc.GetServers(false, addr_hints);
	}

	if(rc==ERR_ERROR)
	{
		Server->Log("Error in BackupServer::findClients rc==ERR_ERROR",LL_ERROR);
	}
}

void BackupServer::startClients(FileClient &fc)
{
	std::vector<std::wstring> names;
	std::vector<sockaddr_in> servers;

	if(!internet_test_mode)
	{
		names=fc.getServerNames();
		servers=fc.getServers();
	}

	for(size_t i=0;i<names.size();++i)
	{
		names[i]=Server->ConvertToUnicode(conv_filename(Server->ConvertToUTF8(names[i])));
	}

	std::vector<bool> inetclient;
	inetclient.resize(names.size());
	std::fill(inetclient.begin(), inetclient.end(), false);
	std::vector<std::string> anames=InternetServiceConnector::getOnlineClients();
	for(size_t i=0;i<anames.size();++i)
	{
		std::wstring new_name=Server->ConvertToUnicode(conv_filename(anames[i]));
		bool skip=false;
		for(size_t j=0;j<names.size();++j)
		{
			if( new_name==names[j] )
			{
				skip=true;
				break;
			}
		}
		if(skip)
			continue;

		names.push_back(new_name);
		inetclient.push_back(true);
		sockaddr_in n;
		memset(&n, 0, sizeof(sockaddr_in));
		servers.push_back(n);
	}

	for(size_t i=0;i<names.size();++i)
	{
		std::map<std::wstring, SClient>::iterator it=clients.find(names[i]);
		if( it==clients.end() )
		{
			Server->Log(L"New Backupclient: "+names[i]);
			ServerStatus::setOnline(names[i], true);
			IPipe *np=Server->createMemoryPipe();

			BackupServerGet *client=new BackupServerGet(np, servers[i], names[i], inetclient[i]);
			Server->getThreadPool()->execute(client);

			SClient c;
			c.pipe=np;
			c.offlinecount=0;
			c.addr=servers[i];
			c.internet_connection=inetclient[i];

			ServerStatus::setIP(names[i], c.addr.sin_addr.s_addr);

			clients.insert(std::pair<std::wstring, SClient>(names[i], c) );
		}
		else if(it->second.offlinecount<max_offline)
		{
			bool found_lan=false;
			if(inetclient[i]==false && it->second.internet_connection==true)
			{
				found_lan=true;
			}

			if(it->second.addr.sin_addr.s_addr==servers[i].sin_addr.s_addr && !found_lan)
			{
				it->second.offlinecount=0;
			}
			else
			{
				bool none_fits=true;
				for(size_t j=0;j<names.size();++j)
				{
					if(i!=j && names[j]==names[i] && it->second.addr.sin_addr.s_addr==servers[j].sin_addr.s_addr)
					{
						none_fits=false;
						break;
					}
				}
				if(none_fits || found_lan)
				{
					it->second.addr=servers[i];
					std::string msg;
					msg.resize(7+sizeof(sockaddr_in)+1);
					msg[0]='a'; msg[1]='d'; msg[2]='d'; msg[3]='r'; msg[4]='e'; msg[5]='s'; msg[6]='s';
					memcpy(&msg[7], &it->second.addr, sizeof(sockaddr_in));
					msg[7+sizeof(sockaddr_in)]=(inetclient[i]==true?1:0);
					it->second.pipe->Write(msg);

					char *ip=(char*)&it->second.addr.sin_addr.s_addr;

					Server->Log("New client address: "+nconvert((unsigned char)ip[0])+"."+nconvert((unsigned char)ip[1])+"."+nconvert((unsigned char)ip[2])+"."+nconvert((unsigned char)ip[3]), LL_INFO);

					ServerStatus::setIP(names[i], it->second.addr.sin_addr.s_addr);

					it->second.offlinecount=0;
				}
			}
		}
	}

	bool c=true;
	size_t maxi=0;
	while(c && !clients.empty())
	{
		c=false;

		size_t i_c=0;
		for(std::map<std::wstring, SClient>::iterator it=clients.begin();it!=clients.end();++it)
		{
			bool found=false;
			for(size_t i=0;i<names.size();++i)
			{
				if( it->first==names[i] )
				{
					found=true;
					break;
				}
			}
			if( found==false || it->second.offlinecount>max_offline)
			{
				if(it->second.offlinecount==max_offline)
				{
					Server->Log(L"Client exitet: "+it->first);
					it->second.pipe->Write("exit");
					++it->second.offlinecount;
					ServerStatus::setOnline(it->first, false);
				}
				else if(it->second.offlinecount>max_offline)
				{
					std::string msg;
					std::vector<std::string> msgs;
					while(it->second.pipe->Read(&msg,0)>0)
					{
						if(msg!="ok")
						{
							msgs.push_back(msg);
						}
						else
						{
							Server->Log(L"Client finished: "+it->first);
							ServerStatus::setDone(it->first, true);
							Server->destroy(it->second.pipe);
							clients.erase(it);
							maxi=i_c;
							c=true;
							break;
						}
					}
					if( c==false )
					{
						for(size_t i=0;i<msgs.size();++i)
						{
							it->second.pipe->Write(msgs[i]);
						}
					}
					else
					{
						break;
					}
				}
				else if(i_c>=maxi)
				{
					SStatusAction s_action=ServerStatus::getStatus(it->first).statusaction;

					if(s_action==sa_none)
					{
						++it->second.offlinecount;
					}
				}
			}
			++i_c;
		}
	}
}

void BackupServer::removeAllClients(void)
{
	for(std::map<std::wstring, SClient>::iterator it=clients.begin();it!=clients.end();++it)
	{
		it->second.pipe->Write("exitnow");
		std::string msg;
		while(msg!="ok")
		{
			it->second.pipe->Read(&msg);
			it->second.pipe->Write(msg.c_str());
			Server->wait(500);
		}
		Server->destroy(it->second.pipe);
	}
}

IPipeThrottler *BackupServer::getGlobalInternetThrottler(size_t speed_bps)
{
	IScopedLock lock(throttle_mutex);

	if(global_internet_throttler==NULL && speed_bps==0 )
		return NULL;

	if(global_internet_throttler==NULL)
	{
		global_internet_throttler=Server->createPipeThrottler(speed_bps);
	}
	else
	{
		global_internet_throttler->changeThrottleLimit(speed_bps);
	}
	return global_internet_throttler;
}

IPipeThrottler *BackupServer::getGlobalLocalThrottler(size_t speed_bps)
{
	IScopedLock lock(throttle_mutex);

	if(global_local_throttler==NULL && speed_bps==0 )
		return NULL;

	if(global_local_throttler==NULL)
	{
		global_local_throttler=Server->createPipeThrottler(speed_bps);
	}
	else
	{
		global_local_throttler->changeThrottleLimit(speed_bps);
	}
	return global_local_throttler;
}

void BackupServer::cleanupThrottlers(void)
{
	if(global_internet_throttler!=NULL)
	{
		Server->destroy(global_internet_throttler);
	}
	if(global_local_throttler!=NULL)
	{
		Server->destroy(global_local_throttler);
	}
}

#endif //CLIENT_ONLY
<|endoftext|>


<commit_before>///
/// @file  print.cpp
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <print.hpp>
#include <primecount-internal.hpp>
#include <int128_t.hpp>
#include <stdint.h>

#include <iostream>
#include <iomanip>
#include <string>

using namespace std;

namespace {

bool print_ = false;
bool print_variables_ = false;

bool is_print_variables()
{
  return print_variables_;
}

} // naespace

namespace primecount {

void set_print(bool print)
{
#ifdef ENABLE_MPI
  print_ = print && is_mpi_main_proc();
#else
  print_ = print;
#endif
}

void set_print_variables(bool print_variables)
{
#ifdef ENABLE_MPI
  print_variables_ = print_variables && is_mpi_main_proc();
#else
  print_variables_ = print_variables;
#endif
}

bool is_print()
{
  return print_;
}

/// The final combined result is always shown at
/// the end even if is_print = false. It is only
/// not shown for partial formulas.
///
bool is_print_combined_result()
{
#ifdef ENABLE_MPI
  return !is_print_variables() && is_mpi_main_proc();
#else
  return !is_print_variables();
#endif
}

void print_threads(int threads)
{
#ifdef ENABLE_MPI
  cout << "processes = " << mpi_num_procs() << endl;
  cout << "threads = " << mpi_num_procs() << " * " << threads << endl;
#else
  cout << "threads = " << threads << endl;
#endif
}

void print_seconds(double seconds)
{
  cout << "Seconds: " << fixed << setprecision(3) << seconds << endl;
}

void print(const string& str)
{
  if (is_print())
    cout << str << endl;
}

void print(const string& str, maxint_t res)
{
  if (is_print())
    cout << str << " = " << res << endl;
}

void print(const string& str, maxint_t res, double time)
{
  if (is_print())
  {
    cout << "\r" << string(50,' ') << "\r";
    cout << "Status: 100%" << endl;
    cout << str << " = " << res << endl;
    print_seconds(get_time() - time);
  }
}

/// Used by pi_lmo(x), pi_deleglise_rivat(x)
void print(maxint_t x, int64_t y, int64_t z, int64_t c, int threads)
{
  if (is_print())
  {
    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "z = " << z << endl;
    cout << "c = " << c << endl;
    cout << "alpha = " << fixed << setprecision(3) << get_alpha(x, y) << endl;
    print_threads(threads);
  }
}

/// Only enabled for partial formulas
void print_vars(maxint_t x, int64_t y, int threads)
{
  if (is_print_variables())
  {
    maxint_t z = x / y;
    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "z = " << z << endl;
    cout << "alpha = " << fixed << setprecision(3) << get_alpha(x, y) << endl;
    print_threads(threads);
    cout << endl;
  }
}

/// Only enabled for partial formulas
void print_vars(maxint_t x, int64_t y, int64_t c, int threads)
{
  if (is_print_variables())
  {
    int64_t z = (int64_t)(x / y);
    print(x, y, z, c, threads);
    cout << endl;
  }
}

/// Used by pi_gourdon(x)
void print_gourdon(maxint_t x, int64_t y, int64_t z, int64_t k, int threads)
{
  if (is_print())
  {
    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "z = " << z << endl;
    cout << "k = " << k << endl;
    cout << "x_star = " << get_x_star_gourdon(x, y) << endl;
    cout << "alpha_y = " << fixed << setprecision(3) << get_alpha_y(x, y) << endl;
    cout << "alpha_z = " << fixed << setprecision(3) << get_alpha_z(y, z) << endl;
    print_threads(threads);
  }
}

/// Only enabled for partial formulas
void print_gourdon_vars(maxint_t x, int64_t y, int threads)
{
  if (is_print_variables())
  {
    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "alpha_y = " << fixed << setprecision(3) << get_alpha_y(x, y) << endl;
    print_threads(threads);
    cout << endl;
  }
}

/// Only enabled for partial formulas
void print_gourdon_vars(maxint_t x, int64_t y, int64_t z, int64_t k, int threads)
{
  if (is_print_variables())
  {
    print_gourdon(x, y, z, k, threads);
    cout << endl;
  }
}

} // namespace
<commit_msg>Refactor<commit_after>///
/// @file  print.cpp
///
/// Copyright (C) 2020 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <print.hpp>
#include <primecount-internal.hpp>
#include <int128_t.hpp>
#include <stdint.h>

#include <iostream>
#include <iomanip>
#include <string>

using namespace std;

namespace {

bool print_ = false;
bool print_variables_ = false;

bool is_print_variables()
{
  return print_variables_;
}

void print_threads(int threads)
{
#ifdef ENABLE_MPI
  using primecount::mpi_num_procs;
  cout << "processes = " << mpi_num_procs() << endl;
  cout << "threads = " << mpi_num_procs() << " * " << threads << endl;
#else
  cout << "threads = " << threads << endl;
#endif
}

} // naespace

namespace primecount {

bool is_print()
{
  return print_;
}

/// The final combined result is always shown at
/// the end even if is_print = false. It is only
/// not shown for partial formulas.
///
bool is_print_combined_result()
{
#ifdef ENABLE_MPI
  return !is_print_variables() && is_mpi_main_proc();
#else
  return !is_print_variables();
#endif
}

void set_print(bool print)
{
#ifdef ENABLE_MPI
  print_ = print && is_mpi_main_proc();
#else
  print_ = print;
#endif
}

void set_print_variables(bool print_variables)
{
#ifdef ENABLE_MPI
  print_variables_ = print_variables && is_mpi_main_proc();
#else
  print_variables_ = print_variables;
#endif
}

void print_seconds(double seconds)
{
  cout << "Seconds: " << fixed << setprecision(3) << seconds << endl;
}

void print(const string& str)
{
  if (is_print())
    cout << str << endl;
}

void print(const string& str, maxint_t res)
{
  if (is_print())
    cout << str << " = " << res << endl;
}

void print(const string& str, maxint_t res, double time)
{
  if (is_print())
  {
    cout << "\r" << string(50,' ') << "\r";
    cout << "Status: 100%" << endl;
    cout << str << " = " << res << endl;
    print_seconds(get_time() - time);
  }
}

/// Used by pi_lmo(x), pi_deleglise_rivat(x)
void print(maxint_t x, int64_t y, int64_t z, int64_t c, int threads)
{
  if (is_print())
  {
    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "z = " << z << endl;
    cout << "c = " << c << endl;
    cout << "alpha = " << fixed << setprecision(3) << get_alpha(x, y) << endl;
    print_threads(threads);
  }
}

/// Only enabled for partial formulas
void print_vars(maxint_t x, int64_t y, int threads)
{
  if (is_print_variables())
  {
    maxint_t z = x / y;
    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "z = " << z << endl;
    cout << "alpha = " << fixed << setprecision(3) << get_alpha(x, y) << endl;
    print_threads(threads);
    cout << endl;
  }
}

/// Only enabled for partial formulas
void print_vars(maxint_t x, int64_t y, int64_t c, int threads)
{
  if (is_print_variables())
  {
    int64_t z = (int64_t)(x / y);
    print(x, y, z, c, threads);
    cout << endl;
  }
}

/// Used by pi_gourdon(x)
void print_gourdon(maxint_t x, int64_t y, int64_t z, int64_t k, int threads)
{
  if (is_print())
  {
    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "z = " << z << endl;
    cout << "k = " << k << endl;
    cout << "x_star = " << get_x_star_gourdon(x, y) << endl;
    cout << "alpha_y = " << fixed << setprecision(3) << get_alpha_y(x, y) << endl;
    cout << "alpha_z = " << fixed << setprecision(3) << get_alpha_z(y, z) << endl;
    print_threads(threads);
  }
}

/// Only enabled for partial formulas
void print_gourdon_vars(maxint_t x, int64_t y, int threads)
{
  if (is_print_variables())
  {
    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "alpha_y = " << fixed << setprecision(3) << get_alpha_y(x, y) << endl;
    print_threads(threads);
    cout << endl;
  }
}

/// Only enabled for partial formulas
void print_gourdon_vars(maxint_t x, int64_t y, int64_t z, int64_t k, int threads)
{
  if (is_print_variables())
  {
    print_gourdon(x, y, z, k, threads);
    cout << endl;
  }
}

} // namespace
<|endoftext|>