<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: FTable.cxx,v $
 *
 *  $Revision: 1.22 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 01:26:43 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

#include <stdio.h>

#ifndef _CONNECTIVITY_FILE_TABLE_HXX_
#include "file/FTable.hxx"
#endif
#ifndef _CONNECTIVITY_FILE_COLUMNS_HXX_
#include "file/FColumns.hxx"
#endif
#ifndef _COM_SUN_STAR_SDBC_XROW_HPP_
#include <com/sun/star/sdbc/XRow.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_XRESULTSET_HPP_
#include <com/sun/star/sdbc/XResultSet.hpp>
#endif
#ifndef _CPPUHELPER_TYPEPROVIDER_HXX_
#include <cppuhelper/typeprovider.hxx>
#endif
#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
#include <com/sun/star/lang/DisposedException.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_COLUMNVALUE_HPP_
#include <com/sun/star/sdbc/ColumnValue.hpp>
#endif
#ifndef _UNTOOLS_UCBSTREAMHELPER_HXX
#include <unotools/ucbstreamhelper.hxx>
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

using namespace connectivity;
using namespace connectivity::file;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::container;

DBG_NAME( file_OFileTable )
OFileTable::OFileTable(sdbcx::OCollection* _pTables,OConnection* _pConnection)
: OTable_TYPEDEF(_pTables,_pConnection->getMetaData()->storesMixedCaseQuotedIdentifiers())
                ,m_pConnection(_pConnection)
                ,m_pFileStream(NULL)
                ,m_nFilePos(0)
                ,m_pBuffer(NULL)
                ,m_nBufferSize(0)
                ,m_bWriteable(sal_False)
{
    DBG_CTOR( file_OFileTable, NULL );
    construct();
    TStringVector aVector;
    //  m_pColumns  = new OColumns(this,m_aMutex,aVector);
    m_aColumns = new OSQLColumns();
}
// -------------------------------------------------------------------------
OFileTable::OFileTable( sdbcx::OCollection* _pTables,OConnection* _pConnection,
                    const ::rtl::OUString& _Name,
                    const ::rtl::OUString& _Type,
                    const ::rtl::OUString& _Description ,
                    const ::rtl::OUString& _SchemaName,
                    const ::rtl::OUString& _CatalogName
                ) : OTable_TYPEDEF(_pTables,_pConnection->getMetaData()->storesMixedCaseQuotedIdentifiers(),
                                  _Name,
                                  _Type,
                                  _Description,
                                  _SchemaName,
                                  _CatalogName)
                ,m_pConnection(_pConnection)
                ,m_pFileStream(NULL)
                ,m_nFilePos(0)
                ,m_pBuffer(NULL)
                ,m_nBufferSize(0)
                ,m_bWriteable(sal_False)
{
    DBG_CTOR( file_OFileTable, NULL );
    m_aColumns = new OSQLColumns();
    construct();
    //  refreshColumns();
}
// -------------------------------------------------------------------------
OFileTable::~OFileTable( )
{
    DBG_DTOR( file_OFileTable, NULL );
}
// -------------------------------------------------------------------------
void OFileTable::refreshColumns()
{
    TStringVector aVector;
        Reference< XResultSet > xResult = m_pConnection->getMetaData()->getColumns(Any(),
                                                    m_SchemaName,m_Name,::rtl::OUString::createFromAscii("%"));

    if(xResult.is())
    {
        Reference< XRow > xRow(xResult,UNO_QUERY);
        while(xResult->next())
            aVector.push_back(xRow->getString(4));
    }

    if(m_pColumns)
        m_pColumns->reFill(aVector);
    else
        m_pColumns  = new OColumns(this,m_aMutex,aVector);
}
// -------------------------------------------------------------------------
void OFileTable::refreshKeys()
{
}
// -------------------------------------------------------------------------
void OFileTable::refreshIndexes()
{
}
// -------------------------------------------------------------------------
Any SAL_CALL OFileTable::queryInterface( const Type & rType ) throw(RuntimeException)
{
    if( rType == ::getCppuType((const Reference<XKeysSupplier>*)0) ||
        rType == ::getCppuType((const Reference<XRename>*)0) ||
        rType == ::getCppuType((const Reference<XAlterTable>*)0) ||
        rType == ::getCppuType((const Reference<XIndexesSupplier>*)0) ||
        rType == ::getCppuType((const Reference<XDataDescriptorFactory>*)0))
        return Any();

    return OTable_TYPEDEF::queryInterface(rType);
}
// -------------------------------------------------------------------------
void SAL_CALL OFileTable::disposing(void)
{
    OTable::disposing();

    ::osl::MutexGuard aGuard(m_aMutex);

    FileClose();
    m_xMetaData = NULL;
}
//--------------------------------------------------------------------------
Sequence< sal_Int8 > OFileTable::getUnoTunnelImplementationId()
{
    static ::cppu::OImplementationId * pId = 0;
    if (! pId)
    {
        ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
        if (! pId)
        {
            static ::cppu::OImplementationId aId;
            pId = &aId;
        }
    }
    return pId->getImplementationId();
}

