<commit_before>/*
    This file is part of KDE.

    Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "parserrelaxng.h"

#include <kdebug.h>

#include <iostream>

using namespace RNG;

Pattern::Pattern()
  : optional( false ), zeroOrMore( false ), oneOrMore( false ),
    choice( false )
{
}

bool Pattern::isEmpty()
{
  return !optional && !zeroOrMore && !oneOrMore && !choice;
}

QString Pattern::asString()
{
  if ( isEmpty() ) return "";
  QString str = "( ";
  if ( optional ) str += "optional ";
  if ( zeroOrMore ) str += "zeroOrMore ";
  if ( oneOrMore ) str += "oneOrMore ";
  if ( choice ) str += "choice ";
  str += ')';
  return str;
}

void Pattern::merge( Pattern p )
{
  if ( p.optional ) optional = true;
  if ( p.zeroOrMore ) zeroOrMore = true;
  if ( p.oneOrMore ) oneOrMore = true;
  if ( p.choice ) choice = true;
}

Element::Element()
  : hasText( false ), isEmpty( false )
{
}

ParserRelaxng::ParserRelaxng()
{
}

void ParserRelaxng::setVerbose( bool verbose )
{
  mVerbose = verbose;
}

Element *ParserRelaxng::parse( const QDomElement &docElement )
{
  Element *start = 0;

  QDomNode n1;
  for( n1 = docElement.firstChild(); !n1.isNull(); n1 = n1.nextSibling() ) {
    QDomElement e1 = n1.toElement();
    if ( mVerbose ) {
      kDebug() << "TOP LEVEL element " << e1.tagName() << endl;
    }
    if ( e1.tagName() == "define" ) {
      Element *d = new Element;
      d->name = e1.attribute( "name" );
      parseElement( e1, d, Pattern() );
      Element::List definitions;
      QMap<QString,Element::List >::ConstIterator it;
      it = mDefinitionMap.find( d->name );
      if ( it != mDefinitionMap.end() ) definitions = *it;
      definitions.append( d );
      mDefinitionMap.insert( d->name, definitions );
    } else if ( e1.tagName() == "start" ) {
      start = new Element;
      parseElement( e1, start, Pattern() );
    } else {
      kDebug() << "parseGrammar: Unrecognized tag: " << e1.tagName() << endl;
    }
  }

  return start;
}

Reference *ParserRelaxng::parseReference( const QDomElement &referenceElement )
{
  Reference *r = new Reference;
  r->name = referenceElement.attribute( "name" );
  return r;
}

bool ParserRelaxng::parseAttribute( const QDomElement &attributeElement,
                           Attribute *a )
{
  a->name = attributeElement.attribute( "name" );

  return true;
}

bool ParserRelaxng::parseElement( const QDomElement &elementElement, Element *e,
                   Pattern pattern )
{
  if ( mVerbose ) {
    kDebug() << "parseElement " << e->name << endl;
  }

  QDomNode n1;
  for( n1 = elementElement.firstChild(); !n1.isNull(); n1 = n1.nextSibling() ) {
    QDomElement e1 = n1.toElement();
    if ( e1.tagName() == "element" ) {
      Element *element = new Element;
      element->name = e1.attribute( "name" );
      element->pattern = pattern;
      parseElement( e1, element, Pattern() );
      e->elements.append( element );
    } else if ( e1.tagName() == "attribute" ) {
      Attribute *a = new Attribute;
      a->name = e1.attribute( "name" );
      a->pattern = pattern;
      if ( mVerbose ) {
        kDebug() << "ATTRIBUTE: " << a->name << " " << a->pattern.asString()
                 << endl;
      }
      parseAttribute( e1, a );
      e->attributes.append( a );
    } else if ( e1.tagName() == "ref" ) {
      Reference *r = parseReference( e1 );
      r->pattern = pattern;
      e->references.append( r );
    } else if ( e1.tagName() == "text" ) {
      e->hasText = true;
    } else if ( e1.tagName() == "empty" ) {
      e->isEmpty = true;
    } else {
      Pattern p = pattern;
      if ( e1.tagName() == "optional" ) p.optional = true;
      else if ( e1.tagName() == "zeroOrMore" ) p.zeroOrMore = true;
      else if ( e1.tagName() == "oneOrMore" ) p.oneOrMore = true;
      else if ( e1.tagName() == "choice" ) p.choice = true;
      else {
        kDebug() << "Unsupported pattern '" << e1.tagName() << "'" << endl;
      }
      parseElement( e1, e, p );
    }
  }

  return true;
}

void ParserRelaxng::substituteReferences( Element *s )
{
  if ( mVerbose ) {
    kDebug() << "substituteReferences for '" << s->name << "'" << endl;
  }
  Reference::List::Iterator it = s->references.begin();
  while( it != s->references.end() ) {
    Reference *r = *it;
    if ( mVerbose ) {
      kDebug() << "REF " << r->name << endl;
    }
    if ( r->name == s->name ) {
      if ( mVerbose ) {
        kDebug() << "Don't resolve self reference" << endl;
      }
      return;
    }
    if ( r->substituted ) {
      if ( mVerbose ) {
        kDebug() << "Already substituted." << endl;
      }
      ++it;
      continue;
    } else {
      r->substituted = true;
    }
    QMap<QString,Element::List >::ConstIterator it1;
    it1 = mDefinitionMap.find( r->name );
    if ( it1 != mDefinitionMap.end() ) {
      Element::List elements = *it1;
      Element::List::ConstIterator it4;
      for( it4 = elements.begin(); it4 != elements.end(); ++it4 ) {
        Element *d = *it4;
        substituteReferences( d );
        Element::List::ConstIterator it2;
        for( it2 = d->elements.begin(); it2 != d->elements.end(); ++it2 ) {
          Element *e = *it2;
          e->pattern.merge( r->pattern );
          substituteReferences( e );
          s->elements.append( e );
        }
        Attribute::List::ConstIterator it3;
        for( it3 = d->attributes.begin(); it3 != d->attributes.end();
             ++it3 ) {
          Attribute *a = *it3;
          a->pattern.merge( r->pattern );
          s->attributes.append( a );
        }
      }
      it = s->references.erase( it );
    } else {
      kDebug() << "Reference not found" << endl;
      ++it;
    }
  }
}

void ParserRelaxng::doIndent( int cols )
{
  for( int i = 0; i < cols; ++i ) std::cout << " ";
}

void ParserRelaxng::dumpPattern( Pattern pattern )
{
  std::cout << pattern.asString().toLocal8Bit().data();
}

void ParserRelaxng::dumpReferences( const Reference::List &references, int indent )
{
  Reference::List::ConstIterator it;
  for( it = references.begin(); it != references.end(); ++it ) {
    Reference *r = *it;
    doIndent( indent );
    std::cout << "REFERENCE " << r->name.toLocal8Bit().data();
    dumpPattern( r->pattern );
    std::cout << std::endl;
  }
}

void ParserRelaxng::dumpAttributes( const Attribute::List &attributes, int indent )
{
  Attribute::List::ConstIterator it;
  for( it = attributes.begin(); it != attributes.end(); ++it ) {
    Attribute *a = *it;
    doIndent( indent );
    std::cout << "ATTRIBUTE " << a->name.toLocal8Bit().data();
    dumpPattern( a->pattern );
    std::cout << std::endl;
  }
}

void ParserRelaxng::dumpElements( const Element::List &elements, int indent )
{
  Element::List::ConstIterator it;
  for( it = elements.begin(); it != elements.end(); ++it ) {
    Element *e = *it;
    dumpElement( e, indent );
  }
}

void ParserRelaxng::dumpElement( Element *e, int indent )
{
  doIndent( indent );
  std::cout << "ELEMENT " << e->name.toLocal8Bit().data();
  dumpPattern( e->pattern );
  std::cout << std::endl;

  if ( e->hasText ) {
    doIndent( indent + 2 );
    std::cout << "TEXT" << std::endl;
  }

  dumpAttributes( e->attributes, indent + 2 );
  dumpElements( e->elements, indent + 2 );
  dumpReferences( e->references, indent + 2 );
}

void ParserRelaxng::dumpTree( Element *s )
{
  std::cout << "START " << s->name.toLocal8Bit().data() << std::endl;
  dumpElements( s->elements, 2 );
  dumpReferences( s->references, 2 );
}

void ParserRelaxng::dumpDefinitionMap()
{
  std::cout << "DEFINITION MAP" << std::endl;
  QMap<QString,Element::List >::ConstIterator it;
  for( it = mDefinitionMap.begin(); it != mDefinitionMap.end(); ++it ) {
    dumpElements( *it, 2 );
  }
}

Schema::Document ParserRelaxng::convertToSchema( Element *start )
{
  Element::List elements = start->elements;
  if ( !elements.isEmpty() ) {
    Schema::Element element = convertToSchemaElement( elements.first() );
    mDocument.setStartElement( element );
  }

  return mDocument;
}

Schema::Element ParserRelaxng::convertToSchemaElement( Element *e )
{
  Schema::Element schemaElement;
  schemaElement.setName( e->name );
  schemaElement.setIdentifier( e->name );

  if ( e->hasText ) schemaElement.setText( true );

  foreach( Element *element, e->elements ) {
    QString id = element->name;
    if ( !mDocument.element( id ).isValid() ) {
      Schema::Element relatedElement = convertToSchemaElement( element );
    }
    Schema::Relation relation = convertToRelation( element->pattern, id );
    schemaElement.addElementRelation( relation );
  }

  foreach( Attribute *attribute, e->attributes ) {
    QString id = schemaElement.identifier() + '/' + attribute->name;
    if ( !mDocument.attribute( id ).isValid() ) {
      Schema::Attribute relatedAttribute = convertToSchemaAttribute(
        schemaElement.identifier(), attribute );
    }
    Schema::Relation relation = convertToRelation( attribute->pattern, id );
    schemaElement.addAttributeRelation( relation );
  }

  foreach( Reference *reference, e->references ) {
    QString id = reference->name;
    Schema::Relation relation = convertToRelation( reference->pattern, id );
    schemaElement.addElementRelation( relation );
  }

  mDocument.addElement( schemaElement );

  return schemaElement;
}

Schema::Relation ParserRelaxng::convertToRelation( const Pattern &pattern,
  const QString &id )
{
  Schema::Relation relation( id );
  if ( pattern.optional ) {
    relation.setMinOccurs( 0 );
    relation.setMaxOccurs( 1 );
  } else if ( pattern.zeroOrMore ) {
    relation.setMinOccurs( 0 );
    relation.setMaxOccurs( Schema::Relation::Unbounded );
  } else if ( pattern.oneOrMore ) {
    relation.setMinOccurs( 1 );
    relation.setMaxOccurs( Schema::Relation::Unbounded );
  }

  return relation;
}

Schema::Attribute ParserRelaxng::convertToSchemaAttribute( const QString &path,
  Attribute *a )
{
  Schema::Attribute schemaAttribute;
  schemaAttribute.setName( a->name );
  schemaAttribute.setIdentifier( path + '/' + a->name );

  mDocument.addAttribute( schemaAttribute );

  return schemaAttribute;
}
<commit_msg>Don't loop over all DOM nodes, convert them to elements and ignore the null elements. Rather simply loop over all DOM elements in the first place. Thanks to Tobias for the hint. This reduces the output of 'unrecognized patterns' of the kxml_compiler by half...<commit_after>/*
    This file is part of KDE.

    Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "parserrelaxng.h"

#include <kdebug.h>

#include <iostream>

using namespace RNG;

Pattern::Pattern()
  : optional( false ), zeroOrMore( false ), oneOrMore( false ),
    choice( false )
{
}

bool Pattern::isEmpty()
{
  return !optional && !zeroOrMore && !oneOrMore && !choice;
}

QString Pattern::asString()
{
  if ( isEmpty() ) return "";
  QString str = "( ";
  if ( optional ) str += "optional ";
  if ( zeroOrMore ) str += "zeroOrMore ";
  if ( oneOrMore ) str += "oneOrMore ";
  if ( choice ) str += "choice ";
  str += ')';
  return str;
}

void Pattern::merge( Pattern p )
{
  if ( p.optional ) optional = true;
  if ( p.zeroOrMore ) zeroOrMore = true;
  if ( p.oneOrMore ) oneOrMore = true;
  if ( p.choice ) choice = true;
}

Element::Element()
  : hasText( false ), isEmpty( false )
{
}

ParserRelaxng::ParserRelaxng()
{
}

void ParserRelaxng::setVerbose( bool verbose )
{
  mVerbose = verbose;
}

Element *ParserRelaxng::parse( const QDomElement &docElement )
{
  Element *start = 0;

  QDomNode n1;
  QDomElement e1;
  for( e1 = docElement.firstChildElement(); !e1.isNull(); e1 = e1.nextSiblingElement() ) {
    if ( mVerbose ) {
      kDebug() << "TOP LEVEL element " << e1.tagName() << endl;
    }
    if ( e1.tagName() == "define" ) {
      Element *d = new Element;
      d->name = e1.attribute( "name" );
      parseElement( e1, d, Pattern() );
      Element::List definitions;
      QMap<QString,Element::List >::ConstIterator it;
      it = mDefinitionMap.find( d->name );
      if ( it != mDefinitionMap.end() ) definitions = *it;
      definitions.append( d );
      mDefinitionMap.insert( d->name, definitions );
    } else if ( e1.tagName() == "start" ) {
      start = new Element;
      parseElement( e1, start, Pattern() );
    } else if ( e1.isComment()  ) {
      // Ignore all comments for now!
    } else {
      kDebug() << "parseGrammar: Unrecognized tag:  " << e1.tagName() << endl;
    }
  }

  return start;
}

Reference *ParserRelaxng::parseReference( const QDomElement &referenceElement )
{
  Reference *r = new Reference;
  r->name = referenceElement.attribute( "name" );
  return r;
}

bool ParserRelaxng::parseAttribute( const QDomElement &attributeElement,
                           Attribute *a )
{
  a->name = attributeElement.attribute( "name" );

  return true;
}

bool ParserRelaxng::parseElement( const QDomElement &elementElement, Element *e,
                   Pattern pattern )
{
  if ( mVerbose ) {
    kDebug() << "parseElement " << e->name << endl;
  }

  QDomNode n1;
  QDomElement e1;
  for( e1 = elementElement.firstChildElement(); !e1.isNull(); e1 = e1.nextSiblingElement() ) {
    if ( e1.tagName() == "element" ) {
      Element *element = new Element;
      element->name = e1.attribute( "name" );
      element->pattern = pattern;
      parseElement( e1, element, Pattern() );
      e->elements.append( element );
    } else if ( e1.tagName() == "attribute" ) {
      Attribute *a = new Attribute;
      a->name = e1.attribute( "name" );
      a->pattern = pattern;
      if ( mVerbose ) {
        kDebug() << "ATTRIBUTE: " << a->name << " " << a->pattern.asString()
                 << endl;
      }
      parseAttribute( e1, a );
      e->attributes.append( a );
    } else if ( e1.tagName() == "ref" ) {
      Reference *r = parseReference( e1 );
      r->pattern = pattern;
      e->references.append( r );
    } else if ( e1.tagName() == "text" ) {
      e->hasText = true;
    } else if ( e1.tagName() == "empty" ) {
      e->isEmpty = true;
    } else {
      Pattern p = pattern;
      if ( e1.tagName() == "optional" ) p.optional = true;
      else if ( e1.tagName() == "zeroOrMore" ) p.zeroOrMore = true;
      else if ( e1.tagName() == "oneOrMore" ) p.oneOrMore = true;
      else if ( e1.tagName() == "choice" ) p.choice = true;
      else {
        kDebug() << "Unsupported pattern '" << e1.tagName() << "'" << endl;
      }
      parseElement( e1, e, p );
    }
  }

  return true;
}

void ParserRelaxng::substituteReferences( Element *s )
{
  if ( mVerbose ) {
    kDebug() << "substituteReferences for '" << s->name << "'" << endl;
  }
  Reference::List::Iterator it = s->references.begin();
  while( it != s->references.end() ) {
    Reference *r = *it;
    if ( mVerbose ) {
      kDebug() << "REF " << r->name << endl;
    }
    if ( r->name == s->name ) {
      if ( mVerbose ) {
        kDebug() << "Don't resolve self reference" << endl;
      }
      return;
    }
    if ( r->substituted ) {
      if ( mVerbose ) {
        kDebug() << "Already substituted." << endl;
      }
      ++it;
      continue;
    } else {
      r->substituted = true;
    }
    QMap<QString,Element::List >::ConstIterator it1;
    it1 = mDefinitionMap.find( r->name );
    if ( it1 != mDefinitionMap.end() ) {
      Element::List elements = *it1;
      Element::List::ConstIterator it4;
      for( it4 = elements.begin(); it4 != elements.end(); ++it4 ) {
        Element *d = *it4;
        substituteReferences( d );
        Element::List::ConstIterator it2;
        for( it2 = d->elements.begin(); it2 != d->elements.end(); ++it2 ) {
          Element *e = *it2;
          e->pattern.merge( r->pattern );
          substituteReferences( e );
          s->elements.append( e );
        }
        Attribute::List::ConstIterator it3;
        for( it3 = d->attributes.begin(); it3 != d->attributes.end();
             ++it3 ) {
          Attribute *a = *it3;
          a->pattern.merge( r->pattern );
          s->attributes.append( a );
        }
      }
      it = s->references.erase( it );
    } else {
      kDebug() << "Reference not found" << endl;
      ++it;
    }
  }
}

void ParserRelaxng::doIndent( int cols )
{
  for( int i = 0; i < cols; ++i ) std::cout << " ";
}

void ParserRelaxng::dumpPattern( Pattern pattern )
{
  std::cout << pattern.asString().toLocal8Bit().data();
}

void ParserRelaxng::dumpReferences( const Reference::List &references, int indent )
{
  Reference::List::ConstIterator it;
  for( it = references.begin(); it != references.end(); ++it ) {
    Reference *r = *it;
    doIndent( indent );
    std::cout << "REFERENCE " << r->name.toLocal8Bit().data();
    dumpPattern( r->pattern );
    std::cout << std::endl;
  }
}

void ParserRelaxng::dumpAttributes( const Attribute::List &attributes, int indent )
{
  Attribute::List::ConstIterator it;
  for( it = attributes.begin(); it != attributes.end(); ++it ) {
    Attribute *a = *it;
    doIndent( indent );
    std::cout << "ATTRIBUTE " << a->name.toLocal8Bit().data();
    dumpPattern( a->pattern );
    std::cout << std::endl;
  }
}

void ParserRelaxng::dumpElements( const Element::List &elements, int indent )
{
  Element::List::ConstIterator it;
  for( it = elements.begin(); it != elements.end(); ++it ) {
    Element *e = *it;
    dumpElement( e, indent );
  }
}

void ParserRelaxng::dumpElement( Element *e, int indent )
{
  doIndent( indent );
  std::cout << "ELEMENT " << e->name.toLocal8Bit().data();
  dumpPattern( e->pattern );
  std::cout << std::endl;

  if ( e->hasText ) {
    doIndent( indent + 2 );
    std::cout << "TEXT" << std::endl;
  }

  dumpAttributes( e->attributes, indent + 2 );
  dumpElements( e->elements, indent + 2 );
  dumpReferences( e->references, indent + 2 );
}

void ParserRelaxng::dumpTree( Element *s )
{
  std::cout << "START " << s->name.toLocal8Bit().data() << std::endl;
  dumpElements( s->elements, 2 );
  dumpReferences( s->references, 2 );
}

void ParserRelaxng::dumpDefinitionMap()
{
  std::cout << "DEFINITION MAP" << std::endl;
  QMap<QString,Element::List >::ConstIterator it;
  for( it = mDefinitionMap.begin(); it != mDefinitionMap.end(); ++it ) {
    dumpElements( *it, 2 );
  }
}

Schema::Document ParserRelaxng::convertToSchema( Element *start )
{
  Element::List elements = start->elements;
  if ( !elements.isEmpty() ) {
    Schema::Element element = convertToSchemaElement( elements.first() );
    mDocument.setStartElement( element );
  }

  return mDocument;
}

Schema::Element ParserRelaxng::convertToSchemaElement( Element *e )
{
  Schema::Element schemaElement;
  schemaElement.setName( e->name );
  schemaElement.setIdentifier( e->name );

  if ( e->hasText ) schemaElement.setText( true );

  foreach( Element *element, e->elements ) {
    QString id = element->name;
    if ( !mDocument.element( id ).isValid() ) {
      Schema::Element relatedElement = convertToSchemaElement( element );
    }
    Schema::Relation relation = convertToRelation( element->pattern, id );
    schemaElement.addElementRelation( relation );
  }

  foreach( Attribute *attribute, e->attributes ) {
    QString id = schemaElement.identifier() + '/' + attribute->name;
    if ( !mDocument.attribute( id ).isValid() ) {
      Schema::Attribute relatedAttribute = convertToSchemaAttribute(
        schemaElement.identifier(), attribute );
    }
    Schema::Relation relation = convertToRelation( attribute->pattern, id );
    schemaElement.addAttributeRelation( relation );
  }

  foreach( Reference *reference, e->references ) {
    QString id = reference->name;
    Schema::Relation relation = convertToRelation( reference->pattern, id );
    schemaElement.addElementRelation( relation );
  }

  mDocument.addElement( schemaElement );

  return schemaElement;
}

Schema::Relation ParserRelaxng::convertToRelation( const Pattern &pattern,
  const QString &id )
{
  Schema::Relation relation( id );
  if ( pattern.optional ) {
    relation.setMinOccurs( 0 );
    relation.setMaxOccurs( 1 );
  } else if ( pattern.zeroOrMore ) {
    relation.setMinOccurs( 0 );
    relation.setMaxOccurs( Schema::Relation::Unbounded );
  } else if ( pattern.oneOrMore ) {
    relation.setMinOccurs( 1 );
    relation.setMaxOccurs( Schema::Relation::Unbounded );
  }

  return relation;
}

Schema::Attribute ParserRelaxng::convertToSchemaAttribute( const QString &path,
  Attribute *a )
{
  Schema::Attribute schemaAttribute;
  schemaAttribute.setName( a->name );
  schemaAttribute.setIdentifier( path + '/' + a->name );

  mDocument.addAttribute( schemaAttribute );

  return schemaAttribute;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: except.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-13 11:02:18 $
 *
 *  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>
#include <dlfcn.h>
#include <cxxabi.h>
#include <hash_map>

#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>
#include <osl/diagnose.h>
#include <osl/mutex.hxx>

#include <com/sun/star/uno/genfunc.hxx>
#include "com/sun/star/uno/RuntimeException.hpp"
#include <typelib/typedescription.hxx>
#include <uno/any2.h>

#include "share.hxx"

using namespace ::std;
using namespace ::osl;
using namespace ::rtl;
using namespace ::com::sun::star::uno;
using namespace ::__cxxabiv1;

namespace CPPU_CURRENT_NAMESPACE
{

void dummy_can_throw_anything( char const * )
{
}

//==================================================================================================
static OUString toUNOname( char const * p ) SAL_THROW( () )
{
#if OSL_DEBUG_LEVEL > 1
    char const * start = p;
#endif

    // example: N3com3sun4star4lang24IllegalArgumentExceptionE

    OUStringBuffer buf( 64 );
    OSL_ASSERT( 'N' == *p );
    ++p; // skip N

    while ('E' != *p)
    {
        // read chars count
        long n = (*p++ - '0');
        while ('0' <= *p && '9' >= *p)
        {
            n *= 10;
            n += (*p++ - '0');
        }
        buf.appendAscii( p, n );
        p += n;
        if ('E' != *p)
            buf.append( (sal_Unicode)'.' );
    }

#if OSL_DEBUG_LEVEL > 1
    OUString ret( buf.makeStringAndClear() );
    OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
    fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
    return ret;
#else
    return buf.makeStringAndClear();
#endif
}

//==================================================================================================
class RTTI
{
    typedef hash_map< OUString, type_info *, OUStringHash > t_rtti_map;

    Mutex m_mutex;
    t_rtti_map m_rttis;
    t_rtti_map m_generatedRttis;

    void * m_hApp;

public:
    RTTI() SAL_THROW( () );
    ~RTTI() SAL_THROW( () );

    type_info * getRTTI( typelib_CompoundTypeDescription * ) SAL_THROW( () );
};
//__________________________________________________________________________________________________
RTTI::RTTI() SAL_THROW( () )
    : m_hApp( dlopen( 0, RTLD_LAZY ) )
{
}
//__________________________________________________________________________________________________
RTTI::~RTTI() SAL_THROW( () )
{
    dlclose( m_hApp );
}

//__________________________________________________________________________________________________
type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) SAL_THROW( () )
{
    type_info * rtti;

    OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;

    MutexGuard guard( m_mutex );
    t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) );
    if (iFind == m_rttis.end())
    {
        // RTTI symbol
        OStringBuffer buf( 64 );
        buf.append( RTL_CONSTASCII_STRINGPARAM("_ZTIN") );
        sal_Int32 index = 0;
        do
        {
            OUString token( unoName.getToken( 0, '.', index ) );
            buf.append( token.getLength() );
            OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
            buf.append( c_token );
        }
        while (index >= 0);
        buf.append( 'E' );

        OString symName( buf.makeStringAndClear() );
        rtti = (type_info *)dlsym( m_hApp, symName.getStr() );

        if (rtti)
        {
            pair< t_rtti_map::iterator, bool > insertion(
                m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
            OSL_ENSURE( insertion.second, "### inserting new rtti failed?!" );
        }
        else
        {
            // try to lookup the symbol in the generated rtti map
            t_rtti_map::const_iterator iFind2( m_generatedRttis.find( unoName ) );
            if (iFind2 == m_generatedRttis.end())
            {
                // we must generate it !
                // symbol and rtti-name is nearly identical,
                // the symbol is prefixed with _ZTI
                char const * rttiName = symName.getStr() +4;
#if OSL_DEBUG_LEVEL > 1
                fprintf( stderr,"generated rtti for %s\n", rttiName );
#endif
                if (pTypeDescr->pBaseTypeDescription)
                {
                    // ensure availability of base
                    type_info * base_rtti = getRTTI(
                        (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
                    rtti = new __si_class_type_info(
                        strdup( rttiName ), (__class_type_info *)base_rtti );
                }
                else
                {
                    // this class has no base class
                    rtti = new __class_type_info( strdup( rttiName ) );
                }

                pair< t_rtti_map::iterator, bool > insertion(
                    m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
                OSL_ENSURE( insertion.second, "### inserting new generated rtti failed?!" );
            }
            else // taking already generated rtti
            {
                rtti = iFind2->second;
            }
        }
    }
    else
    {
        rtti = iFind->second;
    }

    return rtti;
}

//--------------------------------------------------------------------------------------------------
static void deleteException( void * pExc )
{
    __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
    typelib_TypeDescription * pTD = 0;
    OUString unoName( toUNOname( header->exceptionType->name() ) );
    ::typelib_typedescription_getByName( &pTD, unoName.pData );
    OSL_ENSURE( pTD, "### unknown exception type! leaving out destruction => leaking!!!" );
    if (pTD)
    {
        ::uno_destructData( pExc, pTD, cpp_release );
        ::typelib_typedescription_release( pTD );
    }
}

//==================================================================================================
void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
{
#if OSL_DEBUG_LEVEL > 1
    OString cstr(
        OUStringToOString(
            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
            RTL_TEXTENCODING_ASCII_US ) );
    fprintf( stderr, "> uno exception occured: %s\n", cstr.getStr() );
#endif
    void * pCppExc;
    type_info * rtti;

    {
    // construct cpp exception object
    typelib_TypeDescription * pTypeDescr = 0;
    TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
    OSL_ASSERT( pTypeDescr );
    if (! pTypeDescr)
    {
        throw RuntimeException(
            OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get typedescription for type ") ) +
            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
            Reference< XInterface >() );
    }

    pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
    ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );

    // destruct uno exception
    ::uno_any_destruct( pUnoExc, 0 );
    // avoiding locked counts
    static RTTI * s_rtti = 0;
    if (! s_rtti)
    {
        MutexGuard guard( Mutex::getGlobalMutex() );
        if (! s_rtti)
        {
#ifdef LEAK_STATIC_DATA
            s_rtti = new RTTI();
#else
            static RTTI rtti_data;
            s_rtti = &rtti_data;
#endif
        }
    }
    rtti = (type_info *)s_rtti->getRTTI( (typelib_CompoundTypeDescription *) pTypeDescr );
    TYPELIB_DANGER_RELEASE( pTypeDescr );
    OSL_ENSURE( rtti, "### no rtti for throwing exception!" );
    if (! rtti)
    {
        throw RuntimeException(
            OUString( RTL_CONSTASCII_USTRINGPARAM("no rtti for type ") ) +
            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
            Reference< XInterface >() );
    }
    }

    __cxa_throw( pCppExc, rtti, deleteException );
}

//==================================================================================================
void fillUnoException( __cxa_exception * header, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno )
{
    if (! header)
    {
        RuntimeException aRE(
            OUString( RTL_CONSTASCII_USTRINGPARAM("no exception header!") ),
            Reference< XInterface >() );
        Type const & rType = ::getCppuType( &aRE );
        uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
#if OSL_DEBUG_LEVEL > 0
        OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) );
        OSL_ENSURE( 0, cstr.getStr() );
#endif
        return;
    }

    typelib_TypeDescription * pExcTypeDescr = 0;
    OUString unoName( toUNOname( header->exceptionType->name() ) );
#if OSL_DEBUG_LEVEL > 1
    OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
    fprintf( stderr, "> c++ exception occured: %s\n", cstr_unoName.getStr() );
#endif
    typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
    if (0 == pExcTypeDescr)
    {
        RuntimeException aRE(
            OUString( RTL_CONSTASCII_USTRINGPARAM("exception type not found: ") ) + unoName,
            Reference< XInterface >() );
        Type const & rType = ::getCppuType( &aRE );
        uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
#if OSL_DEBUG_LEVEL > 0
        OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) );
        OSL_ENSURE( 0, cstr.getStr() );
#endif
    }
    else
    {
        // construct uno exception any
        uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
        typelib_typedescription_release( pExcTypeDescr );
    }
}

}

<commit_msg>INTEGRATION: CWS pchfix02 (1.2.48); FILE MERGED 2006/09/01 17:17:35 kaib 1.2.48.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: except.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 15:51:22 $
 *
 *  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_bridges.hxx"

#include <stdio.h>
#include <dlfcn.h>
#include <cxxabi.h>
#include <hash_map>

#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>
#include <osl/diagnose.h>
#include <osl/mutex.hxx>

#include <com/sun/star/uno/genfunc.hxx>
#include "com/sun/star/uno/RuntimeException.hpp"
#include <typelib/typedescription.hxx>
#include <uno/any2.h>

#include "share.hxx"

using namespace ::std;
using namespace ::osl;
using namespace ::rtl;
using namespace ::com::sun::star::uno;
using namespace ::__cxxabiv1;

namespace CPPU_CURRENT_NAMESPACE
{

void dummy_can_throw_anything( char const * )
{
}

//==================================================================================================
static OUString toUNOname( char const * p ) SAL_THROW( () )
{
#if OSL_DEBUG_LEVEL > 1
    char const * start = p;
#endif

    // example: N3com3sun4star4lang24IllegalArgumentExceptionE

    OUStringBuffer buf( 64 );
    OSL_ASSERT( 'N' == *p );
    ++p; // skip N

    while ('E' != *p)
    {
        // read chars count
        long n = (*p++ - '0');
        while ('0' <= *p && '9' >= *p)
        {
            n *= 10;
            n += (*p++ - '0');
        }
        buf.appendAscii( p, n );
        p += n;
        if ('E' != *p)
            buf.append( (sal_Unicode)'.' );
    }

#if OSL_DEBUG_LEVEL > 1
    OUString ret( buf.makeStringAndClear() );
    OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
    fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
    return ret;
#else
    return buf.makeStringAndClear();
#endif
}

//==================================================================================================
class RTTI
{
    typedef hash_map< OUString, type_info *, OUStringHash > t_rtti_map;

    Mutex m_mutex;
    t_rtti_map m_rttis;
    t_rtti_map m_generatedRttis;

    void * m_hApp;

public:
    RTTI() SAL_THROW( () );
    ~RTTI() SAL_THROW( () );

    type_info * getRTTI( typelib_CompoundTypeDescription * ) SAL_THROW( () );
};
//__________________________________________________________________________________________________
RTTI::RTTI() SAL_THROW( () )
    : m_hApp( dlopen( 0, RTLD_LAZY ) )
{
}
//__________________________________________________________________________________________________
RTTI::~RTTI() SAL_THROW( () )
{
    dlclose( m_hApp );
}

//__________________________________________________________________________________________________
type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) SAL_THROW( () )
{
    type_info * rtti;

    OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;

    MutexGuard guard( m_mutex );
    t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) );
    if (iFind == m_rttis.end())
    {
        // RTTI symbol
        OStringBuffer buf( 64 );
        buf.append( RTL_CONSTASCII_STRINGPARAM("_ZTIN") );
        sal_Int32 index = 0;
        do
        {
            OUString token( unoName.getToken( 0, '.', index ) );
            buf.append( token.getLength() );
            OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
            buf.append( c_token );
        }
        while (index >= 0);
        buf.append( 'E' );

        OString symName( buf.makeStringAndClear() );
        rtti = (type_info *)dlsym( m_hApp, symName.getStr() );

        if (rtti)
        {
            pair< t_rtti_map::iterator, bool > insertion(
                m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
            OSL_ENSURE( insertion.second, "### inserting new rtti failed?!" );
        }
        else
        {
            // try to lookup the symbol in the generated rtti map
            t_rtti_map::const_iterator iFind2( m_generatedRttis.find( unoName ) );
            if (iFind2 == m_generatedRttis.end())
            {
                // we must generate it !
                // symbol and rtti-name is nearly identical,
                // the symbol is prefixed with _ZTI
                char const * rttiName = symName.getStr() +4;
#if OSL_DEBUG_LEVEL > 1
                fprintf( stderr,"generated rtti for %s\n", rttiName );
#endif
                if (pTypeDescr->pBaseTypeDescription)
                {
                    // ensure availability of base
                    type_info * base_rtti = getRTTI(
                        (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
                    rtti = new __si_class_type_info(
                        strdup( rttiName ), (__class_type_info *)base_rtti );
                }
                else
                {
                    // this class has no base class
                    rtti = new __class_type_info( strdup( rttiName ) );
                }

                pair< t_rtti_map::iterator, bool > insertion(
                    m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
                OSL_ENSURE( insertion.second, "### inserting new generated rtti failed?!" );
            }
            else // taking already generated rtti
            {
                rtti = iFind2->second;
            }
        }
    }
    else
    {
        rtti = iFind->second;
    }

    return rtti;
}

//--------------------------------------------------------------------------------------------------
static void deleteException( void * pExc )
{
    __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
    typelib_TypeDescription * pTD = 0;
    OUString unoName( toUNOname( header->exceptionType->name() ) );
    ::typelib_typedescription_getByName( &pTD, unoName.pData );
    OSL_ENSURE( pTD, "### unknown exception type! leaving out destruction => leaking!!!" );
    if (pTD)
    {
        ::uno_destructData( pExc, pTD, cpp_release );
        ::typelib_typedescription_release( pTD );
    }
}

//==================================================================================================
void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
{
#if OSL_DEBUG_LEVEL > 1
    OString cstr(
        OUStringToOString(
            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
            RTL_TEXTENCODING_ASCII_US ) );
    fprintf( stderr, "> uno exception occured: %s\n", cstr.getStr() );
#endif
    void * pCppExc;
    type_info * rtti;

    {
    // construct cpp exception object
    typelib_TypeDescription * pTypeDescr = 0;
    TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
    OSL_ASSERT( pTypeDescr );
    if (! pTypeDescr)
    {
        throw RuntimeException(
            OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get typedescription for type ") ) +
            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
            Reference< XInterface >() );
    }

    pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
    ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );

    // destruct uno exception
    ::uno_any_destruct( pUnoExc, 0 );
    // avoiding locked counts
    static RTTI * s_rtti = 0;
    if (! s_rtti)
    {
        MutexGuard guard( Mutex::getGlobalMutex() );
        if (! s_rtti)
        {
#ifdef LEAK_STATIC_DATA
            s_rtti = new RTTI();
#else
            static RTTI rtti_data;
            s_rtti = &rtti_data;
#endif
        }
    }
    rtti = (type_info *)s_rtti->getRTTI( (typelib_CompoundTypeDescription *) pTypeDescr );
    TYPELIB_DANGER_RELEASE( pTypeDescr );
    OSL_ENSURE( rtti, "### no rtti for throwing exception!" );
    if (! rtti)
    {
        throw RuntimeException(
            OUString( RTL_CONSTASCII_USTRINGPARAM("no rtti for type ") ) +
            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
            Reference< XInterface >() );
    }
    }

    __cxa_throw( pCppExc, rtti, deleteException );
}

//==================================================================================================
void fillUnoException( __cxa_exception * header, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno )
{
    if (! header)
    {
        RuntimeException aRE(
            OUString( RTL_CONSTASCII_USTRINGPARAM("no exception header!") ),
            Reference< XInterface >() );
        Type const & rType = ::getCppuType( &aRE );
        uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
#if OSL_DEBUG_LEVEL > 0
        OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) );
        OSL_ENSURE( 0, cstr.getStr() );
#endif
        return;
    }

    typelib_TypeDescription * pExcTypeDescr = 0;
    OUString unoName( toUNOname( header->exceptionType->name() ) );
#if OSL_DEBUG_LEVEL > 1
    OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
    fprintf( stderr, "> c++ exception occured: %s\n", cstr_unoName.getStr() );
#endif
    typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
    if (0 == pExcTypeDescr)
    {
        RuntimeException aRE(
            OUString( RTL_CONSTASCII_USTRINGPARAM("exception type not found: ") ) + unoName,
            Reference< XInterface >() );
        Type const & rType = ::getCppuType( &aRE );
        uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
#if OSL_DEBUG_LEVEL > 0
        OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) );
        OSL_ENSURE( 0, cstr.getStr() );
#endif
    }
    else
    {
        // construct uno exception any
        uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
        typelib_typedescription_release( pExcTypeDescr );
    }
}

}

<|endoftext|>


<commit_before>#ifndef LCPP_OBJECT_H
#define LCPP_OBJECT_H

#include <luacpp/reference.hpp>
#include <luacpp/table.hpp>
#include <luacpp/function.hpp>

namespace lua
{
	class object : virtual public reference, public table, public function
	{
		public:
		object(lua_State* L, int index) : reference(L, index)
		{
		}

		object(){}

		private:
	};
}

#endif
<commit_msg>Added implicit conversion operator for lua::object<commit_after>#ifndef LCPP_OBJECT_H
#define LCPP_OBJECT_H

#include <luacpp/stack.hpp>
#include <luacpp/reference.hpp>
#include <luacpp/table.hpp>
#include <luacpp/function.hpp>

namespace lua
{
	class object : virtual public reference, public table, public function
	{
		public:
		object(lua_State* L, int index) : reference(L, index)
		{
		}

		object(){}

		template<typename T>
		operator T()
		{
			push();
			assertType(state(), -1, typeOf<T>(state()));

			T t;

			getValue(state(), -1, t);

			return t;
		}
	};
}

#endif
<|endoftext|>


<commit_before>//
//  yas_db_utils.cpp
//

#include "yas_db_additional_protocol.h"
#include "yas_db_attribute.h"
#include "yas_db_database.h"
#include "yas_db_model.h"
#include "yas_db_row_set.h"
#include "yas_db_select_option.h"
#include "yas_db_sql_utils.h"
#include "yas_db_utils.h"
#include "yas_unless.h"

using namespace yas;

db::update_result db::create_table(db::database &db, std::string const &table_name,
                                   std::vector<std::string> const &fields) {
    return db.execute_update(create_table_sql(table_name, fields));
}

db::update_result db::alter_table(db::database &db, std::string const &table_name, std::string const &field) {
    return db.execute_update(alter_table_sql(table_name, field));
}

db::update_result db::drop_table(db::database &db, std::string const &table_name) {
    return db.execute_update(drop_table_sql(table_name));
}

db::update_result db::create_index(database &db, std::string const &index_name, std::string const &table_name,
                                   std::vector<std::string> const &fields) {
    return db.execute_update(create_index_sql(index_name, table_name, fields));
}

db::update_result db::drop_index(database &db, std::string const &index_name) {
    return db.execute_update(drop_index_sql(index_name));
}

db::update_result db::begin_transaction(db::database &db) {
    return db.execute_update("BEGIN EXCLUSIVE TRANSACTION");
}

db::update_result db::begin_deferred_transaction(db::database &db) {
    return db.execute_update("BEGIN DEFERRED TRANSACTION");
}

db::update_result db::commit(db::database &db) {
    return db.execute_update("COMMIT TRANSACTION");
}

db::update_result db::rollback(db::database &db) {
    return db.execute_update("ROLLBACK TRANSACTION");
}

#if SQLITE_VERSION_NUMBER >= 3007000

namespace yas {
namespace db {
    static std::string escape_save_point_name(std::string const &name) {
        return replaced(name, "'", "''");
    }
}
}

db::update_result db::start_save_point(db::database &db, std::string const &name) {
    if (name.size() == 0) {
        return update_result{error{error_type::invalid_argument}};
    }
    return db.execute_update("SAVEPOINT '" + escape_save_point_name(name) + "';");
}

db::update_result db::release_save_point(db::database &db, std::string const &name) {
    if (name.size() == 0) {
        return update_result{error{error_type::invalid_argument}};
    }
    return db.execute_update("RELEASE SAVEPOINT '" + escape_save_point_name(name) + "';");
}

db::update_result db::rollback_save_point(db::database &db, std::string const &name) {
    if (name.size() == 0) {
        return update_result{error{error_type::invalid_argument}};
    }
    return db.execute_update("ROLLBACK TRANSACTION TO SAVEPOINT '" + escape_save_point_name(name) + "';");
}

db::update_result db::in_save_point(db::database &db, std::function<void(bool &rollback)> const function) {
    static unsigned long save_point_idx = 0;
    std::string const name = "db_save_point_" + std::to_string(save_point_idx++);

    if (auto ul = unless(start_save_point(db, name))) {
        return std::move(ul.value);
    }

    bool should_rollback = false;

    function(should_rollback);

    if (should_rollback) {
        rollback_save_point(db, name);
    }

    return release_save_point(db, name);
}

#endif

bool db::table_exists(database const &db, std::string const &table_name) {
    if (auto row_set = get_table_schema(db, table_name)) {
        if (row_set.next()) {
            return true;
        }
    }
    return false;
}

bool db::index_exists(database const &db, std::string const &index_name) {
    if (auto row_set = get_index_schema(db, index_name)) {
        if (row_set.next()) {
            return true;
        }
    }
    return false;
}

db::row_set db::get_schema(database const &db) {
    if (auto query_result = db.execute_query(
            "select type, name, tbl_name, rootpage, sql from (select * from sqlite_master union all select * from "
            "sqlite_temp_master) where type != 'meta' and name not like 'sqlite_%' order by tbl_name, type desc, "
            "name")) {
        return query_result.value();
    }
    return nullptr;
}

db::row_set db::get_table_schema(database const &db, std::string const &table_name) {
    if (auto query_result = db.execute_query("PRAGMA table_info('" + table_name + "')")) {
        return query_result.value();
    }
    return nullptr;
}

db::row_set db::get_index_schema(database const &db, std::string const &index_name) {
    if (auto query_result =
            db.execute_query("SELECT * FROM sqlite_master WHERE type = 'index' AND name = '" + index_name + "';")) {
        return query_result.value();
    }
    return nullptr;
}

bool db::column_exists(database const &db, std::string column_name, std::string table_name) {
    std::string lower_table_name = to_lower(std::move(table_name));
    std::string lower_column_name = to_lower(std::move(column_name));

    if (auto row_set = get_table_schema(db, lower_table_name)) {
        while (row_set.next()) {
            auto value = row_set.column_value("name");
            if (to_lower(value.get<db::text>()) == lower_column_name) {
                return true;
            }
        }
    }

    return false;
}

db::select_result db::select(db::database const &db, select_option const &option) {
    auto const sql =
        select_sql(option.table, option.fields, option.where_exprs, option.field_orders, option.limit_range);

    db::value_map_vector value_map_vector;

    if (auto query_result = db.execute_query(sql, option.arguments)) {
        auto row_set = query_result.value();
        while (row_set.next()) {
            value_map_vector.emplace_back(row_set.value_map());
        }
    } else {
        return select_result{std::move(query_result.error())};
    }

    return select_result{value_map_vector};
}

db::select_result db::select_last(database const &db, select_option option, value const &save_id,
                                  bool const include_removed) {
    std::vector<std::string> components;

    if (save_id) {
        components.emplace_back(expr(save_id_field, "<=", to_string(save_id)));
    }

    if (option.where_exprs.size() > 0) {
        components.emplace_back(option.where_exprs);
    }

    std::string sub_where = components.size() > 0 ? " WHERE " + joined(components, " AND ") : "";

    std::string where_exprs =
        "rowid IN (SELECT MAX(rowid) FROM " + option.table + sub_where + " GROUP BY " + db::object_id_field + ")";
    if (!include_removed) {
        static std::string const exc_removed_expr = action_field + " != '" + remove_action + "'";
        where_exprs = joined({where_exprs, exc_removed_expr}, " AND ");
    }
    option.where_exprs = where_exprs;

    return select(db, option);
}

db::select_result db::select_undo(database const &db, std::string const &table_name, integer::type const revert_save_id,
                                  integer::type const current_save_id) {
    if (current_save_id <= revert_save_id) {
        throw "revert_save_id greater than or equal to current_save_id";
    }

    std::vector<std::string> components;
    components.emplace_back(object_id_field + " IN (SELECT DISTINCT " + object_id_field + " FROM " + table_name +
                            " WHERE " + joined({expr(save_id_field, "<=", std::to_string(current_save_id)),
                                                expr(save_id_field, ">", std::to_string(revert_save_id))},
                                               " AND ") +
                            ")");
    components.emplace_back(expr(save_id_field, "<=", std::to_string(revert_save_id)));

    select_option option{.table = table_name,
                         .where_exprs = "rowid IN (SELECT MAX(rowid) FROM " + table_name + " WHERE " +
                                        joined(components, " AND ") + " GROUP BY " + object_id_field + ")",
                         .field_orders = {{object_id_field, order::ascending}}};

    auto result = select(db, option);
    if (!result) {
        return select_result{std::move(result.error())};
    }

    select_option empty_option{.table = table_name,
                               .fields = {object_id_field},
                               .where_exprs = joined({expr(save_id_field, "<=", std::to_string(current_save_id)),
                                                      expr(save_id_field, ">", std::to_string(revert_save_id)),
                                                      equal_field_expr(action_field)},
                                                     " AND "),
                               .arguments = {{action_field, db::value{insert_action}}},
                               .field_orders = {{object_id_field, order::ascending}}};
    auto empty_result = select(db, empty_option);
    if (!empty_result) {
        return select_result{std::move(empty_result.error())};
    }

    return select_result{connect(std::move(result.value()), std::move(empty_result.value()))};
}

db::select_result db::select_redo(database const &db, std::string const &table_name, integer::type const revert_save_id,
                                  integer::type const current_save_id) {
    if (revert_save_id <= current_save_id) {
        throw "current_save_id greater than or equal to revert_save_id";
    }

    std::vector<std::string> components;
    components.emplace_back(expr(save_id_field, ">", std::to_string(current_save_id)));

    db::select_option option{.table = table_name,
                             .where_exprs = joined(components, " AND "),
                             .field_orders = {{object_id_field, db::order::ascending}}};

    return select_last(db, std::move(option), db::value{revert_save_id}, true);
}

db::select_result db::select_revert(database const &db, std::string const &table_name,
                                    integer::type const revert_save_id, integer::type const current_save_id) {
    if (revert_save_id < current_save_id) {
        return select_undo(db, table_name, revert_save_id, current_save_id);
    } else if (current_save_id < revert_save_id) {
        return select_redo(db, table_name, revert_save_id, current_save_id);
    }

    return select_result{value_map_vector{}};
}

db::select_single_result db::select_single(database const &db, select_option option) {
    option.limit_range = {.location = 0, .length = 1};

    if (auto result = select(db, option)) {
        if (result.value().size() > 0) {
            return select_single_result{std::move(result.value().at(0))};
        }
    }

    return select_single_result{nullptr};
}

db::select_single_result db::select_db_info(database const &db) {
    return select_single(db, db::select_option{.table = db::info_table});
}

db::update_result db::purge(database &db, std::string const &table_name) {
    std::string where_exprs =
        "NOT rowid IN (SELECT MAX(rowid) FROM " + table_name + " GROUP BY " + db::object_id_field + ")";
    return db.execute_update(delete_sql(table_name, where_exprs));
}

db::update_result db::purge_relation(database &db, std::string const &table_name, std::string const &src_table_name) {
    std::string where_exprs = "NOT " + db::src_id_field + " IN (SELECT rowid FROM " + src_table_name + ")";
    return db.execute_update(delete_sql(table_name, where_exprs));
}

db::value db::max(database const &db, std::string const &table_name, std::string const &field) {
    if (auto query_result = db.execute_query("SELECT MAX(" + field + ") FROM " + table_name + ";")) {
        auto &row_set = query_result.value();
        if (row_set.next()) {
            return row_set.column_value(0);
        }
    }
    return nullptr;
}
<commit_msg>fix include in db_utils<commit_after>//
//  yas_db_utils.cpp
//

#include "yas_db_additional_protocol.h"
#include "yas_db_attribute.h"
#include "yas_db_database.h"
#include "yas_db_model.h"
#include "yas_db_row_set.h"
#include "yas_db_select_option.h"
#include "yas_db_sql_utils.h"
#include "yas_db_utils.h"
#include "yas_stl_utils.h"
#include "yas_unless.h"

using namespace yas;

db::update_result db::create_table(db::database &db, std::string const &table_name,
                                   std::vector<std::string> const &fields) {
    return db.execute_update(create_table_sql(table_name, fields));
}

db::update_result db::alter_table(db::database &db, std::string const &table_name, std::string const &field) {
    return db.execute_update(alter_table_sql(table_name, field));
}

db::update_result db::drop_table(db::database &db, std::string const &table_name) {
    return db.execute_update(drop_table_sql(table_name));
}

db::update_result db::create_index(database &db, std::string const &index_name, std::string const &table_name,
                                   std::vector<std::string> const &fields) {
    return db.execute_update(create_index_sql(index_name, table_name, fields));
}

db::update_result db::drop_index(database &db, std::string const &index_name) {
    return db.execute_update(drop_index_sql(index_name));
}

db::update_result db::begin_transaction(db::database &db) {
    return db.execute_update("BEGIN EXCLUSIVE TRANSACTION");
}

db::update_result db::begin_deferred_transaction(db::database &db) {
    return db.execute_update("BEGIN DEFERRED TRANSACTION");
}

db::update_result db::commit(db::database &db) {
    return db.execute_update("COMMIT TRANSACTION");
}

db::update_result db::rollback(db::database &db) {
    return db.execute_update("ROLLBACK TRANSACTION");
}

#if SQLITE_VERSION_NUMBER >= 3007000

namespace yas {
namespace db {
    static std::string escape_save_point_name(std::string const &name) {
        return replaced(name, "'", "''");
    }
}
}

db::update_result db::start_save_point(db::database &db, std::string const &name) {
    if (name.size() == 0) {
        return update_result{error{error_type::invalid_argument}};
    }
    return db.execute_update("SAVEPOINT '" + escape_save_point_name(name) + "';");
}

db::update_result db::release_save_point(db::database &db, std::string const &name) {
    if (name.size() == 0) {
        return update_result{error{error_type::invalid_argument}};
    }
    return db.execute_update("RELEASE SAVEPOINT '" + escape_save_point_name(name) + "';");
}

db::update_result db::rollback_save_point(db::database &db, std::string const &name) {
    if (name.size() == 0) {
        return update_result{error{error_type::invalid_argument}};
    }
    return db.execute_update("ROLLBACK TRANSACTION TO SAVEPOINT '" + escape_save_point_name(name) + "';");
}

db::update_result db::in_save_point(db::database &db, std::function<void(bool &rollback)> const function) {
    static unsigned long save_point_idx = 0;
    std::string const name = "db_save_point_" + std::to_string(save_point_idx++);

    if (auto ul = unless(start_save_point(db, name))) {
        return std::move(ul.value);
    }

    bool should_rollback = false;

    function(should_rollback);

    if (should_rollback) {
        rollback_save_point(db, name);
    }

    return release_save_point(db, name);
}

#endif

bool db::table_exists(database const &db, std::string const &table_name) {
    if (auto row_set = get_table_schema(db, table_name)) {
        if (row_set.next()) {
            return true;
        }
    }
    return false;
}

bool db::index_exists(database const &db, std::string const &index_name) {
    if (auto row_set = get_index_schema(db, index_name)) {
        if (row_set.next()) {
            return true;
        }
    }
    return false;
}

db::row_set db::get_schema(database const &db) {
    if (auto query_result = db.execute_query(
            "select type, name, tbl_name, rootpage, sql from (select * from sqlite_master union all select * from "
            "sqlite_temp_master) where type != 'meta' and name not like 'sqlite_%' order by tbl_name, type desc, "
            "name")) {
        return query_result.value();
    }
    return nullptr;
}

db::row_set db::get_table_schema(database const &db, std::string const &table_name) {
    if (auto query_result = db.execute_query("PRAGMA table_info('" + table_name + "')")) {
        return query_result.value();
    }
    return nullptr;
}

db::row_set db::get_index_schema(database const &db, std::string const &index_name) {
    if (auto query_result =
            db.execute_query("SELECT * FROM sqlite_master WHERE type = 'index' AND name = '" + index_name + "';")) {
        return query_result.value();
    }
    return nullptr;
}

bool db::column_exists(database const &db, std::string column_name, std::string table_name) {
    std::string lower_table_name = to_lower(std::move(table_name));
    std::string lower_column_name = to_lower(std::move(column_name));

    if (auto row_set = get_table_schema(db, lower_table_name)) {
        while (row_set.next()) {
            auto value = row_set.column_value("name");
            if (to_lower(value.get<db::text>()) == lower_column_name) {
                return true;
            }
        }
    }

    return false;
}

db::select_result db::select(db::database const &db, select_option const &option) {
    auto const sql =
        select_sql(option.table, option.fields, option.where_exprs, option.field_orders, option.limit_range);

    db::value_map_vector value_map_vector;

    if (auto query_result = db.execute_query(sql, option.arguments)) {
        auto row_set = query_result.value();
        while (row_set.next()) {
            value_map_vector.emplace_back(row_set.value_map());
        }
    } else {
        return select_result{std::move(query_result.error())};
    }

    return select_result{value_map_vector};
}

db::select_result db::select_last(database const &db, select_option option, value const &save_id,
                                  bool const include_removed) {
    std::vector<std::string> components;

    if (save_id) {
        components.emplace_back(expr(save_id_field, "<=", to_string(save_id)));
    }

    if (option.where_exprs.size() > 0) {
        components.emplace_back(option.where_exprs);
    }

    std::string sub_where = components.size() > 0 ? " WHERE " + joined(components, " AND ") : "";

    std::string where_exprs =
        "rowid IN (SELECT MAX(rowid) FROM " + option.table + sub_where + " GROUP BY " + db::object_id_field + ")";
    if (!include_removed) {
        static std::string const exc_removed_expr = action_field + " != '" + remove_action + "'";
        where_exprs = joined({where_exprs, exc_removed_expr}, " AND ");
    }
    option.where_exprs = where_exprs;

    return select(db, option);
}

db::select_result db::select_undo(database const &db, std::string const &table_name, integer::type const revert_save_id,
                                  integer::type const current_save_id) {
    if (current_save_id <= revert_save_id) {
        throw "revert_save_id greater than or equal to current_save_id";
    }

    std::vector<std::string> components;
    components.emplace_back(object_id_field + " IN (SELECT DISTINCT " + object_id_field + " FROM " + table_name +
                            " WHERE " + joined({expr(save_id_field, "<=", std::to_string(current_save_id)),
                                                expr(save_id_field, ">", std::to_string(revert_save_id))},
                                               " AND ") +
                            ")");
    components.emplace_back(expr(save_id_field, "<=", std::to_string(revert_save_id)));

    select_option option{.table = table_name,
                         .where_exprs = "rowid IN (SELECT MAX(rowid) FROM " + table_name + " WHERE " +
                                        joined(components, " AND ") + " GROUP BY " + object_id_field + ")",
                         .field_orders = {{object_id_field, order::ascending}}};

    auto result = select(db, option);
    if (!result) {
        return select_result{std::move(result.error())};
    }

    select_option empty_option{.table = table_name,
                               .fields = {object_id_field},
                               .where_exprs = joined({expr(save_id_field, "<=", std::to_string(current_save_id)),
                                                      expr(save_id_field, ">", std::to_string(revert_save_id)),
                                                      equal_field_expr(action_field)},
                                                     " AND "),
                               .arguments = {{action_field, db::value{insert_action}}},
                               .field_orders = {{object_id_field, order::ascending}}};
    auto empty_result = select(db, empty_option);
    if (!empty_result) {
        return select_result{std::move(empty_result.error())};
    }

    return select_result{connect(std::move(result.value()), std::move(empty_result.value()))};
}

db::select_result db::select_redo(database const &db, std::string const &table_name, integer::type const revert_save_id,
                                  integer::type const current_save_id) {
    if (revert_save_id <= current_save_id) {
        throw "current_save_id greater than or equal to revert_save_id";
    }

    std::vector<std::string> components;
    components.emplace_back(expr(save_id_field, ">", std::to_string(current_save_id)));

    db::select_option option{.table = table_name,
                             .where_exprs = joined(components, " AND "),
                             .field_orders = {{object_id_field, db::order::ascending}}};

    return select_last(db, std::move(option), db::value{revert_save_id}, true);
}

db::select_result db::select_revert(database const &db, std::string const &table_name,
                                    integer::type const revert_save_id, integer::type const current_save_id) {
    if (revert_save_id < current_save_id) {
        return select_undo(db, table_name, revert_save_id, current_save_id);
    } else if (current_save_id < revert_save_id) {
        return select_redo(db, table_name, revert_save_id, current_save_id);
    }

    return select_result{value_map_vector{}};
}

db::select_single_result db::select_single(database const &db, select_option option) {
    option.limit_range = {.location = 0, .length = 1};

    if (auto result = select(db, option)) {
        if (result.value().size() > 0) {
            return select_single_result{std::move(result.value().at(0))};
        }
    }

    return select_single_result{nullptr};
}

db::select_single_result db::select_db_info(database const &db) {
    return select_single(db, db::select_option{.table = db::info_table});
}

db::update_result db::purge(database &db, std::string const &table_name) {
    std::string where_exprs =
        "NOT rowid IN (SELECT MAX(rowid) FROM " + table_name + " GROUP BY " + db::object_id_field + ")";
    return db.execute_update(delete_sql(table_name, where_exprs));
}

db::update_result db::purge_relation(database &db, std::string const &table_name, std::string const &src_table_name) {
    std::string where_exprs = "NOT " + db::src_id_field + " IN (SELECT rowid FROM " + src_table_name + ")";
    return db.execute_update(delete_sql(table_name, where_exprs));
}

db::value db::max(database const &db, std::string const &table_name, std::string const &field) {
    if (auto query_result = db.execute_query("SELECT MAX(" + field + ") FROM " + table_name + ";")) {
        auto &row_set = query_result.value();
        if (row_set.next()) {
            return row_set.column_value(0);
        }
    }
    return nullptr;
}
<|endoftext|>


<commit_before>/*
 *  Copyright 2012 Utkin Dmitry
 *
 *  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.
 */