// com::sun::star::lang::XUnoTunnel
//------------------------------------------------------------------
sal_Int64 OFileTable::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException)
{
    return (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(),  rId.getConstArray(), 16 ) )
                ? reinterpret_cast< sal_Int64 >( this )
                : OTable_TYPEDEF::getSomething(rId);
}
// -----------------------------------------------------------------------------
void OFileTable::FileClose()
{
    ::osl::MutexGuard aGuard(m_aMutex);

    if (m_pFileStream && m_pFileStream->IsWritable())
        m_pFileStream->Flush();

    delete m_pFileStream;
    m_pFileStream = NULL;

    if (m_pBuffer)
    {
        delete[] m_pBuffer;
        m_pBuffer = NULL;
    }
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
void SAL_CALL OFileTable::acquire() throw()
{
    OTable_TYPEDEF::acquire();
}
// -----------------------------------------------------------------------------
void SAL_CALL OFileTable::release() throw()
{
    OTable_TYPEDEF::release();
}
// -----------------------------------------------------------------------------
BOOL OFileTable::InsertRow(OValueRefVector& /*rRow*/, BOOL /*bFlush*/,const ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexAccess>& /*_xCols*/)
{
    return sal_False;
}
// -----------------------------------------------------------------------------
BOOL OFileTable::DeleteRow(const OSQLColumns& /*_rCols*/)
{
    return sal_False;
}
// -----------------------------------------------------------------------------
BOOL OFileTable::UpdateRow(OValueRefVector& /*rRow*/, OValueRefRow& /*pOrgRow*/,const ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexAccess>& /*_xCols*/)
{
    return sal_False;
}
// -----------------------------------------------------------------------------
void OFileTable::addColumn(const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet>& /*descriptor*/)
{
    OSL_ENSURE( false, "OFileTable::addColumn: not implemented!" );
}
// -----------------------------------------------------------------------------
void OFileTable::dropColumn(sal_Int32 /*_nPos*/)
{
    OSL_ENSURE( false, "OFileTable::addColumn: not implemented!" );
}

// -----------------------------------------------------------------------------
SvStream* OFileTable::createStream_simpleError( const String& _rFileName, StreamMode _eOpenMode)
{
    utl::UcbLockBytesHandler* p_null_dummy=NULL;
    SvStream* pReturn = ::utl::UcbStreamHelper::CreateStream( _rFileName, _eOpenMode, p_null_dummy);
    if (pReturn && (ERRCODE_NONE != pReturn->GetErrorCode()))
    {
        delete pReturn;
        pReturn = NULL;
    }
    return pReturn;
}

// -----------------------------------------------------------------------------
void OFileTable::refreshHeader()
{
}
// -----------------------------------------------------------------------------

<commit_msg>INTEGRATION: CWS pchfix02 (1.22.60); FILE MERGED 2006/09/01 17:22:12 kaib 1.22.60.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: FTable.cxx,v $
 *
 *  $Revision: 1.23 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 02:34:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_connectivity.hxx"

#include <stdio.h>

#ifndef _CONNECTIVITY_FILE_TABLE_HXX_
#include "file/FTable.hxx"
#endif
#ifndef _CONNECTIVITY_FILE_COLUMNS_HXX_
#include "file/FColumns.hxx"
#endif
#ifndef _COM_SUN_STAR_SDBC_XROW_HPP_
#include <com/sun/star/sdbc/XRow.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_XRESULTSET_HPP_
#include <com/sun/star/sdbc/XResultSet.hpp>
#endif
#ifndef _CPPUHELPER_TYPEPROVIDER_HXX_
#include <cppuhelper/typeprovider.hxx>
#endif
#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
#include <com/sun/star/lang/DisposedException.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_COLUMNVALUE_HPP_
#include <com/sun/star/sdbc/ColumnValue.hpp>
#endif
#ifndef _UNTOOLS_UCBSTREAMHELPER_HXX
#include <unotools/ucbstreamhelper.hxx>
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

using namespace connectivity;
using namespace connectivity::file;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::container;

DBG_NAME( file_OFileTable )
OFileTable::OFileTable(sdbcx::OCollection* _pTables,OConnection* _pConnection)
: OTable_TYPEDEF(_pTables,_pConnection->getMetaData()->storesMixedCaseQuotedIdentifiers())
                ,m_pConnection(_pConnection)
                ,m_pFileStream(NULL)
                ,m_nFilePos(0)
                ,m_pBuffer(NULL)
                ,m_nBufferSize(0)
                ,m_bWriteable(sal_False)
{
    DBG_CTOR( file_OFileTable, NULL );
    construct();
    TStringVector aVector;
    //  m_pColumns  = new OColumns(this,m_aMutex,aVector);
    m_aColumns = new OSQLColumns();
}
// -------------------------------------------------------------------------
OFileTable::OFileTable( sdbcx::OCollection* _pTables,OConnection* _pConnection,
                    const ::rtl::OUString& _Name,
                    const ::rtl::OUString& _Type,
                    const ::rtl::OUString& _Description ,
                    const ::rtl::OUString& _SchemaName,
                    const ::rtl::OUString& _CatalogName
                ) : OTable_TYPEDEF(_pTables,_pConnection->getMetaData()->storesMixedCaseQuotedIdentifiers(),
                                  _Name,
                                  _Type,
                                  _Description,
                                  _SchemaName,
                                  _CatalogName)
                ,m_pConnection(_pConnection)
                ,m_pFileStream(NULL)
                ,m_nFilePos(0)
                ,m_pBuffer(NULL)
                ,m_nBufferSize(0)
                ,m_bWriteable(sal_False)
{
    DBG_CTOR( file_OFileTable, NULL );
    m_aColumns = new OSQLColumns();
    construct();
    //  refreshColumns();
}
// -------------------------------------------------------------------------
OFileTable::~OFileTable( )
{
    DBG_DTOR( file_OFileTable, NULL );
}
// -------------------------------------------------------------------------
void OFileTable::refreshColumns()
{
    TStringVector aVector;
        Reference< XResultSet > xResult = m_pConnection->getMetaData()->getColumns(Any(),
                                                    m_SchemaName,m_Name,::rtl::OUString::createFromAscii("%"));

    if(xResult.is())
    {
        Reference< XRow > xRow(xResult,UNO_QUERY);
        while(xResult->next())
            aVector.push_back(xRow->getString(4));
    }

    if(m_pColumns)
        m_pColumns->reFill(aVector);
    else
        m_pColumns  = new OColumns(this,m_aMutex,aVector);
}
// -------------------------------------------------------------------------
void OFileTable::refreshKeys()
{
}
// -------------------------------------------------------------------------
void OFileTable::refreshIndexes()
{
}
// -------------------------------------------------------------------------
Any SAL_CALL OFileTable::queryInterface( const Type & rType ) throw(RuntimeException)
{
    if( rType == ::getCppuType((const Reference<XKeysSupplier>*)0) ||
        rType == ::getCppuType((const Reference<XRename>*)0) ||
        rType == ::getCppuType((const Reference<XAlterTable>*)0) ||
        rType == ::getCppuType((const Reference<XIndexesSupplier>*)0) ||
        rType == ::getCppuType((const Reference<XDataDescriptorFactory>*)0))
        return Any();

    return OTable_TYPEDEF::queryInterface(rType);
}
// -------------------------------------------------------------------------
void SAL_CALL OFileTable::disposing(void)
{
    OTable::disposing();

    ::osl::MutexGuard aGuard(m_aMutex);

    FileClose();
    m_xMetaData = NULL;
}
//--------------------------------------------------------------------------
Sequence< sal_Int8 > OFileTable::getUnoTunnelImplementationId()
{
    static ::cppu::OImplementationId * pId = 0;
    if (! pId)
    {
        ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
        if (! pId)
        {
            static ::cppu::OImplementationId aId;
            pId = &aId;
        }
    }
    return pId->getImplementationId();
}

// com::sun::star::lang::XUnoTunnel
//------------------------------------------------------------------
sal_Int64 OFileTable::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException)
{
    return (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(),  rId.getConstArray(), 16 ) )
                ? reinterpret_cast< sal_Int64 >( this )
                : OTable_TYPEDEF::getSomething(rId);
}
// -----------------------------------------------------------------------------
void OFileTable::FileClose()
{
    ::osl::MutexGuard aGuard(m_aMutex);

    if (m_pFileStream && m_pFileStream->IsWritable())
        m_pFileStream->Flush();

    delete m_pFileStream;
    m_pFileStream = NULL;

    if (m_pBuffer)
    {
        delete[] m_pBuffer;
        m_pBuffer = NULL;
    }
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
void SAL_CALL OFileTable::acquire() throw()
{
    OTable_TYPEDEF::acquire();
}
// -----------------------------------------------------------------------------
void SAL_CALL OFileTable::release() throw()
{
    OTable_TYPEDEF::release();
}
// -----------------------------------------------------------------------------
BOOL OFileTable::InsertRow(OValueRefVector& /*rRow*/, BOOL /*bFlush*/,const ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexAccess>& /*_xCols*/)
{
    return sal_False;
}
// -----------------------------------------------------------------------------
BOOL OFileTable::DeleteRow(const OSQLColumns& /*_rCols*/)
{
    return sal_False;
}
// -----------------------------------------------------------------------------
BOOL OFileTable::UpdateRow(OValueRefVector& /*rRow*/, OValueRefRow& /*pOrgRow*/,const ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexAccess>& /*_xCols*/)
{
    return sal_False;
}
// -----------------------------------------------------------------------------
void OFileTable::addColumn(const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet>& /*descriptor*/)
{
    OSL_ENSURE( false, "OFileTable::addColumn: not implemented!" );
}
// -----------------------------------------------------------------------------
void OFileTable::dropColumn(sal_Int32 /*_nPos*/)
{
    OSL_ENSURE( false, "OFileTable::addColumn: not implemented!" );
}

// -----------------------------------------------------------------------------
SvStream* OFileTable::createStream_simpleError( const String& _rFileName, StreamMode _eOpenMode)
{
    utl::UcbLockBytesHandler* p_null_dummy=NULL;
    SvStream* pReturn = ::utl::UcbStreamHelper::CreateStream( _rFileName, _eOpenMode, p_null_dummy);
    if (pReturn && (ERRCODE_NONE != pReturn->GetErrorCode()))
    {
        delete pReturn;
        pReturn = NULL;
    }
    return pReturn;
}

// -----------------------------------------------------------------------------
void OFileTable::refreshHeader()
{
}
// -----------------------------------------------------------------------------

<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkShortArray.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkShortArray.h"

// Description:
// Instantiate object.
vtkShortArray::vtkShortArray(int numComp)
{
  this->NumberOfComponents = (numComp < 1 ? 1 : numComp);
  this->Array = NULL;
  this->TupleSize = 3;
  this->Tuple = new float[this->TupleSize]; //used for conversion
  this->SaveUserArray = 0;
}

vtkShortArray::~vtkShortArray()
{
  if ((this->Array) && (!this->SaveUserArray)) delete [] this->Array;
  delete [] this->Tuple;
}

// Description:
// This method lets the user specify data to be held by the array.  The
// array argument is a pointer to the data.  size is the size of
// the array supplied by the user.  Set save to 1 to keep the class
// from deleting the array when it cleans up or reallocates memory.
// The class uses the actual array provided; it does not copy the data
// from the suppled array.
void vtkShortArray::SetArray(short* array, int size, int save)
{
  if ((this->Array) && (!this->SaveUserArray))
    {
      vtkDebugMacro (<< "Deleting the array...");
      delete [] this->Array;
    }
  else
    {
      vtkDebugMacro (<<"Warning, array not deleted, but will point to new array.");
    }

  vtkDebugMacro(<<"Setting array to: " << array);

  this->Array = array;
  this->Size = size;
  this->MaxId = size-1;
  this->SaveUserArray = save;
}

// Description:
// Allocate memory for this array. Delete old storage only if necessary.
int vtkShortArray::Allocate(const int sz, const int ext)
{
  if ( sz > this->Size )
    {
    if ((this->Array) && (!this->SaveUserArray))
      {
      delete [] this->Array;
      }
    this->Size = ( sz > 0 ? sz : 1);
    if ( (this->Array = new short[this->Size]) == NULL ) return 0;
    this->SaveUserArray = 0;
    }

  this->Extend = ( ext > 0 ? ext : 1);
  this->MaxId = -1;

  return 1;
}

// Description:
// Release storage and reset array to initial state.
void vtkShortArray::Initialize()
{
  if (( this->Array != NULL ) && (!this->SaveUserArray))
    {
    delete [] this->Array;
    }
  this->Array = NULL;
  this->Size = 0;
  this->MaxId = -1;
  this->SaveUserArray = 0;
}

// Description:
// Deep copy of another short array.
void vtkShortArray::DeepCopy(vtkDataArray& sa)
{
  if ( sa.GetDataType() != VTK_SHORT )
    {
      vtkDataArray::DeepCopy(sa);
      return;
    }

  if ( this != &sa )
    {
    if ((this->Array) && (!this->SaveUserArray))
      {
      delete [] this->Array;
      }

    this->NumberOfComponents = sa.GetNumberOfComponents();
    this->MaxId = sa.GetMaxId();
    this->Size = sa.GetSize();
    this->Extend = sa.GetExtend();
    this->SaveUserArray = 0;

    this->Array = new short[this->Size];
    memcpy(this->Array, (long *)sa.GetVoidPointer(0), this->Size*sizeof(long));
    }
}

void vtkShortArray::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkDataArray::PrintSelf(os,indent);

  os << indent << "Array: " << this->Array << "\n";
}

//
// Private function does "reallocate"
//
short *vtkShortArray::Resize(const int sz)
{
  short *newArray;
  int newSize;

  if ( sz > this->Size )
    {
    newSize = this->Size + this->Extend*(((sz-this->Size)/this->Extend)+1);
    }
  else if (sz == this->Size)
    {
    return this->Array;
    }
  else
    {
    newSize = sz;
    }

  if ( (newArray = new short[newSize]) == NULL )
    {
    vtkErrorMacro(<< "Cannot allocate memory\n");
    return 0;
    }

  if (this->Array)
    {
    memcpy(newArray, this->Array,
         (sz < this->Size ? sz : this->Size) * sizeof(short));
    if (!this->SaveUserArray)
      {
      delete [] this->Array;
      }
    }

  this->Size = newSize;
  this->Array = newArray;
  this->SaveUserArray = 0;

  return this->Array;
}

// Description:
// Set the number of n-tuples in the array.
void vtkShortArray::SetNumberOfTuples(const int number)
{
  this->SetNumberOfValues(number*this->NumberOfComponents);
}

// Description:
// Get a pointer to a tuple at the ith location. This is a dangerous method
// (it is not thread safe since a pointer is returned).
float *vtkShortArray::GetTuple(const int i)
{
  if ( this->TupleSize < this->NumberOfComponents )
    {
    this->TupleSize = this->NumberOfComponents;
    delete [] this->Tuple;
    this->Tuple = new float[this->TupleSize];
    }

  short *t = this->Array + this->NumberOfComponents*i;
  for (int j=0; j<this->NumberOfComponents; j++) this->Tuple[j] = (float)t[j];
  return this->Tuple;
}

// Description:
// Copy the tuple value into a user-provided array.
void vtkShortArray::GetTuple(const int i, float * tuple)
{
  short *t = this->Array + this->NumberOfComponents*i;
  for (int j=0; j<this->NumberOfComponents; j++) tuple[j] = (float)t[j];
}

// Description:
// Set the tuple value at the ith location in the array.
void vtkShortArray::SetTuple(const int i, const float * tuple)
{
  int loc = i * this->NumberOfComponents;
  for (int j=0; j<this->NumberOfComponents; j++)
    this->Array[loc+j] = (short)tuple[j];
}

// Description:
// Insert (memory allocation performed) the tuple into the ith location
// in the array.
void vtkShortArray::InsertTuple(const int i, const float * tuple)
{
  short *t = this->WritePointer(i*this->NumberOfComponents,this->NumberOfComponents);

  for (int j=0; j<this->NumberOfComponents; j++) *t++ = (short)*tuple++;
}

// Description:
// Insert (memory allocation performed) the tuple onto the end of the array.
int vtkShortArray::InsertNextTuple(const float * tuple)
{
  int i = this->MaxId + 1;
  short *t = this->WritePointer(i,this->NumberOfComponents);

  for (i=0; i<this->NumberOfComponents; i++) *t++ = (short)*tuple++;

  return this->MaxId / this->NumberOfComponents;
}

// Description:
// Return the data component at the ith tuple and jth component location.
// Note that i<NumberOfTuples and j<NumberOfComponents.
float vtkShortArray::GetComponent(const int i, const int j)
{
  return (float) this->GetValue(i*this->NumberOfComponents + j);
}

// Description:
// Set the data component at the ith tuple and jth component location.
// Note that i<NumberOfTuples and j<NumberOfComponents. Make sure enough
// memory has been allocated (use SetNumberOfTuples() and
// SetNumberOfComponents()).
void vtkShortArray::SetComponent(const int i, const int j, const float c)
{
  this->SetValue(i*this->NumberOfComponents + j, (short)c);
}