/*
 *  This file is part of the WSF Staff project.
 *  Please, visit http://code.google.com/p/staff for more information.
 */

#include <staff/utils/console.h>
#include <staff/utils/Log.h>
#include <staff/utils/SharedPtr.h>
#include <staff/utils/stringutils.h>
#include <staff/xml/Document.h>
#include <staff/common/Exception.h>
#include <staff/common/Runtime.h>
#include <staff/common/DataObject.h>
#include <staff/common/Operation.h>
#include <staff/component/SharedContext.h>
#include <staff/component/ServiceWrapper.h>
#include <staff/das/common/DataSource.h>
#include <staff/das/common/Executor.h>
#include "Services.h"

namespace staff
{
namespace das
{

  class ServicesRawExecutor: public IRawExecutor
  {
  public:
    ServicesRawExecutor(ServicesProvider* pProvider):
      m_pProvider(pProvider)
    {
    }

    virtual void Execute(const std::string& sSessionId,
                         const std::string& sExecute, const DataObject& rdoContext,
                         const DataType& /*rReturnType*/, DataObject& rdoResult)
    {
      STAFF_ASSERT(m_pProvider != NULL && m_pProvider->m_pServiceWrapper != NULL, "Not Initialized");

      std::string::size_type nPosBegin = 0;
      std::string::size_type nPosEnd = 0;

      nPosBegin = sExecute.find('(');
      nPosEnd = sExecute.find_last_of(')');

      STAFF_ASSERT(nPosBegin != std::string::npos && nPosEnd != std::string::npos &&
                   nPosEnd > nPosBegin, "Invalid execute statement.\nIt should be in form "
                   "\"<execute>ElementName([par0=val, par1=$var1, par2=$[DO_val], ...])</execute>\"");

      std::string sParam;
      std::string sValue;
      std::string sElement;
      std::string sArguments = sExecute.substr(nPosBegin + 1, nPosEnd - nPosBegin - 1);

      StringTrim(sArguments);

      // check for junk
      sElement = sExecute.substr(nPosEnd + 1);
      StringTrim(sElement);
      STAFF_ASSERT(sElement.empty(), "Junk at end of operation: [" + sElement + "]");

      // request element name
      sElement = sExecute.substr(0, nPosBegin);
      StringTrim(sElement);

      // operation name
      staff::Operation tOperation(sElement);
      staff::DataObject& rdoRequest = tOperation.Request();
      tOperation.SetResponse(rdoResult);
      tOperation.GetResponse().SetOwner(false);

      if (!sArguments.empty())
      {
        nPosBegin = 0;
        nPosEnd = 0;

        while (nPosEnd != std::string::npos)
        {
          nPosEnd = sArguments.find('=', nPosBegin);
          STAFF_ASSERT(nPosEnd != std::string::npos, "Unexpected end of parameter after: ["
                       + sArguments.substr(nPosBegin) + "]");

          // parameter's name
          sParam = sArguments.substr(nPosBegin, nPosEnd - nPosBegin);
          StringTrim(sParam);
          nPosBegin = nPosEnd + 1;

          // parameter's value
          nPosEnd = sArguments.find(',', nPosBegin);

          if (nPosEnd != std::string::npos)
          {
            sValue = sArguments.substr(nPosBegin, nPosEnd - nPosBegin);
          }
          else
          {
            sValue = sArguments.substr(nPosBegin);
          }
          StringTrim(sValue);

          if (!sValue.empty() && sValue[0] == '$')
          {
            // pass dataobject
            if (sValue[1] == '[' && sValue[sValue.size() - 1] == ']')
            {
              const std::string& sChildName = sValue.substr(2, sValue.size() - 3);
              DataObject doChild;
              GetChild(rdoContext, sChildName, doChild);
              doChild.SetLocalName(sParam);
              rdoRequest.AppendChild(doChild);
            }
          }
          else
          {
            rdoRequest.CreateChild(sParam, sValue);
          }

          nPosBegin = nPosEnd + 1;
        }
      }

#ifdef _DEBUG
      LogDebug2() << "Invoking service [" << m_pProvider->m_pServiceWrapper->GetName() << "]: \n"
                  << ColorTextBlue << rdoRequest.ToString() << ColorDefault;
#endif
      m_pProvider->m_pServiceWrapper->Invoke(tOperation, sSessionId, "");

      if (rdoResult != tOperation.GetResponse())
      {
        // this may occur in case of using variables as return value
        std::string sResponseName;
        rdoResult.GetLocalName(sResponseName);
        rdoResult.ReplaceNode(tOperation.GetResponse());
        rdoResult.SetLocalName(sResponseName);
      }

#ifdef _DEBUG
      LogDebug2() << "Service [" << m_pProvider->m_pServiceWrapper->GetName() << "] response: \n"
                  << ColorTextBlue << rdoResult.ToString() << ColorDefault;
#endif

      /* example of response:
        <Response>
          <RowItem>
            <Field_1>data 1</Field_1><Field_2>2</Field_2>...
          </RowItem>
          ...
        </Response>
      */
    }

    void GetChild(const DataObject& rdoContext, const std::string& sPath, DataObject& rdoResult)
    {
      rdoResult = rdoContext;

      if (!sPath.empty())
      {
        std::string sName;
        std::string::size_type nSize = sPath.size();
        STAFF_ASSERT(nSize > 1, "invalid node name: [" + sPath + "]");

        std::string::size_type nBegin = 0;
        std::string::size_type nEnd = 0;
        do
        {
          nEnd = sPath.find('.', nBegin);
          if (nEnd == std::string::npos)
          {
            sName = sPath.substr(nBegin);
          }
          else
          {
            sName = sPath.substr(nBegin, nEnd - nBegin);
          }

          if (sName.empty()) // parent node
          {
            rdoResult = rdoResult.Parent();
            STAFF_ASSERT(!rdoResult.IsNull(), "parent of root element reached while GetChild[" + sPath + "]");
          }
          else
          {
            rdoResult = rdoResult.GetChildByLocalName(sName);
          }

          nBegin = nEnd + 1;
        }
        while(nEnd != std::string::npos);
      }
    }

  private:
    ServicesProvider* m_pProvider;
  };

  ServicesProvider::ServicesProvider():
    m_pServiceWrapper(NULL)
  {
  }

  ServicesProvider::~ServicesProvider()
  {
    Deinit();
  }