// Description:
// Insert the data component at ith tuple and jth component location.
// Note that memory allocation is performed as necessary to hold the data.
void vtkShortArray::InsertComponent(const int i, const int j, const float c)
{
  this->InsertValue(i*this->NumberOfComponents + j, (short)c);
}

<commit_msg>ERR: cast to long instead short<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkShortArray.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkShortArray.h"

// Description:
// Instantiate object.
vtkShortArray::vtkShortArray(int numComp)
{
  this->NumberOfComponents = (numComp < 1 ? 1 : numComp);
  this->Array = NULL;
  this->TupleSize = 3;
  this->Tuple = new float[this->TupleSize]; //used for conversion
  this->SaveUserArray = 0;
}

vtkShortArray::~vtkShortArray()
{
  if ((this->Array) && (!this->SaveUserArray)) delete [] this->Array;
  delete [] this->Tuple;
}

// Description:
// This method lets the user specify data to be held by the array.  The
// array argument is a pointer to the data.  size is the size of
// the array supplied by the user.  Set save to 1 to keep the class
// from deleting the array when it cleans up or reallocates memory.
// The class uses the actual array provided; it does not copy the data
// from the suppled array.
void vtkShortArray::SetArray(short* array, int size, int save)
{
  if ((this->Array) && (!this->SaveUserArray))
    {
      vtkDebugMacro (<< "Deleting the array...");
      delete [] this->Array;
    }
  else
    {
      vtkDebugMacro (<<"Warning, array not deleted, but will point to new array.");
    }

  vtkDebugMacro(<<"Setting array to: " << array);

  this->Array = array;
  this->Size = size;
  this->MaxId = size-1;
  this->SaveUserArray = save;
}

// Description:
// Allocate memory for this array. Delete old storage only if necessary.
int vtkShortArray::Allocate(const int sz, const int ext)
{
  if ( sz > this->Size )
    {
    if ((this->Array) && (!this->SaveUserArray))
      {
      delete [] this->Array;
      }
    this->Size = ( sz > 0 ? sz : 1);
    if ( (this->Array = new short[this->Size]) == NULL ) return 0;
    this->SaveUserArray = 0;
    }

  this->Extend = ( ext > 0 ? ext : 1);
  this->MaxId = -1;

  return 1;
}

// Description:
// Release storage and reset array to initial state.
void vtkShortArray::Initialize()
{
  if (( this->Array != NULL ) && (!this->SaveUserArray))
    {
    delete [] this->Array;
    }
  this->Array = NULL;
  this->Size = 0;
  this->MaxId = -1;
  this->SaveUserArray = 0;
}

// Description:
// Deep copy of another short array.
void vtkShortArray::DeepCopy(vtkDataArray& sa)
{
  if ( sa.GetDataType() != VTK_SHORT )
    {
      vtkDataArray::DeepCopy(sa);
      return;
    }

  if ( this != &sa )
    {
    if ((this->Array) && (!this->SaveUserArray))
      {
      delete [] this->Array;
      }

    this->NumberOfComponents = sa.GetNumberOfComponents();
    this->MaxId = sa.GetMaxId();
    this->Size = sa.GetSize();
    this->Extend = sa.GetExtend();
    this->SaveUserArray = 0;

    this->Array = new short[this->Size];
    memcpy(this->Array, (short *)sa.GetVoidPointer(0), this->Size*sizeof(short));
    }
}

void vtkShortArray::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkDataArray::PrintSelf(os,indent);

  os << indent << "Array: " << this->Array << "\n";
}

//
// Private function does "reallocate"
//
short *vtkShortArray::Resize(const int sz)
{
  short *newArray;
  int newSize;

  if ( sz > this->Size )
    {
    newSize = this->Size + this->Extend*(((sz-this->Size)/this->Extend)+1);
    }
  else if (sz == this->Size)
    {
    return this->Array;
    }
  else
    {
    newSize = sz;
    }

  if ( (newArray = new short[newSize]) == NULL )
    {
    vtkErrorMacro(<< "Cannot allocate memory\n");
    return 0;
    }

  if (this->Array)
    {
    memcpy(newArray, this->Array,
         (sz < this->Size ? sz : this->Size) * sizeof(short));
    if (!this->SaveUserArray)
      {
      delete [] this->Array;
      }
    }

  this->Size = newSize;
  this->Array = newArray;
  this->SaveUserArray = 0;

  return this->Array;
}

// Description:
// Set the number of n-tuples in the array.
void vtkShortArray::SetNumberOfTuples(const int number)
{
  this->SetNumberOfValues(number*this->NumberOfComponents);
}

// Description:
// Get a pointer to a tuple at the ith location. This is a dangerous method
// (it is not thread safe since a pointer is returned).
float *vtkShortArray::GetTuple(const int i)
{
  if ( this->TupleSize < this->NumberOfComponents )
    {
    this->TupleSize = this->NumberOfComponents;
    delete [] this->Tuple;
    this->Tuple = new float[this->TupleSize];
    }

  short *t = this->Array + this->NumberOfComponents*i;
  for (int j=0; j<this->NumberOfComponents; j++) this->Tuple[j] = (float)t[j];
  return this->Tuple;
}

// Description:
// Copy the tuple value into a user-provided array.
void vtkShortArray::GetTuple(const int i, float * tuple)
{
  short *t = this->Array + this->NumberOfComponents*i;
  for (int j=0; j<this->NumberOfComponents; j++) tuple[j] = (float)t[j];
}

// Description:
// Set the tuple value at the ith location in the array.
void vtkShortArray::SetTuple(const int i, const float * tuple)
{
  int loc = i * this->NumberOfComponents;
  for (int j=0; j<this->NumberOfComponents; j++)
    this->Array[loc+j] = (short)tuple[j];
}

// Description:
// Insert (memory allocation performed) the tuple into the ith location
// in the array.
void vtkShortArray::InsertTuple(const int i, const float * tuple)
{
  short *t = this->WritePointer(i*this->NumberOfComponents,this->NumberOfComponents);

  for (int j=0; j<this->NumberOfComponents; j++) *t++ = (short)*tuple++;
}

// Description:
// Insert (memory allocation performed) the tuple onto the end of the array.
int vtkShortArray::InsertNextTuple(const float * tuple)
{
  int i = this->MaxId + 1;
  short *t = this->WritePointer(i,this->NumberOfComponents);

  for (i=0; i<this->NumberOfComponents; i++) *t++ = (short)*tuple++;

  return this->MaxId / this->NumberOfComponents;
}

// Description:
// Return the data component at the ith tuple and jth component location.
// Note that i<NumberOfTuples and j<NumberOfComponents.
float vtkShortArray::GetComponent(const int i, const int j)
{
  return (float) this->GetValue(i*this->NumberOfComponents + j);
}

// Description:
// Set the data component at the ith tuple and jth component location.
// Note that i<NumberOfTuples and j<NumberOfComponents. Make sure enough
// memory has been allocated (use SetNumberOfTuples() and
// SetNumberOfComponents()).
void vtkShortArray::SetComponent(const int i, const int j, const float c)
{
  this->SetValue(i*this->NumberOfComponents + j, (short)c);
}

// Description:
// Insert the data component at ith tuple and jth component location.
// Note that memory allocation is performed as necessary to hold the data.
void vtkShortArray::InsertComponent(const int i, const int j, const float c)
{
  this->InsertValue(i*this->NumberOfComponents + j, (short)c);
}

<|endoftext|>


<commit_before>/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>

#include "AstPrintDocs.h"
#include "AstToText.h"
#include "driver.h"
#include "expr.h"
#include "files.h"
#include "mysystem.h"
#include "passes.h"
#include "stmt.h"
#include "symbol.h"
#include "stringutil.h"

#include "docs.h"

static int compareNames(const void* v1, const void* v2) {
  Symbol* s1 = *(Symbol* const *)v1;
  Symbol* s2 = *(Symbol* const *)v2;
  return strcmp(s1->name, s2->name);
}

static int compareClasses(const void *v1, const void* v2) {
  Type *t1 = *(Type* const *)v1;
  Type *t2 = *(Type* const *)v2;
  return strcmp(t1->symbol->name, t2->symbol->name);
}

void docs(void) {

  if (fDocs) {
    // Open the directory to store the docs

    // This is the final location for the output format (e.g. the html files.).
    std::string docsOutputDir;
    if (strlen(fDocsFolder) > 0) {
      docsOutputDir = fDocsFolder;
    } else {
      docsOutputDir = astr(getCwd(), "/docs");
    }

    // Root of the sphinx project and generated rst files. If
    // --docs-save-sphinx is not specified, it will be a temp dir.
    std::string docsTempDir = "";
    std::string docsSphinxDir;
    if (strlen(fDocsSphinxDir) > 0) {
      docsSphinxDir = fDocsSphinxDir;
    } else {
      docsTempDir = makeTempDir("chpldoc-");
      docsSphinxDir = docsTempDir;
    }

    // The location of intermediate rst files.
    std::string docsRstDir;
    if (fDocsTextOnly) {
      // For text-only mode, the output and working location is the same.
      docsRstDir = docsOutputDir;
    } else {
      // For rst mode, the working location is somewhere inside the temp dir.
      docsRstDir = generateSphinxProject(docsSphinxDir);
    }

    // TODO: Check for errors here... (thomasvandoren, 2015-02-25)
    const int dirPerms = S_IRWXU | S_IRWXG | S_IRWXO;
    mkdir(docsRstDir.c_str(), dirPerms);
    mkdir(docsOutputDir.c_str(), dirPerms);

    forv_Vec(ModuleSymbol, mod, gModuleSymbols) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!mod->hasFlag(FLAG_NO_DOC) && !devOnlyModule(mod)) {
        if (isNotSubmodule(mod)) {
          std::ofstream *file = openFileFromMod(mod, docsRstDir);

          AstPrintDocs *docsVisitor = new AstPrintDocs(file);
          mod->accept(docsVisitor);
          delete docsVisitor;

          // Comment the above three lines and uncomment the following line to
          // get the old category based output (or alphabetical). Note that
          // this will be restored (hopefully soon)... (thomasvandoren, 2015-02-22)
          //
          // printModule(file, mod, 0);

          file->close();
        }
      }
    }

    if (!fDocsTextOnly) {
      generateSphinxOutput(docsSphinxDir, docsOutputDir);
    }

    if (docsTempDir.length() > 0) {
      deleteDir(docsTempDir.c_str());
    }
  }
}

bool isNotSubmodule(ModuleSymbol *mod) {
  return (mod->defPoint == NULL ||
          mod->defPoint->parentSymbol == NULL ||
          mod->defPoint->parentSymbol->name == NULL ||
          strcmp("chpl__Program", mod->defPoint->parentSymbol->name) == 0 ||
          strcmp("_root", mod->defPoint->parentSymbol->name) == 0);
}

void printFields(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  for (int i = 1; i <= cl->fields.length; i++) {
    if (VarSymbol *var = toVarSymbol(((DefExpr *)cl->fields.get(i))->sym)) {
      var->printDocs(file, tabs);
    }
  }
}