  void ServicesProvider::Init(const xml::Element& rConfig)
  {
    // initialize connection
    const xml::Element& rConnection = rConfig.GetChildElementByName("connection");

    const std::string& sService = rConnection.GetChildElementByName("service").GetValue();
    m_pServiceWrapper = SharedContext::Inst().GetService(sService);
    STAFF_ASSERT(m_pServiceWrapper, "Can't find service: [" + sService + "]");
  }

  void ServicesProvider::Deinit()
  {
    if (m_pServiceWrapper)
    {
      m_pServiceWrapper = NULL;
    }
  }

  const std::string& ServicesProvider::GetName() const
  {
    static const std::string sName = "staff.das.Services";
    return sName;
  }

  const std::string& ServicesProvider::GetDescr() const
  {
    static const std::string sDescr = "Services data access provider";
    return sDescr;
  }

  PExecutor ServicesProvider::GetExecutor()
  {
    return new ServicesRawExecutor(this);
  }

}
}

<commit_msg>DAS: fixed crash when passing DataObject var over several services<commit_after>/*
 *  Copyright 2012 Utkin Dmitry
 *
 *  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.
 */

/*
 *  This file is part of the WSF Staff project.
 *  Please, visit http://code.google.com/p/staff for more information.
 */

#include <staff/utils/console.h>
#include <staff/utils/Log.h>
#include <staff/utils/SharedPtr.h>
#include <staff/utils/stringutils.h>
#include <staff/xml/Document.h>
#include <staff/common/Exception.h>
#include <staff/common/Runtime.h>
#include <staff/common/DataObject.h>
#include <staff/common/Operation.h>
#include <staff/component/SharedContext.h>
#include <staff/component/ServiceWrapper.h>
#include <staff/das/common/DataSource.h>
#include <staff/das/common/Executor.h>
#include "Services.h"