void printClass(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  if (!cl->symbol->hasFlag(FLAG_NO_DOC) && ! cl->isUnion()) {
    cl->printDocs(file, tabs);

    printFields(file, cl, tabs + 1);

    // In rst mode, add an additional line break after the attributes and
    // before the next directive.
    if (!fDocsTextOnly) {
      *file << std::endl;
    }

    // If alphabetical option passed, alphabetizes the output
    if (fDocsAlphabetize)
      qsort(cl->methods.v, cl->methods.n, sizeof(cl->methods.v[0]),
        compareNames);

    forv_Vec(FnSymbol, fn, cl->methods){
      // We only want to print methods defined within the class under the
      // class header
      if (fn->isPrimaryMethod())
        fn->printDocs(file, tabs + 1);
    }
  }
}

// Returns true if the provided fn is a module initializer, class constructor,
// type constructor, or module copy of a class method.  These functions are
// only printed in developer mode.  Is not applicable to printing class
// functions.
bool devOnlyFunction(FnSymbol *fn) {
  return (fn->hasFlag(FLAG_MODULE_INIT) || fn->hasFlag(FLAG_TYPE_CONSTRUCTOR)
          || fn->hasFlag(FLAG_CONSTRUCTOR) || fn->isPrimaryMethod());
}

// Returns true if the provide module is one of the internal or standard
// modules. It is our opinion that these should only automatically be printed
// out if the user is in developer mode.
bool devOnlyModule(ModuleSymbol *mod) {
  return mod->modTag == MOD_INTERNAL || mod->modTag == MOD_STANDARD;
}

void printModule(std::ofstream *file, ModuleSymbol *mod, unsigned int tabs) {
  if (!mod->hasFlag(FLAG_NO_DOC)) {
    mod->printDocs(file, tabs);

    Vec<VarSymbol*> configs = mod->getTopLevelConfigVars();
    if (fDocsAlphabetize)
      qsort(configs.v, configs.n, sizeof(configs.v[0]), compareNames);
    forv_Vec(VarSymbol, var, configs) {
      var->printDocs(file, tabs + 1);
    }

    Vec<VarSymbol*> variables = mod->getTopLevelVariables();
    if (fDocsAlphabetize)
      qsort(variables.v, variables.n, sizeof(variables.v[0]), compareNames);
    forv_Vec(VarSymbol, var, variables) {
      var->printDocs(file, tabs + 1);
    }
    Vec<FnSymbol*> fns = mod->getTopLevelFunctions(fDocsIncludeExterns);
    // If alphabetical option passed, fDocsAlphabetizes the output
    if (fDocsAlphabetize)
      qsort(fns.v, fns.n, sizeof(fns.v[0]), compareNames);

    forv_Vec(FnSymbol, fn, fns) {
      // TODO: Add flag to compiler to turn on doc dev only output

      // We want methods on classes that are defined at the module level to be
      // printed at the module level
      if (!devOnlyFunction(fn) || fn->isSecondaryMethod()) {
        fn->printDocs(file, tabs + 1);
      }
    }

    Vec<AggregateType*> classes = mod->getTopLevelClasses();
    if (fDocsAlphabetize)
      qsort(classes.v, classes.n, sizeof(classes.v[0]), compareClasses);

    forv_Vec(AggregateType, cl, classes) {
      printClass(file, cl, tabs + 1);
    }

    Vec<ModuleSymbol*> mods = mod->getTopLevelModules();
    if (fDocsAlphabetize)
      qsort(mods.v, mods.n, sizeof(mods.v[0]), compareNames);

    forv_Vec(ModuleSymbol, subMod, mods) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!devOnlyModule(subMod)) {
        subMod->addPrefixToName(mod->docsName() + ".");
        printModule(file, subMod, tabs + 1);
      }
    }
  }
}

void createDocsFileFolders(std::string filename) {
  size_t dirCutoff = filename.find("/");
  size_t total = 0;
  while (dirCutoff != std::string::npos) {
    // Creates each subdirectory within the new documentation directory
    dirCutoff += total;
    std::string shorter = filename.substr(dirCutoff+1);
    std::string otherHalf = filename.substr(0, dirCutoff);
    mkdir(otherHalf.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);
    total = dirCutoff + 1;
    dirCutoff = shorter.find("/");
  }
}

/*
 * Create new sphinx project at given location and return path where .rst files
 * should be placed.
 */
std::string generateSphinxProject(std::string dirpath) {
  // Create the output dir under the docs output dir.
  const char * sphinxDir = dirpath.c_str();

  // Ensure output directory exists.
  const char * mkdirCmd = astr("mkdir -p ", sphinxDir);
  mysystem(mkdirCmd, "creating docs output dir");

  // Copy the sphinx template into the output dir.
  const char * sphinxTemplate = astr(CHPL_HOME, "/third-party/chpldoc-venv/chpldoc-sphinx-project/*");
  const char * cmd = astr("cp -r ", sphinxTemplate, " ", sphinxDir, "/");
  mysystem(cmd, "copying chpldoc sphinx template");

  const char * moddir = astr(sphinxDir, "/source/modules");
  return std::string(moddir);
}

/*
 * Invoke sphinx-build using sphinxDir to find conf.py and rst sources, and
 * outputDir for generated html files.
 */
void generateSphinxOutput(std::string sphinxDir, std::string outputDir) {
  // Set the PATH and VIRTUAL_ENV variables in the environment. The values are
  // based on the install path in the third-party/chpldoc-venv/ dir.
  const char * venvDir = astr(
    CHPL_HOME, "/third-party/chpldoc-venv/install/",
    CHPL_TARGET_PLATFORM, "/chpldoc-virtualenv");
  const char * venvBinDir = astr(venvDir, "/bin");
  const char * sphinxBuild = astr(venvBinDir, "/sphinx-build");
  const char * envVars = astr("export PATH=", venvBinDir, ":$PATH && ",
                              "export VIRTUAL_ENV=", venvDir);

  // Run:
  //   $envVars &&
  //     sphinx-build -b html
  //     -d $sphinxDir/build/doctrees -W
  //     $sphinxDir/source $outputDir
  const char * cmdPrefix = astr(envVars, " && ");
  const char * cmd = astr(
    cmdPrefix,
    sphinxBuild, " -b html -d ",
    sphinxDir.c_str(), "/build/doctrees -W ",
    sphinxDir.c_str(), "/source ", outputDir.c_str());
  mysystem(cmd, "building html output from chpldoc sphinx project");
  printf("HTML files are at: %s\n", outputDir.c_str());
}

std::string filenameFromMod(ModuleSymbol *mod, std::string docsWorkDir) {
  std::string filename = mod->filename;

  if (mod->modTag == MOD_INTERNAL) {
    filename = "internal-modules/";
  } else if (mod ->modTag == MOD_STANDARD) {
    filename = "standard-modules/";
  } else {
    size_t location = filename.rfind("/");
    if (location != std::string::npos) {
      filename = filename.substr(0, location + 1);
    } else {
      filename = "";
    }
  }
  filename = docsWorkDir + "/" + filename;
  createDocsFileFolders(filename);

  // Creates files for each top level module.
  if (fDocsTextOnly) {
    filename = filename + mod->name + ".txt";
  } else {
    filename = filename + mod->name + ".rst";
  }

  return filename;
}

std::ofstream* openFileFromMod(ModuleSymbol *mod, std::string docsWorkDir) {
  std::string filename = filenameFromMod(mod, docsWorkDir);
  return new std::ofstream(filename.c_str(), std::ios::out);
}
<commit_msg>Update docs() pass to set PYTHONPATH before calling sphinx-build.<commit_after>/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <fstream>
#include <glob.h>
#include <iostream>
#include <iterator>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>

#include "AstPrintDocs.h"
#include "AstToText.h"
#include "driver.h"
#include "expr.h"
#include "files.h"
#include "mysystem.h"
#include "passes.h"
#include "stmt.h"
#include "symbol.h"
#include "stringutil.h"

#include "docs.h"

static int compareNames(const void* v1, const void* v2) {
  Symbol* s1 = *(Symbol* const *)v1;
  Symbol* s2 = *(Symbol* const *)v2;
  return strcmp(s1->name, s2->name);
}

static int compareClasses(const void *v1, const void* v2) {
  Type *t1 = *(Type* const *)v1;
  Type *t2 = *(Type* const *)v2;
  return strcmp(t1->symbol->name, t2->symbol->name);
}

void docs(void) {

  if (fDocs) {
    // Open the directory to store the docs

    // This is the final location for the output format (e.g. the html files.).
    std::string docsOutputDir;
    if (strlen(fDocsFolder) > 0) {
      docsOutputDir = fDocsFolder;
    } else {
      docsOutputDir = astr(getCwd(), "/docs");
    }

    // Root of the sphinx project and generated rst files. If
    // --docs-save-sphinx is not specified, it will be a temp dir.
    std::string docsTempDir = "";
    std::string docsSphinxDir;
    if (strlen(fDocsSphinxDir) > 0) {
      docsSphinxDir = fDocsSphinxDir;
    } else {
      docsTempDir = makeTempDir("chpldoc-");
      docsSphinxDir = docsTempDir;
    }

    // The location of intermediate rst files.
    std::string docsRstDir;
    if (fDocsTextOnly) {
      // For text-only mode, the output and working location is the same.
      docsRstDir = docsOutputDir;
    } else {
      // For rst mode, the working location is somewhere inside the temp dir.
      docsRstDir = generateSphinxProject(docsSphinxDir);
    }

    // TODO: Check for errors here... (thomasvandoren, 2015-02-25)
    const int dirPerms = S_IRWXU | S_IRWXG | S_IRWXO;
    mkdir(docsRstDir.c_str(), dirPerms);
    mkdir(docsOutputDir.c_str(), dirPerms);

    forv_Vec(ModuleSymbol, mod, gModuleSymbols) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!mod->hasFlag(FLAG_NO_DOC) && !devOnlyModule(mod)) {
        if (isNotSubmodule(mod)) {
          std::ofstream *file = openFileFromMod(mod, docsRstDir);

          AstPrintDocs *docsVisitor = new AstPrintDocs(file);
          mod->accept(docsVisitor);
          delete docsVisitor;

          // Comment the above three lines and uncomment the following line to
          // get the old category based output (or alphabetical). Note that
          // this will be restored (hopefully soon)... (thomasvandoren, 2015-02-22)
          //
          // printModule(file, mod, 0);

          file->close();
        }
      }
    }

    if (!fDocsTextOnly) {
      generateSphinxOutput(docsSphinxDir, docsOutputDir);
    }

    if (docsTempDir.length() > 0) {
      deleteDir(docsTempDir.c_str());
    }
  }
}

bool isNotSubmodule(ModuleSymbol *mod) {
  return (mod->defPoint == NULL ||
          mod->defPoint->parentSymbol == NULL ||
          mod->defPoint->parentSymbol->name == NULL ||
          strcmp("chpl__Program", mod->defPoint->parentSymbol->name) == 0 ||
          strcmp("_root", mod->defPoint->parentSymbol->name) == 0);
}