namespace staff
{
namespace das
{

  class ServicesRawExecutor: public IRawExecutor
  {
  public:
    ServicesRawExecutor(ServicesProvider* pProvider):
      m_pProvider(pProvider)
    {
    }

    virtual void Execute(const std::string& sSessionId,
                         const std::string& sExecute, const DataObject& rdoContext,
                         const DataType& /*rReturnType*/, DataObject& rdoResult)
    {
      STAFF_ASSERT(m_pProvider != NULL && m_pProvider->m_pServiceWrapper != NULL, "Not Initialized");

      std::string::size_type nPosBegin = 0;
      std::string::size_type nPosEnd = 0;

      nPosBegin = sExecute.find('(');
      nPosEnd = sExecute.find_last_of(')');

      STAFF_ASSERT(nPosBegin != std::string::npos && nPosEnd != std::string::npos &&
                   nPosEnd > nPosBegin, "Invalid execute statement.\nIt should be in form "
                   "\"<execute>ElementName([par0=val, par1=$var1, par2=$[DO_val], ...])</execute>\"");

      std::string sParam;
      std::string sValue;
      std::string sElement;
      std::string sArguments = sExecute.substr(nPosBegin + 1, nPosEnd - nPosBegin - 1);

      StringTrim(sArguments);

      // check for junk
      sElement = sExecute.substr(nPosEnd + 1);
      StringTrim(sElement);
      STAFF_ASSERT(sElement.empty(), "Junk at end of operation: [" + sElement + "]");

      // request element name
      sElement = sExecute.substr(0, nPosBegin);
      StringTrim(sElement);

      // operation name
      staff::Operation tOperation(sElement);
      staff::DataObject& rdoRequest = tOperation.Request();
      tOperation.SetResponse(rdoResult);
      tOperation.GetResponse().SetOwner(false);

      if (!sArguments.empty())
      {
        nPosBegin = 0;
        nPosEnd = 0;

        while (nPosEnd != std::string::npos)
        {
          nPosEnd = sArguments.find('=', nPosBegin);
          STAFF_ASSERT(nPosEnd != std::string::npos, "Unexpected end of parameter after: ["
                       + sArguments.substr(nPosBegin) + "]");

          // parameter's name
          sParam = sArguments.substr(nPosBegin, nPosEnd - nPosBegin);
          StringTrim(sParam);
          nPosBegin = nPosEnd + 1;

          // parameter's value
          nPosEnd = sArguments.find(',', nPosBegin);

          if (nPosEnd != std::string::npos)
          {
            sValue = sArguments.substr(nPosBegin, nPosEnd - nPosBegin);
          }
          else
          {
            sValue = sArguments.substr(nPosBegin);
          }
          StringTrim(sValue);

          if (!sValue.empty() && sValue[0] == '$')
          {
            // pass dataobject
            if (sValue[1] == '[' && sValue[sValue.size() - 1] == ']')
            {
              const std::string& sChildName = sValue.substr(2, sValue.size() - 3);
              DataObject doChild;
              GetChild(rdoContext, sChildName, doChild);
              doChild.SetLocalName(sParam);
              rdoRequest.AppendChild(doChild);
            }
          }
          else
          {
            rdoRequest.CreateChild(sParam, sValue);
          }

          nPosBegin = nPosEnd + 1;
        }
      }

#ifdef _DEBUG
      LogDebug2() << "Invoking service [" << m_pProvider->m_pServiceWrapper->GetName() << "]: \n"
                  << ColorTextBlue << rdoRequest.ToString() << ColorDefault;
#endif
      m_pProvider->m_pServiceWrapper->Invoke(tOperation, sSessionId, "");

      if (rdoResult != tOperation.GetResponse())
      {
        // this may occur in case of using variables as return value
        std::string sResponseName;
        rdoResult.GetLocalName(sResponseName);
        rdoResult.ReplaceNode(tOperation.GetResponse());
        rdoResult.SetLocalName(sResponseName);
      }

#ifdef _DEBUG
      LogDebug2() << "Service [" << m_pProvider->m_pServiceWrapper->GetName() << "] response: \n"
                  << ColorTextBlue << rdoResult.ToString() << ColorDefault;
#endif

      /* example of response:
        <Response>
          <RowItem>
            <Field_1>data 1</Field_1><Field_2>2</Field_2>...
          </RowItem>
          ...
        </Response>
      */
    }