void printFields(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  for (int i = 1; i <= cl->fields.length; i++) {
    if (VarSymbol *var = toVarSymbol(((DefExpr *)cl->fields.get(i))->sym)) {
      var->printDocs(file, tabs);
    }
  }
}

void printClass(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  if (!cl->symbol->hasFlag(FLAG_NO_DOC) && ! cl->isUnion()) {
    cl->printDocs(file, tabs);

    printFields(file, cl, tabs + 1);

    // In rst mode, add an additional line break after the attributes and
    // before the next directive.
    if (!fDocsTextOnly) {
      *file << std::endl;
    }

    // If alphabetical option passed, alphabetizes the output
    if (fDocsAlphabetize)
      qsort(cl->methods.v, cl->methods.n, sizeof(cl->methods.v[0]),
        compareNames);

    forv_Vec(FnSymbol, fn, cl->methods){
      // We only want to print methods defined within the class under the
      // class header
      if (fn->isPrimaryMethod())
        fn->printDocs(file, tabs + 1);
    }
  }
}

// Returns true if the provided fn is a module initializer, class constructor,
// type constructor, or module copy of a class method.  These functions are
// only printed in developer mode.  Is not applicable to printing class
// functions.
bool devOnlyFunction(FnSymbol *fn) {
  return (fn->hasFlag(FLAG_MODULE_INIT) || fn->hasFlag(FLAG_TYPE_CONSTRUCTOR)
          || fn->hasFlag(FLAG_CONSTRUCTOR) || fn->isPrimaryMethod());
}

// Returns true if the provide module is one of the internal or standard
// modules. It is our opinion that these should only automatically be printed
// out if the user is in developer mode.
bool devOnlyModule(ModuleSymbol *mod) {
  return mod->modTag == MOD_INTERNAL || mod->modTag == MOD_STANDARD;
}

void printModule(std::ofstream *file, ModuleSymbol *mod, unsigned int tabs) {
  if (!mod->hasFlag(FLAG_NO_DOC)) {
    mod->printDocs(file, tabs);

    Vec<VarSymbol*> configs = mod->getTopLevelConfigVars();
    if (fDocsAlphabetize)
      qsort(configs.v, configs.n, sizeof(configs.v[0]), compareNames);
    forv_Vec(VarSymbol, var, configs) {
      var->printDocs(file, tabs + 1);
    }

    Vec<VarSymbol*> variables = mod->getTopLevelVariables();
    if (fDocsAlphabetize)
      qsort(variables.v, variables.n, sizeof(variables.v[0]), compareNames);
    forv_Vec(VarSymbol, var, variables) {
      var->printDocs(file, tabs + 1);
    }
    Vec<FnSymbol*> fns = mod->getTopLevelFunctions(fDocsIncludeExterns);
    // If alphabetical option passed, fDocsAlphabetizes the output
    if (fDocsAlphabetize)
      qsort(fns.v, fns.n, sizeof(fns.v[0]), compareNames);

    forv_Vec(FnSymbol, fn, fns) {
      // TODO: Add flag to compiler to turn on doc dev only output

      // We want methods on classes that are defined at the module level to be
      // printed at the module level
      if (!devOnlyFunction(fn) || fn->isSecondaryMethod()) {
        fn->printDocs(file, tabs + 1);
      }
    }

    Vec<AggregateType*> classes = mod->getTopLevelClasses();
    if (fDocsAlphabetize)
      qsort(classes.v, classes.n, sizeof(classes.v[0]), compareClasses);

    forv_Vec(AggregateType, cl, classes) {
      printClass(file, cl, tabs + 1);
    }

    Vec<ModuleSymbol*> mods = mod->getTopLevelModules();
    if (fDocsAlphabetize)
      qsort(mods.v, mods.n, sizeof(mods.v[0]), compareNames);

    forv_Vec(ModuleSymbol, subMod, mods) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!devOnlyModule(subMod)) {
        subMod->addPrefixToName(mod->docsName() + ".");
        printModule(file, subMod, tabs + 1);
      }
    }
  }
}

void createDocsFileFolders(std::string filename) {
  size_t dirCutoff = filename.find("/");
  size_t total = 0;
  while (dirCutoff != std::string::npos) {
    // Creates each subdirectory within the new documentation directory
    dirCutoff += total;
    std::string shorter = filename.substr(dirCutoff+1);
    std::string otherHalf = filename.substr(0, dirCutoff);
    mkdir(otherHalf.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);
    total = dirCutoff + 1;
    dirCutoff = shorter.find("/");
  }
}

/*
 * Create new sphinx project at given location and return path where .rst files
 * should be placed.
 */
std::string generateSphinxProject(std::string dirpath) {
  // Create the output dir under the docs output dir.
  const char * sphinxDir = dirpath.c_str();

  // Ensure output directory exists.
  const char * mkdirCmd = astr("mkdir -p ", sphinxDir);
  mysystem(mkdirCmd, "creating docs output dir");

  // Copy the sphinx template into the output dir.
  const char * sphinxTemplate = astr(CHPL_HOME, "/third-party/chpldoc-venv/chpldoc-sphinx-project/*");
  const char * cmd = astr("cp -r ", sphinxTemplate, " ", sphinxDir, "/");
  mysystem(cmd, "copying chpldoc sphinx template");

  const char * moddir = astr(sphinxDir, "/source/modules");
  return std::string(moddir);
}

/* Returns the first path found matching '$venvDir/lib/python*\/site-packages' */
static const char* getPythonPath(const char* venvDir) {
  glob_t globResult;
  const char* globPattern = astr(venvDir, "/lib/python*/site-packages");
  glob(globPattern, 0, NULL, &globResult);
  const size_t count = globResult.gl_pathc;

  // No results found. Return "".

  // FIXME: This should report error (chpldoc is not properly built/installed),
  //        and stop processing...
  //        (thomasvandoren, 2015-03-10)
  char* result;
  if (count == 0) {
    result = (char*)"";
  // At least one result found, so return first.
  } else {
    result = globResult.gl_pathv[0];
  }
  globfree(&globResult);
  return result;
}

/*
 * Invoke sphinx-build using sphinxDir to find conf.py and rst sources, and
 * outputDir for generated html files.
 */
void generateSphinxOutput(std::string sphinxDir, std::string outputDir) {
  // Set the PATH and VIRTUAL_ENV variables in the environment. The values are
  // based on the install path in the third-party/chpldoc-venv/ dir.

  const char * venvDir = astr(
    CHPL_HOME, "/third-party/chpldoc-venv/install/",
    CHPL_TARGET_PLATFORM, "/chpldoc-virtualenv");
  const char * venvBinDir = astr(venvDir, "/bin");
  const char * sphinxBuild = astr(venvBinDir, "/sphinx-build");

  const char * pythonPath = getPythonPath(venvDir);

  const char * envVars = astr("export PATH=", venvBinDir, ":$PATH && ",
                              "export VIRTUAL_ENV=", venvDir, " && ",
                              "export PYTHONPATH=", pythonPath);

  // Run:
  //   $envVars &&
  //     sphinx-build -b html
  //     -d $sphinxDir/build/doctrees -W
  //     $sphinxDir/source $outputDir
  const char * cmdPrefix = astr(envVars, " && ");
  const char * cmd = astr(
    cmdPrefix,
    sphinxBuild, " -b html -d ",
    sphinxDir.c_str(), "/build/doctrees -W ",
    sphinxDir.c_str(), "/source ", outputDir.c_str());
  mysystem(cmd, "building html output from chpldoc sphinx project");
  printf("HTML files are at: %s\n", outputDir.c_str());
}

std::string filenameFromMod(ModuleSymbol *mod, std::string docsWorkDir) {
  std::string filename = mod->filename;

  if (mod->modTag == MOD_INTERNAL) {
    filename = "internal-modules/";
  } else if (mod ->modTag == MOD_STANDARD) {
    filename = "standard-modules/";
  } else {
    size_t location = filename.rfind("/");
    if (location != std::string::npos) {
      filename = filename.substr(0, location + 1);
    } else {
      filename = "";
    }
  }
  filename = docsWorkDir + "/" + filename;
  createDocsFileFolders(filename);

  // Creates files for each top level module.
  if (fDocsTextOnly) {
    filename = filename + mod->name + ".txt";
  } else {
    filename = filename + mod->name + ".rst";
  }

  return filename;
}

std::ofstream* openFileFromMod(ModuleSymbol *mod, std::string docsWorkDir) {
  std::string filename = filenameFromMod(mod, docsWorkDir);
  return new std::ofstream(filename.c_str(), std::ios::out);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: sfxhelp.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: as $ $Date: 2000-11-08 14:25:40 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _SFX_HELP_HXX
#define _SFX_HELP_HXX

#ifndef _BUTTON_HXX //autogen
#include <vcl/button.hxx>
#endif
#ifndef _HELP_HXX //autogen
#include <vcl/help.hxx>
#endif
#ifndef _SV_CONFIG_HXX
#include <vcl/config.hxx>
#endif
#include <childwin.hxx>
#include <dockwin.hxx>

#include <docfac.hxx>
#include <viewfac.hxx>
#include <objsh.hxx>
#include <viewsh.hxx>

class HelpPI;
class SHelpInfo;
struct SpecialLinkInfo;
class Library;
class SfxPrinter;
class DirEntry;
class SvStringsDtor;

struct HelpFileInfo
{
    String  aFileName;
    String  aTitle;
};

class SfxHelpPIWrapper : public SfxChildWindow
{
public:
                            SfxHelpPIWrapper(Window *pParent, USHORT nId,
                                SfxBindings *pBindings, SfxChildWinInfo *pInfo);

                            SFX_DECL_CHILDWINDOW(SfxHelpPIWrapper);

    virtual BOOL            QueryClose();
};

class SfxHelpTipsWrapper : public SfxChildWindow
{
public:
                            SfxHelpTipsWrapper(Window *pParent, USHORT nId,
                                SfxBindings *pBindings, SfxChildWinInfo *pInfo);

                            SFX_DECL_CHILDWINDOW(SfxHelpTipsWrapper);
};

class SfxHelpTipsWindow : public SfxDockingWindow
{
private:
    HelpPI*         mpHelpPI;
    PushButton      maCloseButton;
    Window          maTipWindow;
    CheckBox        maCheckBox;

protected:
    DECL_LINK(      CloseButtonHdl, Button* );
    DECL_LINK(      ShowTip, void* );
    DECL_LINK(      CheckBoxHdl, CheckBox* );

public:
                    SfxHelpTipsWindow( SfxBindings* pBindimgs, SfxChildWindow* pChildWin, Window* pParent );
                    ~SfxHelpTipsWindow();

    virtual void    FillInfo( SfxChildWinInfo& ) const;
    virtual void    Resize();
};

class SfxHelpPI : public SfxDockingWindow
{
    HelpPI*             pHelpPI;
    Window*             pInnerWindow;

    Timer               aTopicJustRequestedTimer;

    ULONG               nTip;
    CheckBox            aTipBox;

    BOOL                bInShowMe;

protected:
    virtual void    Resize();
    virtual void    Paint( const Rectangle& );

public:
                    SfxHelpPI( SfxBindings* pBindimgs, SfxChildWindow* pChildWin,
                                Window* pParent, USHORT nScale );
                    ~SfxHelpPI();

    void            LoadTopic( const String& rFileName, ULONG nId );
    void            LoadTopic( ULONG nId );
    void            LoadTopic( const String& rKeyword );
    void            ResetTopic();

    BOOL            Close();

    BOOL            IsConstructed() const { return ( pHelpPI != 0 ); }
    String          GetExtraInfo() const;

    HelpPI*         GetHelpPI() const { return pHelpPI; }

    virtual void    FillInfo( SfxChildWinInfo& ) const;

    void            SetTip( ULONG nId );
    ULONG           GetTip() const { return nTip; }
    void            SetTipText( const String& rText );

    BOOL            IsInShowMe() const { return bInShowMe; }

    // Nach F1 fuer einige ms nicht aufgrund von FocusChanged ein anderes Topic laden...
    BOOL            IsTopicJustRequested() const { return aTopicJustRequestedTimer.IsActive(); }
    void            SetTopicJustRequested( BOOL bOn ) { if( bOn )
                                                            aTopicJustRequestedTimer.Start();
                                                        else
                                                            aTopicJustRequestedTimer.Stop(); }

#if __PRIVATE
    DECL_LINK(      TopicChangedHdl_Impl, void* );
    DECL_LINK(      SpecialLinkHdl, SpecialLinkInfo* );
    DECL_LINK(      TipBoxHdl, CheckBox* );
    DECL_LINK(      PIToolboxHdl, ToolBox* );
#endif
};

class SfxHelp
{
public:
    static  BOOL            ShowHelp( ULONG nId, BOOL bShowInHelpAgent, const char* pFileName = 0, BOOL bQuiet = FALSE );
    static  BOOL            ShowHelp( const String& rKeyword, BOOL bShowInHelpAgent, const char* pFileName = 0 );
    static  void            ShowHint( ULONG nId );
    static  void            SetCustomHelpFile( const String& rName );
    static  USHORT          GetHelpFileInfoCount();
    static  HelpFileInfo*   GetHelpFileInfo( USHORT n );
};

USHORT ImplSetLanguageGroup( Config& rConfig, const String& rGroupName, BOOL bSearchLanguage );

#if __PRIVATE

SV_DECL_VARARR_SORT( SortedULONGs, ULONG, 0, 4 );
//SV_DECL_PTRARR_DEL( HelpTextCaches, HelpTextCache*, 0, 4 );

class SfxHelp_Impl : public Help, public SfxListener
{
    friend class SfxHelp;

    String              aCustomHelpFile;
    String              aCurHelpFile;   // Kurzer Name ohne Pfad

    SHelpInfo*          pHelpInfo;      // Fr GetHelpText()

//    HelpTextCache*      pHelpCache;
//    HelpTextCaches      aHelpCaches;

    Timer               aDialogDetector;

    SortedULONGs*       pPIStarterList;

    ULONG               nLastDialog;
    BOOL                bForcedFloatingPI;

    List*               pHelpFileInfos;

private:
    BOOL            ImplStart( ULONG nHelpId, BOOL bCheckHelpFile, BOOL bChangeHelpFile, BOOL bHelpAgent );
    virtual BOOL    Start( ULONG nHelpId );
#ifndef ENABLEUNICODE
    virtual BOOL    Start( const String& rKeyWord );
#else
    virtual BOOL    Start( const UniString& rKeyWord );
#endif
    void            SetCurrentHelpFile( ULONG nId );
    String          GetCurrentHelpFile() const { return aCurHelpFile; }

    virtual void    Notify( SfxBroadcaster& rBC, const SfxHint& rHint );

    inline SortedULONGs*    GetPIStarterList();
    void                    CreatePIStarterList();

    DECL_LINK(      DialogDetectHdl, Timer* );

protected:
    void            AssertValidHelpDocInfo();

public:

                    SfxHelp_Impl();
                    ~SfxHelp_Impl();

    static String   GetHelpPath();
    static String   GetHelpFileName( ULONG nId );
    BOOL            CheckHelpFile( BOOL bPrompt ) const;
    static BOOL     CheckHelpFile( const String& rFilename, BOOL bPrompt );

    static Window*  SearchFocusWindowParent();
    void            CheckPIPosition();

    void            SetHelpFile( const String &rHelpFileName, BOOL bAdjustExt = TRUE );
    const String&   GetCurHelpFile() const { return aCurHelpFile; }

    XubString       GetHelpText( ULONG nHelpId );

    void            GetHelpURLs( const String& rRootURL, SvStringsDtor& rLst );
    void            GetBookmarks( SvStringsDtor& rLst );
    void            AddBookmark( const String& rName, const String& rURL );
    void            RemoveBookmark( const String& rName );
    void            RenameBookmark( const String& rOldTitle, const String& rNewTitle );

    void            SlotExecutedOrFocusChanged( ULONG nId, BOOL bSlot, BOOL bAutoStart );
    void            EnableTip( ULONG nTip, BOOL bEnable );

    void            ResetPIStarterList();

    void            HelpAgentClosed();

    void            StartHelpPI( ULONG nHelpId, BOOL bSlot, BOOL bTip = FALSE );

    USHORT          GetHelpFileInfoCount();
    HelpFileInfo*   GetHelpFileInfo( USHORT n );

    static String   GetConfigDir( BOOL bGetSharedConfig );
    static String   GetHelpAgentConfig();
};

inline SortedULONGs* SfxHelp_Impl::GetPIStarterList()
{
    if ( !pPIStarterList )
        CreatePIStarterList();
    return pPIStarterList;
}

#endif // _PRIVATE

#endif // #ifndef _SFX_HELP_HXX

<commit_msg>#80231#: new help browser<commit_after>/*************************************************************************
 *
 *  $RCSfile: sfxhelp.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: mba $ $Date: 2000-11-27 08:56:56 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _SFX_HELP_HXX
#define _SFX_HELP_HXX

#ifndef _HELP_HXX //autogen
#include <vcl/help.hxx>
#endif

#include <tools/string.hxx>

#if __PRIVATE
class SfxHelp_Impl : public Help
{
    String          aTicket;        // for Plugins

private:
    virtual BOOL    Start( ULONG nHelpId );
    String          GetHelpModuleName( ULONG nHelpId );
public:
                    SfxHelp_Impl();
                    ~SfxHelp_Impl();
    void            SetTicket( const String& rTicket )
                    { aTicket = rTicket;}
};
#endif // _PRIVATE

#endif // #ifndef _SFX_HELP_HXX

<|endoftext|>


<commit_before>/// Le Plan:
/// 1. Proof of concept.
/// 2. ???
/// 3. PROFIT!

// blackhole/sink/asynchronous.hpp

#include <atomic>
#include <thread>

#include <cds/container/vyukov_mpmc_cycle_queue.h>

#include "blackhole/sink.hpp"

#include "blackhole/detail/record.owned.hpp"

namespace blackhole {
inline namespace v1 {
namespace experimental {
namespace sink {

class asynchronous_t : public sink_t {
    struct value_type {
        detail::owned<record_t> record;
        std::string message;
    };

    // union union_type {
    //     struct {} uninitialized;
    //     value_type value;
    //
    //     constexpr union_type() noexcept :
    //         uninitialized({})
    //     {}
    //
    //     union_type(const union_type& other) = delete;
    //
    //     union_type(union_type&& other) noexcept :
    //         value(std::move(other.value))
    //     {}
    //
    //     ~union_type() {}
    //
    //     auto operator=(const union_type& other) -> union_type& = delete;
    //
    //     auto operator=(union_type&& other) noexcept -> union_type& {
    //         value = std::move(other.value);
    //         return *this;
    //     }
    // };

    typedef cds::container::VyukovMPSCCycleQueue<value_type> queue_type;

    queue_type queue;
    std::atomic<bool> running;
    std::unique_ptr<sink_t> wrapped;

    std::thread thread;

public:
    /// \param factor queue capacity factor from which the queue capacity will be generated as
    ///     a value of `2 << factor`. Must fit in [0; 20] range (64 MB).
    /// \param queue_type
    /// \param overflow_policy [drop silently, drop with error, block]
    asynchronous_t(std::unique_ptr<sink_t> wrapped, std::size_t factor = 10);

    ~asynchronous_t();

    auto emit(const record_t& record, const string_view& message) -> void;

private:
    auto run() -> void;
};

}  // namespace sink
}  // namespace experimental
}  // namespace v1
}  // namespace blackhole

// src/sink/asynchronous.cpp

#include <unistd.h>

#include <cmath>

namespace blackhole {
inline namespace v1 {
namespace experimental {
namespace sink {
namespace {

static auto exp2(std::size_t factor) -> std::size_t {
    if (factor > 20) {
        throw std::invalid_argument("factor should fit in [0; 20] range");
    }

    return std::exp2(factor);
}

}  // namespace

asynchronous_t::asynchronous_t(std::unique_ptr<sink_t> wrapped, std::size_t factor) :
    queue(exp2(factor)),
    running(true),
    wrapped(std::move(wrapped)),
    thread(std::bind(&asynchronous_t::run, this))
{}

asynchronous_t::~asynchronous_t() {
    running = false;
    thread.join();
}

auto asynchronous_t::emit(const record_t& record, const string_view& message) -> void {
    if (!running) {
        return;
    }

    const auto enqueued = queue.enqueue_with([&](value_type& value) {
        value = {detail::owned<record_t>(record), message.to_string()};
    });

    // TODO: If failed, some kind of overflow policy is immediately involved.
}

auto asynchronous_t::run() -> void {
    while (true) {
        value_type result;
        const auto dequeued = queue.dequeue_with([&](value_type& value) {
            result = std::move(value);
        });

        // std::cout << std::boolalpha << dequeued << ":" << result.message << std::endl;
        if (dequeued) {
            // TODO: What to do with exceptions?
            wrapped->emit(result.record.into_view(), result.message);
        } else {
            // Sleep or CV.
            ::usleep(1000);
        }

        if (!(running || dequeued)) {
            return;
        }
    }
}

}  // namespace sink
}  // namespace experimental
}  // namespace v1
}  // namespace blackhole

// unit/sink/asynchronous.cpp

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "mocks/sink.hpp"

namespace blackhole {
inline namespace v1 {
namespace experimental {
namespace sink {
namespace {

using ::testing::_;

namespace mock = testing::mock;

TEST(asynchronous_t, DelegatesEmit) {
    std::unique_ptr<mock::sink_t> wrapped(new mock::sink_t);

    EXPECT_CALL(*wrapped, emit(_, string_view("formatted message")))
        .Times(1);

    asynchronous_t sink(std::move(wrapped));

    const string_view message("");
    const attribute_pack pack;
    record_t record(42, message, pack);

    sink.emit(record, "formatted message");
}

}  // namespace
}  // namespace sink
}  // namespace experimental
}  // namespace v1
}  // namespace blackhole
<commit_msg>refactor(sink/asynchronous): clean up the code<commit_after>/// Le Plan:
/// 1. Proof of concept.
/// 2. ???
/// 3. PROFIT!

// blackhole/sink/asynchronous.hpp

#include <atomic>
#include <thread>

#include <cds/container/vyukov_mpmc_cycle_queue.h>

#include "blackhole/sink.hpp"

#include "blackhole/detail/record.owned.hpp"

namespace blackhole {
inline namespace v1 {
namespace experimental {
namespace sink {

class asynchronous_t : public sink_t {
    struct value_type {
        detail::owned<record_t> record;
        std::string message;
    };

    typedef cds::container::VyukovMPSCCycleQueue<value_type> queue_type;

    queue_type queue;
    std::atomic<bool> running;
    std::unique_ptr<sink_t> wrapped;

    std::thread thread;

public:
    /// \param factor queue capacity factor from which the queue capacity will be generated as
    ///     a value of `2 << factor`. Must fit in [0; 20] range (64 MB).
    /// \param queue_type
    /// \param overflow_policy [drop silently, drop with error, block]
    ///
    /// \throw std::invalid_argument if the factor is greater than 20.
    asynchronous_t(std::unique_ptr<sink_t> wrapped, std::size_t factor = 10);

    ~asynchronous_t();

    auto emit(const record_t& record, const string_view& message) -> void;

private:
    auto run() -> void;
};

}  // namespace sink
}  // namespace experimental
}  // namespace v1
}  // namespace blackhole

// src/sink/asynchronous.cpp

#include <unistd.h>

#include <cmath>

namespace blackhole {
inline namespace v1 {
namespace experimental {
namespace sink {
namespace {

static auto exp2(std::size_t factor) -> std::size_t {
    if (factor > 20) {
        throw std::invalid_argument("factor should fit in [0; 20] range");
    }

    return std::exp2(factor);
}

}  // namespace

asynchronous_t::asynchronous_t(std::unique_ptr<sink_t> wrapped, std::size_t factor) :
    queue(exp2(factor)),
    running(true),
    wrapped(std::move(wrapped)),
    thread(std::bind(&asynchronous_t::run, this))
{}

asynchronous_t::~asynchronous_t() {
    running.store(false);
    thread.join();
}

auto asynchronous_t::emit(const record_t& record, const string_view& message) -> void {
    if (!running) {
        return;
    }

    const auto enqueued = queue.enqueue_with([&](value_type& value) {
        value = {detail::owned<record_t>(record), message.to_string()};
    });

    // TODO: If failed, some kind of overflow policy is immediately involved.
}

auto asynchronous_t::run() -> void {
    while (true) {
        value_type result;
        const auto dequeued = queue.dequeue_with([&](value_type& value) {
            result = std::move(value);
        });

        // std::cout << std::boolalpha << dequeued << ":" << result.message << std::endl;
        if (dequeued) {
            // TODO: What to do with exceptions?
            wrapped->emit(result.record.into_view(), result.message);
        } else {
            // Sleep or CV.
            ::usleep(1000);
        }

        if (!(running || dequeued)) {
            return;
        }
    }
}

}  // namespace sink
}  // namespace experimental
}  // namespace v1
}  // namespace blackhole

// unit/sink/asynchronous.cpp

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "mocks/sink.hpp"

namespace blackhole {
inline namespace v1 {
namespace experimental {
namespace sink {
namespace {

using ::testing::_;

namespace mock = testing::mock;

TEST(asynchronous_t, DelegatesEmit) {
    std::unique_ptr<mock::sink_t> wrapped(new mock::sink_t);

    EXPECT_CALL(*wrapped, emit(_, string_view("formatted message")))
        .Times(1);

    asynchronous_t sink(std::move(wrapped));

    const string_view message("");
    const attribute_pack pack;
    record_t record(42, message, pack);

    sink.emit(record, "formatted message");
}

}  // namespace
}  // namespace sink
}  // namespace experimental
}  // namespace v1
}  // namespace blackhole
<|endoftext|>


<commit_before>// -*- Mode:C++ -*-

/**************************************************************************************************/
/*                                                                                */
/* Copyright (C) 2016 University of Hull                                                          */
/*                                                                                */
/**************************************************************************************************/
/*                                                                                */
/*  module     :  hugh/support/thread.hpp                                                         */
/*  project    :                                                                                */
/*  description:                                                                                */
/*                                                                                */
/**************************************************************************************************/

#if !defined(HUGH_SUPPORT_THREAD_HPP)

#define HUGH_SUPPORT_THREAD_HPP

// includes, system

#include <iosfwd> // std::ostream (fwd)
#include <mutex>  // std::mutex, std::lock_guard<>
#include <string> // std::string
#include <thread> // std::this_thread, std::thread

// includes, project

#include <hugh/support/chrono.hpp> // support::clock::duration
#include <hugh/support/config.hpp>

namespace hugh {

  namespace support {

    // types, exported (class, enum, struct, union, typedef)

    namespace this_thread = std::this_thread;

    using simple_lock       = std::mutex;
    using simple_lock_guard = std::lock_guard<simple_lock>;

    // variables, exported (extern)

    // functions, inlined (inline)

    // functions, exported (extern)

    HUGH_SUPPORT_EXPORT
    void dump_thread_stats(std::ostream&          /* output_stream     */,
                           std::string const&     /* context_string    */,
                           clock::duration const& /* timeout/interval  */,
                           clock::duration const& /* actual activity   */,
                           bool                   /* thread_was_paused */,
                           unsigned               /* dump modulo       */ = 10);

  } // namespace support {

} // namespace hugh {

#endif // #if !defined(HUGH_SUPPORT_THREAD_HPP)
<commit_msg>added: support::recursive_lock[_guard]<commit_after>// -*- Mode:C++ -*-

/**************************************************************************************************/
/*                                                                                */
/* Copyright (C) 2016 University of Hull                                                          */
/*                                                                                */
/**************************************************************************************************/
/*                                                                                */
/*  module     :  hugh/support/thread.hpp                                                         */
/*  project    :                                                                                */
/*  description:                                                                                */
/*                                                                                */
/**************************************************************************************************/

#if !defined(HUGH_SUPPORT_THREAD_HPP)

#define HUGH_SUPPORT_THREAD_HPP

// includes, system

#include <iosfwd> // std::ostream (fwd)
#include <mutex>  // std::mutex, std::lock_guard<>
#include <string> // std::string
#include <thread> // std::this_thread, std::thread

// includes, project

#include <hugh/support/chrono.hpp> // support::clock::duration
#include <hugh/support/config.hpp>

namespace hugh {

  namespace support {

    // types, exported (class, enum, struct, union, typedef)

    namespace this_thread = std::this_thread;

    using recursive_lock       = std::recursive_mutex;
    using recursive_lock_guard = std::lock_guard<recursive_lock>;
    using simple_lock          = std::mutex;
    using simple_lock_guard    = std::lock_guard<simple_lock>;

    // variables, exported (extern)

    // functions, inlined (inline)

    // functions, exported (extern)

    HUGH_SUPPORT_EXPORT
    void dump_thread_stats(std::ostream&          /* output_stream     */,
                           std::string const&     /* context_string    */,
                           clock::duration const& /* timeout/interval  */,
                           clock::duration const& /* actual activity   */,
                           bool                   /* thread_was_paused */,
                           unsigned               /* dump modulo       */ = 10);

  } // namespace support {

} // namespace hugh {

#endif // #if !defined(HUGH_SUPPORT_THREAD_HPP)
<|endoftext|>


<commit_before>#pragma once
#include <exception>
#include "iostream"
using namespace std;

class MatrixException : public std::exception {
public:
	MatrixException() : std::exception(invalid_argument("Unknown exception")) {}
	MatrixException(const char *_message) : std::exception(invalid_argument(_message)) {}
};
class FileException : public MatrixException {
public:
	FileException() : MatrixException("File cannot be opened") {};
};
class SizesException : public MatrixException {
public:
	SizesException() : MatrixException("Wrong sizes of matrix") {};
};
class StreamException : public MatrixException {
public:
	StreamException() : MatrixException("Fill error: bad stream") {};
};
class IndexException : public MatrixException {
public:
	IndexException() : MatrixException("Index >= number of lines") {};
};
class AddException : public MatrixException {
public:
	AddException() : MatrixException("left_matrix.columns != right_matrix.columns\
 || left_matrix.lines != right_matix.lines") {};
};
class MultiplyException : public MatrixException {
public:
	MultiplyException() : MatrixException("left_matrix.columns != right_matrix.lines") {};
};
<commit_msg>Delete MatrixException.hpp<commit_after><|endoftext|>


<commit_before>#include "ServerRepo.hpp"
#include "../inanity/net/Fcgi.hpp"
#include "../inanity/MemoryStream.hpp"
#include "../inanity/StreamReader.hpp"
#include "../inanity/StreamWriter.hpp"
#include "../inanity/File.hpp"
#include "../inanity/Thread.hpp"
#include "../inanity/CriticalSection.hpp"
#include "../inanity/CriticalCode.hpp"
#include "../inanity/Time.hpp"
#include <vector>
#include <iostream>
#include <cstring>

BEGIN_INANITY_OIL

class Server : public Object
{
private:
	ptr<ServerRepo> repo;
	long long lastSyncRevision;
	CriticalSection csRepo;

	std::vector<std::pair<ptr<Net::Fcgi::Request>, Time::Tick> > watchRequests;
	CriticalSection csWatchRequests;

	Server() : lastSyncRevision(-1) {}

	void Process(ptr<Net::Fcgi::Request> request)
	{
		std::cerr << request->GetParam("REQUEST_URI") << '\n';

		StreamReader reader(request->GetInputStream());
		StreamWriter writer(request->GetOutputStream());

		try
		{
			const char* query = request->GetParam("QUERY_STRING");
			if(!query)
				query = "";

			if(strcmp(query, "manifest") == 0)
			{
				request->OutputContentType("application/x-inanityoil-manifest");
				request->OutputStatus("200 OK");
				request->OutputBeginResponse();

				{
					CriticalCode cc(csRepo);
					repo->WriteManifest(&writer);
				}

				request->End();
			}
			else if(strcmp(query, "sync") == 0)
			{
				request->OutputContentType("application/x-inanityoil-sync");
				request->OutputStatus("200 OK");
				request->OutputBeginResponse();

				ptr<File> watchResponse;
				{
					CriticalCode cc(csRepo);
					// TODO: add actual user verification
					// task postponed
					static const String userName = "anonimous";
					repo->Sync(&reader, &writer, userName, true);
					long long maxRevision = repo->GetMaxRevision();
					if(lastSyncRevision < maxRevision)
					{
						ptr<MemoryStream> stream = NEW(MemoryStream());
						StreamWriter writer(stream);
						repo->RespondWatch(&writer);
						watchResponse = stream->ToFile();
					}
					lastSyncRevision = maxRevision;
				}

				request->End();

				if(watchResponse)
				{
					// respond to all watch requests
					CriticalCode cc(csWatchRequests);

					for(size_t i = 0; i < watchRequests.size(); ++i)
						try
						{
							ptr<Net::Fcgi::Request> request = watchRequests[i].first;
							request->GetOutputStream()->Write(watchResponse);
							request->End();
						}
						catch(Exception* exception)
						{
							request->End();
							MakePointer(exception)->PrintStack(std::cerr);
							std::cerr << '\n';
						}

					watchRequests.clear();
				}
			}
			else if(strcmp(query, "watch") == 0)
			{
				request->OutputContentType("application/x-inanityoil-watchreply");
				request->OutputStatus("200 OK");
				request->OutputBeginResponse();

				bool watchResponded;
				{
					CriticalCode cc(csRepo);
					watchResponded = repo->Watch(&reader, &writer);
				}
				if(watchResponded)
					request->End();
				else
				{
					CriticalCode cc(csWatchRequests);
					watchRequests.push_back(std::make_pair(request, Time::GetTicks()));
				}
			}
			else
			{
				// unknown query
				request->OutputContentType("text/plain");
				request->OutputStatus("400 Bad Request");
				request->OutputBeginResponse();
				static const char response[] =
					"Unknown query string";
				writer.Write(response, sizeof(response) - 1);
				request->End();
			}
		}
		catch(Exception* exception)
		{
			request->End();
			MakePointer(exception)->PrintStack(std::cerr);
			std::cerr << '\n';
		}
	}

	void BackgroundProcess(const Thread::ThreadHandler::Result& threadResult)
	{
		const int sleepPause = 1000;
		const Time::Tick timeout = 20 * Time::GetTicksPerSecond();
		for(;;)
		{
			{
				Time::Tick tick = Time::GetTicks();
				CriticalCode cc(csWatchRequests);

				ptr<File> response = nullptr;

				size_t j = 0;
				for(size_t i = 0; i < watchRequests.size(); ++i)
				{
					if(watchRequests[i].second + timeout < tick)
					{
						if(!response)
						{
							ptr<MemoryStream> stream = NEW(MemoryStream());
							StreamWriter writer(stream);
							{
								CriticalCode cc(csRepo);
								repo->RespondWatch(&writer);
							}
							response = stream->ToFile();
						}

						watchRequests[i].first->GetOutputStream()->Write(response);
						watchRequests[i].first->End();
					}
					else
						watchRequests[j++] = watchRequests[i];
				}
				watchRequests.resize(j);
			}

			Thread::Sleep(sleepPause);
		}
	}

	int Run(int argc, char** argv)
	{
		// read options
		argc--;
		argv++;

		const char* fileName = nullptr;
		const char* socketName = ":5000";
		int backlogSize = 10;

		for(int i = 0; i < argc; ++i)
		{
			if(strcmp(argv[i], "-f") == 0)
			{
				if(++i < argc)
					fileName = argv[i];
				else
				{
					std::cerr << "-f requires file name\n";
					return 1;
				}
			}
			else if(strcmp(argv[i], "-s") == 0)
			{
				if(++i < argc)
					socketName = argv[i];
				else
				{
					std::cerr << "-s requires socket name\n";
					return 1;
				}
			}
			else if(strcmp(argv[i], "-b") == 0)
			{
				if(++i < argc)
					backlogSize = atoi(argv[i]);
				else
				{
					std::cerr << "-b requires backlog size\n";
					return 1;
				}
			}
			else
			{
				std::cerr << "Unknown option: " << argv[i] << "\n";
				return 1;
			}
		}

		if(!fileName)
		{
			std::cerr << "You should set db file name with -f\n";
			return 1;
		}

		repo = NEW(ServerRepo(fileName));

		MakePointer(NEW(Thread(Thread::ThreadHandler::Bind<Server>(this, &Server::BackgroundProcess))));

		Net::Fcgi fcgi(socketName, backlogSize);

		while(ptr<Net::Fcgi::Request> request = fcgi.Accept())
			Process(request);

		std::cerr << "end\n";

		return 0;
	}

public:
	static int Main(int argc, char** argv)
	{
		try
		{
			return MakePointer(NEW(Server()))->Run(argc, argv);
		}
		catch(Exception* exception)
		{
			MakePointer(exception)->PrintStack(std::cerr);
			std::cerr << "\n";
			return 1;
		}
	}
};

END_INANITY_OIL

int main(int argc, char** argv)
{
	return Inanity::Oil::Server::Main(argc, argv);
}
<commit_msg>change according to rename GetTicks to GetTick<commit_after>#include "ServerRepo.hpp"
#include "../inanity/net/Fcgi.hpp"
#include "../inanity/MemoryStream.hpp"
#include "../inanity/StreamReader.hpp"
#include "../inanity/StreamWriter.hpp"
#include "../inanity/File.hpp"
#include "../inanity/Thread.hpp"
#include "../inanity/CriticalSection.hpp"
#include "../inanity/CriticalCode.hpp"
#include "../inanity/Time.hpp"
#include <vector>
#include <iostream>
#include <cstring>

BEGIN_INANITY_OIL

class Server : public Object
{
private:
	ptr<ServerRepo> repo;
	long long lastSyncRevision;
	CriticalSection csRepo;

	std::vector<std::pair<ptr<Net::Fcgi::Request>, Time::Tick> > watchRequests;
	CriticalSection csWatchRequests;

	Server() : lastSyncRevision(-1) {}

	void Process(ptr<Net::Fcgi::Request> request)
	{
		std::cerr << request->GetParam("REQUEST_URI") << '\n';

		StreamReader reader(request->GetInputStream());
		StreamWriter writer(request->GetOutputStream());

		try
		{
			const char* query = request->GetParam("QUERY_STRING");
			if(!query)
				query = "";

			if(strcmp(query, "manifest") == 0)
			{
				request->OutputContentType("application/x-inanityoil-manifest");
				request->OutputStatus("200 OK");
				request->OutputBeginResponse();

				{
					CriticalCode cc(csRepo);
					repo->WriteManifest(&writer);
				}

				request->End();
			}
			else if(strcmp(query, "sync") == 0)
			{
				request->OutputContentType("application/x-inanityoil-sync");
				request->OutputStatus("200 OK");
				request->OutputBeginResponse();

				ptr<File> watchResponse;
				{
					CriticalCode cc(csRepo);
					// TODO: add actual user verification
					// task postponed
					static const String userName = "anonimous";
					repo->Sync(&reader, &writer, userName, true);
					long long maxRevision = repo->GetMaxRevision();
					if(lastSyncRevision < maxRevision)
					{
						ptr<MemoryStream> stream = NEW(MemoryStream());
						StreamWriter writer(stream);
						repo->RespondWatch(&writer);
						watchResponse = stream->ToFile();
					}
					lastSyncRevision = maxRevision;
				}

				request->End();

				if(watchResponse)
				{
					// respond to all watch requests
					CriticalCode cc(csWatchRequests);

					for(size_t i = 0; i < watchRequests.size(); ++i)
						try
						{
							ptr<Net::Fcgi::Request> request = watchRequests[i].first;
							request->GetOutputStream()->Write(watchResponse);
							request->End();
						}
						catch(Exception* exception)
						{
							request->End();
							MakePointer(exception)->PrintStack(std::cerr);
							std::cerr << '\n';
						}

					watchRequests.clear();
				}
			}
			else if(strcmp(query, "watch") == 0)
			{
				request->OutputContentType("application/x-inanityoil-watchreply");
				request->OutputStatus("200 OK");
				request->OutputBeginResponse();

				bool watchResponded;
				{
					CriticalCode cc(csRepo);
					watchResponded = repo->Watch(&reader, &writer);
				}
				if(watchResponded)
					request->End();
				else
				{
					CriticalCode cc(csWatchRequests);
					watchRequests.push_back(std::make_pair(request, Time::GetTick()));
				}
			}
			else
			{
				// unknown query
				request->OutputContentType("text/plain");
				request->OutputStatus("400 Bad Request");
				request->OutputBeginResponse();
				static const char response[] =
					"Unknown query string";
				writer.Write(response, sizeof(response) - 1);
				request->End();
			}
		}
		catch(Exception* exception)
		{
			request->End();
			MakePointer(exception)->PrintStack(std::cerr);
			std::cerr << '\n';
		}
	}

	void BackgroundProcess(const Thread::ThreadHandler::Result& threadResult)
	{
		const int sleepPause = 1000;
		const Time::Tick timeout = 20 * Time::GetTicksPerSecond();
		for(;;)
		{
			{
				Time::Tick tick = Time::GetTick();
				CriticalCode cc(csWatchRequests);

				ptr<File> response = nullptr;

				size_t j = 0;
				for(size_t i = 0; i < watchRequests.size(); ++i)
				{
					if(watchRequests[i].second + timeout < tick)
					{
						if(!response)
						{
							ptr<MemoryStream> stream = NEW(MemoryStream());
							StreamWriter writer(stream);
							{
								CriticalCode cc(csRepo);
								repo->RespondWatch(&writer);
							}
							response = stream->ToFile();
						}

						watchRequests[i].first->GetOutputStream()->Write(response);
						watchRequests[i].first->End();
					}
					else
						watchRequests[j++] = watchRequests[i];
				}
				watchRequests.resize(j);
			}

			Thread::Sleep(sleepPause);
		}
	}

	int Run(int argc, char** argv)
	{
		// read options
		argc--;
		argv++;

		const char* fileName = nullptr;
		const char* socketName = ":5000";
		int backlogSize = 10;

		for(int i = 0; i < argc; ++i)
		{
			if(strcmp(argv[i], "-f") == 0)
			{
				if(++i < argc)
					fileName = argv[i];
				else
				{
					std::cerr << "-f requires file name\n";
					return 1;
				}
			}
			else if(strcmp(argv[i], "-s") == 0)
			{
				if(++i < argc)
					socketName = argv[i];
				else
				{
					std::cerr << "-s requires socket name\n";
					return 1;
				}
			}
			else if(strcmp(argv[i], "-b") == 0)
			{
				if(++i < argc)
					backlogSize = atoi(argv[i]);
				else
				{
					std::cerr << "-b requires backlog size\n";
					return 1;
				}
			}
			else
			{
				std::cerr << "Unknown option: " << argv[i] << "\n";
				return 1;
			}
		}

		if(!fileName)
		{
			std::cerr << "You should set db file name with -f\n";
			return 1;
		}

		repo = NEW(ServerRepo(fileName));

		MakePointer(NEW(Thread(Thread::ThreadHandler::Bind<Server>(this, &Server::BackgroundProcess))));

		Net::Fcgi fcgi(socketName, backlogSize);

		while(ptr<Net::Fcgi::Request> request = fcgi.Accept())
			Process(request);

		std::cerr << "end\n";

		return 0;
	}

public:
	static int Main(int argc, char** argv)
	{
		try
		{
			return MakePointer(NEW(Server()))->Run(argc, argv);
		}
		catch(Exception* exception)
		{
			MakePointer(exception)->PrintStack(std::cerr);
			std::cerr << "\n";
			return 1;
		}
	}
};

END_INANITY_OIL

int main(int argc, char** argv)
{
	return Inanity::Oil::Server::Main(argc, argv);
}
<|endoftext|>