    void GetChild(const DataObject& rdoContext, const std::string& sPath, DataObject& rdoResult)
    {
      rdoResult = rdoContext.Copy();

      if (!sPath.empty())
      {
        std::string sName;
        std::string::size_type nSize = sPath.size();
        STAFF_ASSERT(nSize > 1, "invalid node name: [" + sPath + "]");

        std::string::size_type nBegin = 0;
        std::string::size_type nEnd = 0;
        do
        {
          nEnd = sPath.find('.', nBegin);
          if (nEnd == std::string::npos)
          {
            sName = sPath.substr(nBegin);
          }
          else
          {
            sName = sPath.substr(nBegin, nEnd - nBegin);
          }

          if (sName.empty()) // parent node
          {
            rdoResult = rdoResult.Parent();
            STAFF_ASSERT(!rdoResult.IsNull(), "parent of root element reached while GetChild[" + sPath + "]");
          }
          else
          {
            rdoResult = rdoResult.GetChildByLocalName(sName);
          }

          nBegin = nEnd + 1;
        }
        while(nEnd != std::string::npos);
      }
    }

  private:
    ServicesProvider* m_pProvider;
  };

  ServicesProvider::ServicesProvider():
    m_pServiceWrapper(NULL)
  {
  }

  ServicesProvider::~ServicesProvider()
  {
    Deinit();
  }

  void ServicesProvider::Init(const xml::Element& rConfig)
  {
    // initialize connection
    const xml::Element& rConnection = rConfig.GetChildElementByName("connection");

    const std::string& sService = rConnection.GetChildElementByName("service").GetValue();
    m_pServiceWrapper = SharedContext::Inst().GetService(sService);
    STAFF_ASSERT(m_pServiceWrapper, "Can't find service: [" + sService + "]");
  }

  void ServicesProvider::Deinit()
  {
    if (m_pServiceWrapper)
    {
      m_pServiceWrapper = NULL;
    }
  }

  const std::string& ServicesProvider::GetName() const
  {
    static const std::string sName = "staff.das.Services";
    return sName;
  }

  const std::string& ServicesProvider::GetDescr() const
  {
    static const std::string sDescr = "Services data access provider";
    return sDescr;
  }

  PExecutor ServicesProvider::GetExecutor()
  {
    return new ServicesRawExecutor(this);
  }

}
}

<|endoftext|>


<commit_before>/*
** Anitomy
** Copyright (C) 2014-2015, Eren Okka
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <algorithm>

#include "element.h"

namespace anitomy {

bool Elements::empty() const {
  return elements_.empty();
}

size_t Elements::size() const {
  return elements_.size();
}

////////////////////////////////////////////////////////////////////////////////

element_iterator_t Elements::begin() {
  return elements_.begin();
}

element_const_iterator_t Elements::begin() const {
  return elements_.begin();
}

element_const_iterator_t Elements::cbegin() const {
  return elements_.begin();
}

element_iterator_t Elements::end() {
  return elements_.end();
}

element_const_iterator_t Elements::end() const {
  return elements_.end();
}

element_const_iterator_t Elements::cend() const {
  return elements_.end();
}

////////////////////////////////////////////////////////////////////////////////

element_pair_t& Elements::at(size_t position) {
  return elements_.at(position);
}

const element_pair_t& Elements::at(size_t position) const {
  return elements_.at(position);
}

element_pair_t& Elements::operator[](size_t position) {
  return elements_[position];
}

const element_pair_t& Elements::operator[](size_t position) const {
  return elements_[position];
}

////////////////////////////////////////////////////////////////////////////////

string_t& Elements::get(ElementCategory category) {
  auto element = find(category);

  if (element == elements_.end())
    element = elements_.insert(elements_.end(),
                               std::make_pair(category, string_t()));

  return element->second;
}

std::vector<string_t> Elements::get_all(ElementCategory category) const {
  std::vector<string_t> elements;

  for (const auto& element : elements_)
    if (element.first == category)
      elements.push_back(element.second);

  return elements;
}

////////////////////////////////////////////////////////////////////////////////

void Elements::clear() {
  elements_.clear();
}

void Elements::insert(ElementCategory category, const string_t& value) {
  if (!value.empty())
    elements_.push_back(std::make_pair(category, value));
}

void Elements::erase(ElementCategory category) {
  elements_.erase(std::remove_if(elements_.begin(), elements_.end(),
      [&](const element_pair_t& element) {
        return element.first == category;
      }));
}

element_iterator_t Elements::erase(element_iterator_t iterator) {
  return elements_.erase(iterator);
}

////////////////////////////////////////////////////////////////////////////////

size_t Elements::count(ElementCategory category) const {
  return std::count_if(elements_.begin(), elements_.end(),
      [&](const element_pair_t& element) {
        return element.first == category;
      });
}

bool Elements::empty(ElementCategory category) const {
  return find(category) == elements_.end();
}

element_iterator_t Elements::find(ElementCategory category) {
  return std::find_if(elements_.begin(), elements_.end(),
      [&](const element_pair_t& element) {
        return element.first == category;
      });
}

element_const_iterator_t Elements::find(ElementCategory category) const {
  return std::find_if(elements_.cbegin(), elements_.cend(),
      [&](const element_pair_t& element) {
        return element.first == category;
      });
}

}  // namespace anitomy<commit_msg>Fix crash when trying to erase inexistent element<commit_after>/*
** Anitomy
** Copyright (C) 2014-2015, Eren Okka
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <algorithm>

#include "element.h"

namespace anitomy {

bool Elements::empty() const {
  return elements_.empty();
}

size_t Elements::size() const {
  return elements_.size();
}

////////////////////////////////////////////////////////////////////////////////

element_iterator_t Elements::begin() {
  return elements_.begin();
}

element_const_iterator_t Elements::begin() const {
  return elements_.begin();
}

element_const_iterator_t Elements::cbegin() const {
  return elements_.begin();
}

element_iterator_t Elements::end() {
  return elements_.end();
}

element_const_iterator_t Elements::end() const {
  return elements_.end();
}

element_const_iterator_t Elements::cend() const {
  return elements_.end();
}

////////////////////////////////////////////////////////////////////////////////

element_pair_t& Elements::at(size_t position) {
  return elements_.at(position);
}

const element_pair_t& Elements::at(size_t position) const {
  return elements_.at(position);
}

element_pair_t& Elements::operator[](size_t position) {
  return elements_[position];
}

const element_pair_t& Elements::operator[](size_t position) const {
  return elements_[position];
}

////////////////////////////////////////////////////////////////////////////////

string_t& Elements::get(ElementCategory category) {
  auto element = find(category);

  if (element == elements_.end())
    element = elements_.insert(elements_.end(),
                               std::make_pair(category, string_t()));

  return element->second;
}

std::vector<string_t> Elements::get_all(ElementCategory category) const {
  std::vector<string_t> elements;

  for (const auto& element : elements_)
    if (element.first == category)
      elements.push_back(element.second);

  return elements;
}

////////////////////////////////////////////////////////////////////////////////

void Elements::clear() {
  elements_.clear();
}

void Elements::insert(ElementCategory category, const string_t& value) {
  if (!value.empty())
    elements_.push_back(std::make_pair(category, value));
}

void Elements::erase(ElementCategory category) {
  auto iterator = std::remove_if(elements_.begin(), elements_.end(),
      [&](const element_pair_t& element) {
        return element.first == category;
      });
  elements_.erase(iterator, elements_.end());
}

element_iterator_t Elements::erase(element_iterator_t iterator) {
  return elements_.erase(iterator);
}

////////////////////////////////////////////////////////////////////////////////

size_t Elements::count(ElementCategory category) const {
  return std::count_if(elements_.begin(), elements_.end(),
      [&](const element_pair_t& element) {
        return element.first == category;
      });
}

bool Elements::empty(ElementCategory category) const {
  return find(category) == elements_.end();
}

element_iterator_t Elements::find(ElementCategory category) {
  return std::find_if(elements_.begin(), elements_.end(),
      [&](const element_pair_t& element) {
        return element.first == category;
      });
}

element_const_iterator_t Elements::find(ElementCategory category) const {
  return std::find_if(elements_.cbegin(), elements_.cend(),
      [&](const element_pair_t& element) {
        return element.first == category;
      });
}

}  // namespace anitomy<|endoftext|>


<commit_before>
// .\Release\x64\benchmarks.exe --benchmark_repetitions=10 --benchmark_min_time=2 --benchmark_filter=Newhall  // NOLINT(whitespace/line_length)
// Benchmarking on 1 X 3310 MHz CPU
// 2015/05/24-13:16:32
// Benchmark                    Time(ns)    CPU(ns) Iterations
// -----------------------------------------------------------
// BM_NewhallApproximation/4         589        562    2000000
// BM_NewhallApproximation/8         657        624    2000000
// BM_NewhallApproximation/16        754        741    2000000

#include <random>
#include <vector>

#include "benchmark/benchmark.h"
#include "geometry/named_quantities.hpp"
#include "numerics/newhall.hpp"
#include "quantities/named_quantities.hpp"
#include "quantities/si.hpp"

namespace principia {

using geometry::Instant;
using quantities::Variation;
using quantities::si::Second;

namespace numerics {

void BM_NewhallApproximation(benchmark::State& state) {
  int const degree = state.range_x();
  std::mt19937_64 random(42);
  std::vector<double> p;
  std::vector<Variation<double>> v;
  Instant const t0;
  Instant const t_min = t0 + static_cast<double>(random()) * Second;
  Instant const t_max = t_min + static_cast<double>(random()) * Second;

  while (state.KeepRunning()) {
    state.PauseTiming();
    p.clear();
    v.clear();
    for (int i = 0; i <= 8; ++i) {
      p.push_back(static_cast<double>(static_cast<double>(random())));
      v.push_back(static_cast<double>(static_cast<double>(random())) / Second);
    }
    state.ResumeTiming();
    auto const series =
        newhall::ApproximationInЧебышёвBasis<double>(
            degree, p, v, t_min, t_max);
  }
}

BENCHMARK(BM_NewhallApproximation)->Arg(4)->Arg(8)->Arg(16);

}  // namespace numerics
}  // namespace principia
<commit_msg>The benchmark.<commit_after>
// .\Release\x64\benchmarks.exe --benchmark_repetitions=10 --benchmark_min_time=2 --benchmark_filter=Newhall  // NOLINT(whitespace/line_length)
// Benchmarking on 1 X 3310 MHz CPU
// 2015/05/24-13:16:32
// Benchmark                    Time(ns)    CPU(ns) Iterations
// -----------------------------------------------------------
// BM_NewhallApproximation/4         589        562    2000000
// BM_NewhallApproximation/8         657        624    2000000
// BM_NewhallApproximation/16        754        741    2000000

#include <random>
#include <vector>

#include "benchmark/benchmark.h"
#include "geometry/named_quantities.hpp"
#include "numerics/newhall.hpp"
#include "quantities/named_quantities.hpp"
#include "quantities/si.hpp"

namespace principia {

using geometry::Instant;
using quantities::Variation;
using quantities::si::Second;

namespace numerics {

void BM_NewhallApproximation(benchmark::State& state) {
  int const degree = state.range_x();
  std::mt19937_64 random(42);
  std::vector<double> p;
  std::vector<Variation<double>> v;
  Instant const t0;
  Instant const t_min = t0 + static_cast<double>(random()) * Second;
  Instant const t_max = t_min + static_cast<double>(random()) * Second;

  while (state.KeepRunning()) {
    state.PauseTiming();
    p.clear();
    v.clear();
    for (int i = 0; i <= 8; ++i) {
      p.push_back(static_cast<double>(static_cast<double>(random())));
      v.push_back(static_cast<double>(static_cast<double>(random())) / Second);
    }
    state.ResumeTiming();
    auto const series =
        NewhallApproximationInЧебышёвBasis<double>(degree, p, v, t_min, t_max);
  }
}

BENCHMARK(BM_NewhallApproximation)->Arg(4)->Arg(8)->Arg(16);

}  // namespace numerics
}  // namespace principia
<|endoftext|>