<commit_before>/**
 ** \file object/object.cc
 ** \brief Implementation of object::Object.
 */

#include <algorithm>

#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/lambda/lambda.hpp>

#include <libport/containers.hh>
#include <libport/foreach.hh>

#include "object/object.hh"
#include "object/atom.hh"
#include "object/global-class.hh"
#include "object/hash-slots.hh"
#include "object/urbi-exception.hh"

#include "runner/runner.hh"

namespace object
{

  /*---------.
  | Callers. |
  `---------*/

  rObject urbi_call(runner::Runner& r,
		    rObject self,
		    libport::Symbol msg,
		    objects_type args)
  {
    assertion(self);
    rObject message = self->slot_get(msg);
    if (!message)
      throw LookupError(msg);
    args.insert(args.begin(), self);
    rObject res = r.apply(message, msg, args);
    assertion(res);
    return res;
  }

  rObject urbi_call(runner::Runner& r,
		    rObject self,
		    libport::Symbol msg)
  {
    objects_type args; // Call with no args.
    return urbi_call(r, self, msg, args);
  }

  /*-------.
  | kind.  |
  `-------*/

  const char*
  Object::string_of (Object::kind_type k)
  {
    switch (k)
    {
#define CASE(What, Name) case kind_ ## What: return #Name; break;
      APPLY_ON_ALL_PRIMITIVES(CASE);
#undef CASE
    }
    pabort("unreachable");
  }

  /*---------.
  | Scopes.  |
  `---------*/

  // Typedef for lookups that return rObject
  typedef boost::optional<rObject> lookup_result;
  typedef boost::function1<lookup_result, rObject> lookup_action;

  namespace
  {
    using std::make_pair;
    using boost::bind;
    using boost::optional;

    static lookup_result
    targetLookup(rObject obj,
		 const object::Slots::key_type& slotName)
    {
      // First, check if the object has the slot locally. We do not
      // handle 'self' here, since we first want to see whether it has
      // been captured in the context.
      if (slotName != SYMBOL(self) && obj->own_slot_get(slotName, 0))
	// Return a nonempty optional containing an empty rObject, to
	// indicate to target that the lookup is successful, and the
	// target is the initial object.
	return optional<rObject>(rObject());
      // If this is a method outer scope, perform special lookup in
      // self and context.
      if (rObject self = obj->own_slot_get(SYMBOL(self), 0))
      {
	// FIXME: The 'code' slot is *always* set by the scoping
	// system, yet the user can still delete it. What kind of
	// error should we raise when this problem occurs? For now,
	// just ignore it:
	if (rObject code = obj->own_slot_get(SYMBOL(code), 0))
	  // Likewise.
	  if (rObject captured = code->own_slot_get(SYMBOL(capturedVars), 0))
	  {
	    if (captured == nil_class)
	      return target(code->own_slot_get(SYMBOL(context)), slotName);
	    else
	      foreach (const rObject& var, captured->value<object::List>())
		if (var->value<object::String>() == slotName)
		  return target(code->own_slot_get(SYMBOL(context)), slotName);
	  }
	// If we were looking for 'self' and it wasn't captured in the
	// context, we found it here.
	if (slotName == SYMBOL(self))
	  return optional<rObject>(rObject());
	// Check whether self has the slot. We do not use the
	// 'fallback' method here: only calls with explicit target are
	// subject to fallback.
	if (self->slot_locate(slotName, false))
	  return self;
      }
      return optional<rObject>();
    }
  }

  rObject
  target(rObject where, const libport::Symbol& name)
  {
    boost::function1<boost::optional<rObject>, rObject> lookup =
      boost::bind(targetLookup, _1, name);
    boost::optional<rObject> res = where->lookup(lookup);
    if (!res)
      throw object::LookupError(name);
    if (!res.get())
      return where;
    return res.get();
  }

  rObject
  Object::make_scope(const rObject& parent)
  {
    rObject res = object::Object::fresh();
    res->locals_set(true);
    res->proto_add(parent);
    return res;
  }

  namespace
  {
    // helper for make_method_scope and make_do_scope
    static rObject
    make_outer_scope(const rObject& parent, const rObject& self)
    {
      rObject res = Object::make_scope(parent);
      res->slot_copy(SYMBOL(getSlot), scope_class);
      res->slot_copy(SYMBOL(locateSlot), scope_class);
      res->slot_copy(SYMBOL(removeSlot), scope_class);
      res->slot_copy(SYMBOL(updateSlot), scope_class);
      res->slot_set(SYMBOL(self), self);
      // We really need to copy 'locals' in every scope, or else
      // Scope's methods will get completely fubared: 'locals' will be
      // found in 'self' and will thus not be the local scope!
      res->slot_copy(SYMBOL(locals), scope_class);
      return res;
    }
  }

  rObject
  Object::make_method_scope(const rObject& self)
  {
    rObject res = make_outer_scope(global_class, self);
    res->slot_copy(SYMBOL(setSlot), scope_class);
    return res;
  }

  rObject
  Object::make_do_scope(const rObject& parent, const rObject& self)
  {
    rObject res = make_outer_scope (parent ? parent : global_class, self);
    res->slot_set(SYMBOL(setSlot), scope_class->slot_get(SYMBOL(doSetSlot)));
    return res;
  }

  /*--------.
  | Slots.  |
  `--------*/

  rObject
  Object::urbi_protos_get ()
  {
    if (!protos_cache_)
    {
      rList protos = List::fresh (*protos_);
      protos_cache_ = protos;
      delete protos_;
      protos_ = &protos->value_get ();
    }
    return protos_cache_;
  }

  void
  Object::protos_set (rObject l)
  {
    if (!protos_cache_)
      delete protos_;
    protos_cache_ = l;
    protos_ = &l.unsafe_cast<object::List>()->value_get ();
  }

  template <typename R>
  boost::optional<R>
  Object::lookup(boost::function1<boost::optional<R>, rObject> action,
		 objects_set_type& marks) const
  {
    if (!libport::mhas(marks, this))
    {
      marks.insert(this);
      assertion(self());
      boost::optional<R> res = action(self());
      if (res)
	return res;
      else
	foreach (const rObject& proto, protos_get())
	  if (boost::optional<R> res = proto->lookup(action, marks))
	    return res;
    }
    return boost::optional<R>();
  }

  template <typename R>
  boost::optional<R>
  Object::lookup(boost::function1<boost::optional<R>, rObject> action) const
  {
    objects_set_type marks;
    return lookup(action, marks);
  }

  namespace
  {
    class SlotLookup
    {
    public:
      lookup_result
      slot_lookup(rObject obj, const Slots::key_type& k, bool value)
      {
	assertion(obj);
	if (rObject x = obj->own_slot_get(k, 0))
	  return value ? x : obj;
	if (!fallback)
          if (rObject f = obj->own_slot_get(SYMBOL(fallback), 0))
            fallback = value ? f : obj;
	return boost::optional<rObject>();
      }
      rObject fallback;
    };
  }

  rObject Object::slot_locate(const Slots::key_type& k,
                              bool fallback, bool value) const
  {
    SlotLookup looker;
    lookup_action action = boost::bind(&SlotLookup::slot_lookup, &looker, _1, k, value);
    boost::optional<rObject> res = lookup(action);
    if (!res && fallback && looker.fallback)
      res = looker.fallback;
    return res ? res.get() : 0;
  }

  rObject
  Object::safe_slot_locate(const Slots::key_type& k, bool value) const
  {
    rObject r = slot_locate(k, true, value);
    if (!r)
      throw LookupError(k);
    return iassertion(r);
  }

  rObject
  Object::slot_get (const Slots::key_type& k, boost::optional<rObject> def) const
  {
    rObject value;
    if (def)
      value = slot_locate(k, true, true);
    else
      value = safe_slot_locate(k, true);
    if (value)
      return value;
    else
      return def.get();
  }

  Object&
  Object::slot_set (const Slots::key_type& k, rObject o)
  {
    if (!slots_.set(k, o))
      throw RedefinitionError(k);
    return *this;
  }

  Object&
  Object::slot_copy (const Slots::key_type& name, rObject from)
  {
    this->slot_set(name, from->slot_get(name));
    return *this;
  }

  void
  Object::slot_update (runner::Runner& r,
		       const Slots::key_type& k,
		       rObject o,
		       bool hook)
  {
    // The target of updateSlot
    rObject context = self();
    // The owner of the updated slot
    rObject owner = context->safe_slot_locate(k);

    // We have to determine where the new value must be stored,
    // depending on whether the slot owner and the context are scopes.
    rObject effective_target;

    // If both are scopes, update the original scope.
    if (context->locals_ && owner->locals_get())
      effective_target = owner;
    else if (context->locals_ && !owner->locals_get())
    {
      // Local->class: copyonwrite to "self" after evaluating it.
      rObject self = urbi_call(r, context, SYMBOL(self));
      assertion(self);
      effective_target = self;
    }
    else // Class->class: copy on write.
      effective_target = context;
    // Check hook, only if we are not create-on-writing.
    /* If the current value in the slot to be written in has a slot named
     * 'updateHook', call it, passing the object owning the slot, the slot name
     * and the target.
     */
    if (hook && effective_target == owner)
    // FIXME: We probably want helper to access properties
    if (rObject properties = effective_target->slot_get(SYMBOL(properties), rObject()))
    if (rObject slotProperties = properties->slot_get(k, rObject()))
    if (rObject hook = slotProperties->slot_get(SYMBOL(updateHook), rObject()))
    {
      objects_type args;
      args.push_back(effective_target);
      args.push_back(String::fresh(k));
      args.push_back(o);
      rObject ret = r.apply(hook, SYMBOL(updateHook), args);
      // If the updateHook returned void, do nothing. Otherwise let
      // the slot be overwritten.
      if (ret == object::void_class)
	return;
    }
    // If return-value of hook is not void, write it to slot.
    effective_target->own_slot_update(k, o);
  };

  void
  Object::own_slot_update (const Slots::key_type& k, rObject v)
  {
    slots_.update(k, v);
  }

  rObject
  Object::own_slot_get (const Slots::key_type& k, rObject def)
  {
    rObject res = slots_.get(k);
    return res ? res : def;
  }

  void
  Object::all_slots_copy(const rObject& other)
  {
    foreach (Slots::slot_type slot, other->slots_get())
      if (!own_slot_get(slot.first, 0))
        slot_set(slot.first, slot.second);
  }

  /*-----------.
  | Printing.  |
  `-----------*/

  std::ostream&
  Object::special_slots_dump (std::ostream& o, runner::Runner&) const
  {
    return o;
  }

  bool
  Object::operator< (const Object& rhs) const
  {
    return this < &rhs;
  }

  std::ostream&
  Object::id_dump(std::ostream& o, runner::Runner& r) const
  {
    rObject data = urbi_call(r, self(), SYMBOL(id));
    std::string s = data->value<String>().name_get();
    return o << s;
  }

  std::ostream&
  Object::protos_dump(std::ostream& o, runner::Runner& runner) const
  {
    if (!protos_->empty())
    {
      o << "protos = ";
      bool tail = false;
      foreach (rObject p, *protos_)
      {
	if (tail++)
	  o << ", ";
	p->id_dump (o, runner);
      }
      o << libport::iendl;
    }
    return o;
  }

  std::ostream&
  Object::dump (std::ostream& o, runner::Runner& runner) const
  {
    id_dump(o, runner);
    /// Use xalloc/iword to store our current depth within the stream object.
    static const long idx = o.xalloc();
    long& current_depth = o.iword(idx);

    // Stop recursion at depth_max.
    enum { depth_max = 3 };
    if (current_depth > depth_max)
      return o << " <...>";
    ++current_depth;
    o << " {" << libport::incendl;
    protos_dump(o, runner);
    special_slots_dump (o, runner);
    foreach(Slots::slot_type s, slots_.container())
    {
      o << s.first << " = ";
      s.second->dump(o, runner) << libport::iendl;
    }

    o << libport::decindent << '}';
    //We can not reuse current_depth variable above according to spec.
    o.iword(idx)--;
    return o;
  }

  std::ostream&
  Object::print(std::ostream& o, runner::Runner& runner) const
  {
    try
    {
      rObject s = urbi_call(runner, self(), SYMBOL(asString));
      o << s->value<String>().name_get();
      return o;
    }
    // Check if asString was found, especially for bootstrap: asString
    // is implemented in urbi/urbi.u, but print is called to show
    // result in the toplevel before its definition.
    catch (LookupError&)
    {
      // If no asString method is supplied, print the unique id
      return o << std::hex << this;
    }
  }

  bool
  is_a(const rObject& c, const rObject& p)
  {
    return for_all_protos(c, boost::lambda::_1 == p);
  }

  bool
  is_true(const rObject& o)
  {
    // FIXME: should nil be true? It should probably be false.
    if (o == nil_class)
      return true;
    if (o->type_is<object::Float>())
      return o.unsafe_cast<object::Float>()->value_get();
    return false;
  }

} // namespace object
<commit_msg>Fix mindo.<commit_after>/**
 ** \file object/object.cc
 ** \brief Implementation of object::Object.
 */

#include <algorithm>

#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/lambda/lambda.hpp>

#include <libport/containers.hh>
#include <libport/foreach.hh>

#include "object/object.hh"
#include "object/atom.hh"
#include "object/global-class.hh"
#include "object/hash-slots.hh"
#include "object/urbi-exception.hh"

#include "runner/runner.hh"

namespace object
{

  /*---------.
  | Callers. |
  `---------*/

  rObject urbi_call(runner::Runner& r,
		    rObject self,
		    libport::Symbol msg,
		    objects_type args)
  {
    assertion(self);
    rObject message = self->slot_get(msg);
    if (!message)
      throw LookupError(msg);
    args.insert(args.begin(), self);
    rObject res = r.apply(message, msg, args);
    assertion(res);
    return res;
  }

  rObject urbi_call(runner::Runner& r,
		    rObject self,
		    libport::Symbol msg)
  {
    objects_type args; // Call with no args.
    return urbi_call(r, self, msg, args);
  }

  /*-------.
  | kind.  |
  `-------*/

  const char*
  Object::string_of (Object::kind_type k)
  {
    switch (k)
    {
#define CASE(What, Name) case kind_ ## What: return #Name; break;
      APPLY_ON_ALL_PRIMITIVES(CASE);
#undef CASE
    }
    pabort("unreachable");
  }

  /*---------.
  | Scopes.  |
  `---------*/

  // Typedef for lookups that return rObject
  typedef boost::optional<rObject> lookup_result;
  typedef boost::function1<lookup_result, rObject> lookup_action;

  namespace
  {
    using std::make_pair;
    using boost::bind;
    using boost::optional;

    static lookup_result
    targetLookup(rObject obj,
		 const object::Slots::key_type& slotName)
    {
      // First, check if the object has the slot locally. We do not
      // handle 'self' here, since we first want to see whether it has
      // been captured in the context.
      if (slotName != SYMBOL(self) && obj->own_slot_get(slotName, 0))
	// Return a nonempty optional containing an empty rObject, to
	// indicate to target that the lookup is successful, and the
	// target is the initial object.
	return optional<rObject>(rObject());
      // If this is a method outer scope, perform special lookup in
      // self and context.
      if (rObject self = obj->own_slot_get(SYMBOL(self), 0))
      {
	// FIXME: The 'code' slot is *always* set by the scoping
	// system, yet the user can still delete it. What kind of
	// error should we raise when this problem occurs? For now,
	// just ignore it:
	if (rObject code = obj->own_slot_get(SYMBOL(code), 0))
	  // Likewise.
	  if (rObject captured = code->own_slot_get(SYMBOL(capturedVars), 0))
	  {
	    if (captured == nil_class)
	      return target(code->own_slot_get(SYMBOL(context)), slotName);
	    else
	      foreach (const rObject& var, captured->value<object::List>())
		if (var->value<object::String>() == slotName)
		  return target(code->own_slot_get(SYMBOL(context)), slotName);
	  }
	// If we were looking for 'self' and it wasn't captured in the
	// context, we found it here.
	if (slotName == SYMBOL(self))
	  return optional<rObject>(rObject());
	// Check whether self has the slot. We do not use the
	// 'fallback' method here: only calls with explicit target are
	// subject to fallback.
	if (self->slot_locate(slotName, false))
	  return self;
      }
      return optional<rObject>();
    }
  }

  rObject
  target(rObject where, const libport::Symbol& name)
  {
    boost::function1<boost::optional<rObject>, rObject> lookup =
      boost::bind(targetLookup, _1, name);
    boost::optional<rObject> res = where->lookup(lookup);
    if (!res)
      throw object::LookupError(name);
    if (!res.get())
      return where;
    return res.get();
  }

  rObject
  Object::make_scope(const rObject& parent)
  {
    rObject res = object::Object::fresh();
    res->locals_set(true);
    res->proto_add(parent);
    return res;
  }

  namespace
  {
    // helper for make_method_scope and make_do_scope
    static rObject
    make_outer_scope(const rObject& parent, const rObject& self)
    {
      rObject res = Object::make_scope(parent);
      res->slot_copy(SYMBOL(getSlot), scope_class);
      res->slot_copy(SYMBOL(locateSlot), scope_class);
      res->slot_copy(SYMBOL(removeSlot), scope_class);
      res->slot_copy(SYMBOL(updateSlot), scope_class);
      res->slot_set(SYMBOL(self), self);
      // We really need to copy 'locals' in every scope, or else
      // Scope's methods will get completely fubared: 'locals' will be
      // found in 'self' and will thus not be the local scope!
      res->slot_copy(SYMBOL(locals), scope_class);
      return res;
    }
  }

  rObject
  Object::make_method_scope(const rObject& self)
  {
    rObject res = make_outer_scope(global_class, self);
    res->slot_copy(SYMBOL(setSlot), scope_class);
    return res;
  }

  rObject
  Object::make_do_scope(const rObject& parent, const rObject& self)
  {
    rObject res = make_outer_scope (parent ? parent : global_class, self);
    res->slot_set(SYMBOL(setSlot), scope_class->slot_get(SYMBOL(doSetSlot)));
    return res;
  }

  /*--------.
  | Slots.  |
  `--------*/

  rObject
  Object::urbi_protos_get ()
  {
    if (!protos_cache_)
    {
      rList protos = List::fresh (*protos_);
      protos_cache_ = protos;
      delete protos_;
      protos_ = &protos->value_get ();
    }
    return protos_cache_;
  }

  void
  Object::protos_set (rObject l)
  {
    if (!protos_cache_)
      delete protos_;
    protos_cache_ = l;
    protos_ = &l.unsafe_cast<object::List>()->value_get ();
  }

  template <typename R>
  boost::optional<R>
  Object::lookup(boost::function1<boost::optional<R>, rObject> action,
		 objects_set_type& marks) const
  {
    if (!libport::mhas(marks, this))
    {
      marks.insert(this);
      assertion(self());
      boost::optional<R> res = action(self());
      if (res)
	return res;
      else
	foreach (const rObject& proto, protos_get())
	  if (boost::optional<R> res = proto->lookup(action, marks))
	    return res;
    }
    return boost::optional<R>();
  }

  template <typename R>
  boost::optional<R>
  Object::lookup(boost::function1<boost::optional<R>, rObject> action) const
  {
    objects_set_type marks;
    return lookup(action, marks);
  }

  namespace
  {
    class SlotLookup
    {
    public:
      lookup_result
      slot_lookup(rObject obj, const Slots::key_type& k, bool value)
      {
	assertion(obj);
	if (rObject x = obj->own_slot_get(k, 0))
	  return value ? x : obj;
	if (!fallback)
          if (rObject f = obj->own_slot_get(SYMBOL(fallback), 0))
            fallback = value ? f : obj;
	return boost::optional<rObject>();
      }
      rObject fallback;
    };
  }

  rObject Object::slot_locate(const Slots::key_type& k,
                              bool fallback, bool value) const
  {
    SlotLookup looker;
    lookup_action action = boost::bind(&SlotLookup::slot_lookup, &looker, _1, k, value);
    boost::optional<rObject> res = lookup(action);
    if (!res && fallback && looker.fallback)
      res = looker.fallback;
    return res ? res.get() : 0;
  }

  rObject
  Object::safe_slot_locate(const Slots::key_type& k, bool value) const
  {
    rObject r = slot_locate(k, true, value);
    if (!r)
      throw LookupError(k);
    return iassertion(r);
  }

  rObject
  Object::slot_get (const Slots::key_type& k, boost::optional<rObject> def) const
  {
    rObject value;
    if (def)
      value = slot_locate(k, true, true);
    else
      value = safe_slot_locate(k, true);
    if (value)
      return value;
    else
      return def.get();
  }

  Object&
  Object::slot_set (const Slots::key_type& k, rObject o)
  {
    if (!slots_.set(k, o))
      throw RedefinitionError(k);
    return *this;
  }

  Object&
  Object::slot_copy (const Slots::key_type& name, rObject from)
  {
    this->slot_set(name, from->slot_get(name));
    return *this;
  }

  void
  Object::slot_update (runner::Runner& r,
		       const Slots::key_type& k,
		       rObject o,
		       bool hook)
  {
    // The target of updateSlot
    rObject context = self();
    // The owner of the updated slot
    rObject owner = context->safe_slot_locate(k);

    // We have to determine where the new value must be stored,
    // depending on whether the slot owner and the context are scopes.
    rObject effective_target;

    // If both are scopes, update the original scope.
    if (context->locals_ && owner->locals_get())
      effective_target = owner;
    else if (context->locals_ && !owner->locals_get())
    {
      // Local->class: copyonwrite to "self" after evaluating it.
      rObject self = urbi_call(r, context, SYMBOL(self));
      assertion(self);
      effective_target = self;
    }
    else // Class->class: copy on write.
      effective_target = context;
    // Check hook, only if we are not create-on-writing.
    /* If the current value in the slot to be written in has a slot named
     * 'updateHook', call it, passing the object owning the slot, the slot name
     * and the target.
     */
    if (hook && effective_target == owner)
    // FIXME: We probably want helper to access properties
    if (rObject properties = effective_target->slot_get(SYMBOL(properties), rObject()))
    if (rObject slotProperties = properties->slot_get(k, rObject()))
    if (rObject hook = slotProperties->slot_get(SYMBOL(updateHook), rObject()))
    {
      objects_type args;
      args.push_back(effective_target);
      args.push_back(String::fresh(k));
      args.push_back(o);
      rObject ret = r.apply(hook, SYMBOL(updateHook), args);
      // If the updateHook returned void, do nothing. Otherwise let
      // the slot be overwritten.
      if (ret == object::void_class)
	return;
    }
    // If return-value of hook is not void, write it to slot.
    effective_target->own_slot_update(k, o);
  };

  void
  Object::own_slot_update (const Slots::key_type& k, rObject v)
  {
    slots_.update(k, v);
  }

  rObject
  Object::own_slot_get (const Slots::key_type& k, rObject def)
  {
    rObject res = slots_.get(k);
    return res ? res : def;
  }

  void
  Object::all_slots_copy(const rObject& other)
  {
    foreach (Slots::slot_type slot, other->slots_get())
      if (!own_slot_get(slot.first, 0))
        slot_set(slot.first, slot.second);
  }

  /*-----------.
  | Printing.  |
  `-----------*/

  std::ostream&
  Object::special_slots_dump (std::ostream& o, runner::Runner&) const
  {
    return o;
  }

  bool
  Object::operator< (const Object& rhs) const
  {
    return this < &rhs;
  }

  std::ostream&
  Object::id_dump(std::ostream& o, runner::Runner& r) const
  {
    rObject data = urbi_call(r, self(), SYMBOL(id));
    std::string s = data->value<String>().name_get();
    return o << s;
  }

  std::ostream&
  Object::protos_dump(std::ostream& o, runner::Runner& runner) const
  {
    if (!protos_->empty())
    {
      o << "protos = ";
      bool tail = false;
      foreach (rObject p, *protos_)
      {
	if (tail++)
	  o << ", ";
	p->id_dump (o, runner);
      }
      o << libport::iendl;
    }
    return o;
  }

  std::ostream&
  Object::dump (std::ostream& o, runner::Runner& runner) const
  {
    id_dump(o, runner);
    /// Use xalloc/iword to store our current depth within the stream object.
    static const long idx = o.xalloc();
    long& current_depth = o.iword(idx);

    // Stop recursion at depth_max.
    enum { depth_max = 3 };
    if (current_depth > depth_max)
      return o << " <...>";
    ++current_depth;
    o << " {" << libport::incendl;
    protos_dump(o, runner);
    special_slots_dump (o, runner);
    foreach(Slots::slot_type s, slots_.container())
    {
      o << s.first << " = ";
      s.second->dump(o, runner) << libport::iendl;
    }

    o << libport::decindent << '}';
    //We can not reuse current_depth variable above according to spec.
    o.iword(idx)--;
    return o;
  }

  std::ostream&
  Object::print(std::ostream& o, runner::Runner& runner) const
  {
    try
    {
      rObject s = urbi_call(runner, self(), SYMBOL(asString));
      o << s->value<String>().name_get();
      return o;
    }
    // Check if asString was found, especially for bootstrap: asString
    // is implemented in urbi/urbi.u, but print is called to show
    // result in the toplevel before its definition.
    catch (LookupError&)
    {
      // If no asString method is supplied, print the unique id
      return o << std::hex << this;
    }
  }

  bool
  is_a(const rObject& c, const rObject& p)
  {
    return for_all_protos(c, boost::lambda::_1 == p);
  }

  bool
  is_true(const rObject& o)
  {
    // FIXME: should nil be true? It should probably be false.
    if (o == nil_class)
      return true;
    if (o->type_is<object::Float>())
      return o.unsafe_cast<object::Float>()->value_get();
    return true;
  }

} // namespace object
<|endoftext|>


<commit_before>/**
 ** \file object/system-class.cc
 ** \brief Creation of the URBI object system.
 */

#include <ltdl.h>

//#define ENABLE_DEBUG_TRACES
#include <libport/compiler.hh>
#include <libport/cstdlib>
#include <libport/format.hh>
#include <libport/program-name.hh>

#include <memory>
#include <sstream>

#include <kernel/uconnection.hh>
#include <kernel/uobject.hh>
#include <kernel/userver.hh>

#include <object/code.hh>
#include <object/cxx-primitive.hh>
#include <object/dictionary.hh>
#include <object/float.hh>
#include <object/global.hh>
#include <object/list.hh>
#include <object/lobby.hh>
#include <object/path.hh>
#include <object/symbols.hh>
#include <object/system.hh>
#include <object/tag.hh>
#include <object/task.hh>
#include <parser/transform.hh>
#include <runner/at-handler.hh>
#include <runner/interpreter.hh>
#include <runner/raise.hh>
#include <runner/runner.hh>

#include <ast/nary.hh>
#include <ast/routine.hh>

namespace object
{
  using kernel::urbiserver;

  static inline
  runner::Runner&
  runner()
  {
    return ::kernel::urbiserver->getCurrentRunner();
  }

  static inline
  runner::Interpreter&
  interpreter()
  {
    return dynamic_cast<runner::Interpreter&>(runner());
  }

  // Extract a filename from a String or a Path object
  static std::string
  filename_get(const rObject& o)
  {
    if (o.is_a<Path>())
      return o->as<Path>()->as_string();
    type_check<String>(o);
    return o->as<String>()->value_get();
  }

  rObject
  execute_parsed(parser::parse_result_type p,
                 libport::Symbol fun, std::string e)
  {
    runner::Interpreter& run = interpreter();

    // Report potential errors
    {
      ast::rNary errs = new ast::Nary();
      p->process_errors(*errs);
      run(errs.get());
    }

    ast::rConstAst ast = parser::transform(p->ast_get());
    if (!ast)
      RAISE(e);

    runner::Interpreter* sub = new runner::Interpreter(run, ast, fun);
    // So that it will resist to the call to yield_until_terminated,
    // and will be reclaimed at the end of the scope.
    sched::rJob job = sub;
    libport::Finally finally;
    runner().register_child(sub, finally);
    sub->start_job();
    try
    {
      run.yield_until_terminated(*job);
    }
    catch (const sched::ChildException& ce)
    {
      // Kill the sub-job and propagate.
      ce.rethrow_child_exception();
    }
    return sub->result_get();
  }

  rObject system_class;

  /*--------------------.
  | System primitives.  |
  `--------------------*/

#define SERVER_FUNCTION(Function)               \
  static void                                   \
  system_ ## Function()                         \
  {                                             \
    urbiserver->Function();                     \
  }

  SERVER_FUNCTION(reboot)
  SERVER_FUNCTION(shutdown)

#undef SERVER_FUNCTION

  static void
  system_sleep(const rObject&, libport::ufloat seconds)
  {
    runner::Runner& r = runner();
    if (seconds == std::numeric_limits<ufloat>::infinity())
      r.yield_until_terminated(r);
    else
      r.yield_until(r.scheduler_get().get_time()
                    + static_cast<libport::utime_t>(seconds * 1000000.0));
  }

  static float
  system_time()
  {
    return runner().scheduler_get().get_time() / 1000000.0;
  }

  static float
  system_shiftedTime()
  {
    runner::Runner& r = runner();
    return (r.scheduler_get().get_time() - r.time_shift_get()) / 1000000.0;
  }

  static void
  system_assert_(const rObject&,
                 const rObject& value, const std::string& assertion)
  {
    if (!is_true(value))
      RAISE("failed assertion: " + assertion);
  }

  static rObject
  system_eval(const rObject&, const std::string& code)
  {
    return execute_parsed(parser::parse(code, ast::loc()),
                          SYMBOL(eval),
                          "error executing command: " + code);
  }

  static void
  system_registerAtJob(const rObject&,
                       const rObject& condition,
                       const rObject& clause,
                       const rObject& on_leave)
  {
    runner::register_at_job(interpreter(),
			    condition, clause, on_leave);
  }

  static rObject
  system_scopeTag()
  {
    return new Tag(interpreter().scope_tag());
  }

  static rObject
  system_searchFile(const rObject&, const rObject& f)
  {
    const std::string& filename = filename_get(f);
    try
    {
      return new Path(urbiserver->find_file(filename));
    }
    catch (libport::file_library::Not_found&)
    {
      runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
      // Never reached
      assertion(false);
      return 0;
    }
  }

  static List::value_type
  system_searchPath()
  {
    List::value_type res;
    foreach (const libport::path& p, urbiserver->search_path.search_path_get())
      res.push_back(new Path(p));
    return res;
  }

  static rObject
  system_loadFile(const rObject&, const rObject& f)
  {
    const std::string& filename = filename_get(f);
    if (!libport::path(filename).exists())
      runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
    return
      execute_parsed(parser::parse_file(filename),
                     SYMBOL(loadFile),
		     "error loading file: " + filename);
  }

  static rObject
  system_currentRunner()
  {
    return runner().as_task();
  }

  static float
  system_cycle()
  {
    return runner().scheduler_get().cycle_get();
  }

  static libport::Symbol
  system_fresh()
  {
    return libport::Symbol::fresh();
  }

  static rObject
  system_lobby()
  {
    return runner().lobby_get();
  }

  static void
  system_nonInterruptible()
  {
    runner().non_interruptible_set(true);
  }

  static void
  system_quit()
  {
    runner().lobby_get()->connection_get().close();
  }

  static void
  system_spawn(const rObject&,
	       const rCode& code,
               const rObject& clear_tags)
  {
    runner::Runner& r = runner();
    runner::Interpreter* new_runner =
      new runner::Interpreter(interpreter(),
                              rObject(code),
                              libport::Symbol::fresh(r.name_get()));

    if (is_true(clear_tags))
      new_runner->tag_stack_clear();

    new_runner->time_shift_set(r.time_shift_get());
    new_runner->start_job();
  }

  static rObject
  system_stats()
  {
    Dictionary::value_type res;
    const sched::scheduler_stats_type& stats =
      runner().scheduler_get().stats_get();

    // If statistics have just been reset, return "nil" since we cannot
    // return anything significant.
    if (stats.empty())
      return nil_class;

    // The space after "Symbol(" is mandatory to avoid triggering an error in
    // symbol generation code
#define ADDSTAT(Suffix, Function, Divisor)      \
    res[libport::Symbol("cycles" # Suffix)] =   \
      new Float(stats.Function() / Divisor)
    ADDSTAT(, size, 1);
    ADDSTAT(Max, max, 1e6);
    ADDSTAT(Mean, mean, 1e6);
    ADDSTAT(Min, min, 1e6);
    ADDSTAT(StdDev, standard_deviation, 1e6);
    ADDSTAT(Variance, variance, 1e3);
#undef ADDSTAT
    return new Dictionary(res);
  }

  static void
  system_resetStats()
  {
    runner().scheduler_get().stats_reset();
  }

  // This should give a backtrace as an urbi object.
  static void
  system_backtrace()
  {
    // FIXME: This method sucks a bit, because show_backtrace sucks a
    // bit, because our channeling/message-sending system sucks a lot.
    runner::Runner::backtrace_type bt = runner().backtrace_get();
    bt.pop_back();
    foreach (const runner::Runner::frame_type& elt,
	     boost::make_iterator_range(boost::rbegin(bt),
					boost::rend(bt)))
      runner().send_message("backtrace", elt.first + " (" + elt.second + ")");
  }

  static List::value_type
  system_jobs()
  {
    List::value_type res;
    foreach(sched::rJob job, runner().scheduler_get().jobs_get())
      res.push_back(dynamic_cast<runner::Runner*>(job.get())->as_task());
    return res;
  }

  static int
  system_aliveJobs()
  {
    return sched::Job::alive_jobs();
  }

  static void
  system_breakpoint()
  {
    return;
  }

#define SERVER_SET_VAR(Function, Variable, Value)       \
  static void                                           \
  system_ ## Function ()                                \
  {                                                     \
    urbiserver->Variable = Value;                       \
  }

  SERVER_SET_VAR(stopall, stopall, true)

#undef SERVER_SET_VAR

  static rObject
  system_getenv(const rObject&, const std::string& name)
  {
    char* res = getenv(name.c_str());
    return res ? new String(res) : nil_class;
  }

  static rObject
  system_setenv(const rObject&, const std::string& name, rObject value)
  {
    rString v = value->call(SYMBOL(asString))->as<String>();
    setenv(name.c_str(), v->value_get().c_str(), 1);
    return v;
  }

  static rObject
  system_unsetenv(const rObject&, const std::string& name)
  {
    rObject res = system_getenv(0, name);
    unsetenv(name.c_str());
    return res;
  }

  static libport::InstanceTracker<Lobby>::set_type
  system_lobbies()
  {
    return Lobby::instances_get();
  }

  static void
  system_loadModule(const rObject&, const std::string& name)
  {
    static bool initialized = false;

    if (!initialized)
    {
      initialized = true;
      lt_dlinit();
    }
    lt_dlhandle handle = lt_dlopenext(name.c_str());
    if (!handle)
      RAISE("Failed to open `" + name + "': " + lt_dlerror());

    // Reload uobjects
    uobjects_reload();

    // Reload CxxObjects
    CxxObject::create();
    CxxObject::initialize(global_class);
    CxxObject::cleanup();
  }

  static libport::cli_args_type urbi_arguments_;
  static boost::optional<std::string> urbi_program_name_;

  void
  system_push_argument(const std::string& arg)
  {
    urbi_arguments_.push_back(arg);
  }

  void
  system_set_program_name(const std::string& name)
  {
    urbi_program_name_ = name;
  }

  static const libport::cli_args_type&
  system_arguments()
  {
    return urbi_arguments_;
  }

  static boost::optional<std::string>
  system_programName()
  {
    return urbi_program_name_;
  }

  static void
  system__exit(const rObject&, int status)
  {
    exit(status);
  }

  static int
  system_system(const rObject&, const std::string& s)
  {
    int res = system(s.c_str());
    switch (res)
    {
    case -1:
      // FIXME: This is potentially widly used, see also path.cc.
      RAISE(libport::format("%1%: %2%", strerror(errno), s));
      break;
    case 127:
      RAISE(libport::format("shell failed: %1%", s));
      break;
    }
    return res;
  }

  void
  system_class_initialize()
  {
#define DECLARE(Name)                                                   \
    system_class->slot_set(SYMBOL(Name),                                \
                           make_primitive(&system_##Name))              \

    DECLARE(_exit);
    DECLARE(aliveJobs);
    DECLARE(arguments);
    DECLARE(assert_);
    DECLARE(backtrace);
    DECLARE(breakpoint);
    DECLARE(currentRunner);
    DECLARE(cycle);
    DECLARE(eval);
    DECLARE(fresh);
    DECLARE(getenv);
    DECLARE(jobs);
    DECLARE(loadFile);
    DECLARE(loadModule);
    DECLARE(lobbies);
    DECLARE(lobby);
    DECLARE(nonInterruptible);
    DECLARE(programName);
    DECLARE(quit);
    DECLARE(reboot);
    DECLARE(registerAtJob);
    DECLARE(resetStats);
    DECLARE(scopeTag);
    DECLARE(searchFile);
    DECLARE(searchPath);
    DECLARE(setenv);
    DECLARE(shiftedTime);
    DECLARE(shutdown);
    DECLARE(sleep);
    DECLARE(spawn);
    DECLARE(stats);
    DECLARE(stopall);
    DECLARE(system);
    DECLARE(time);
    DECLARE(unsetenv);

#undef DECLARE
  }

} // namespace object
<commit_msg>Missing include.<commit_after>/**
 ** \file object/system-class.cc
 ** \brief Creation of the URBI object system.
 */

#include <ltdl.h>

//#define ENABLE_DEBUG_TRACES
#include <libport/compiler.hh>
#include <libport/cstdlib>
#include <libport/format.hh>
#include <libport/program-name.hh>

#include <cerrno>
#include <memory>
#include <sstream>

#include <kernel/uconnection.hh>
#include <kernel/uobject.hh>
#include <kernel/userver.hh>

#include <object/code.hh>
#include <object/cxx-primitive.hh>
#include <object/dictionary.hh>
#include <object/float.hh>
#include <object/global.hh>
#include <object/list.hh>
#include <object/lobby.hh>
#include <object/path.hh>
#include <object/symbols.hh>
#include <object/system.hh>
#include <object/tag.hh>
#include <object/task.hh>
#include <parser/transform.hh>
#include <runner/at-handler.hh>
#include <runner/interpreter.hh>
#include <runner/raise.hh>
#include <runner/runner.hh>

#include <ast/nary.hh>
#include <ast/routine.hh>

namespace object
{
  using kernel::urbiserver;

  static inline
  runner::Runner&
  runner()
  {
    return ::kernel::urbiserver->getCurrentRunner();
  }

  static inline
  runner::Interpreter&
  interpreter()
  {
    return dynamic_cast<runner::Interpreter&>(runner());
  }

  // Extract a filename from a String or a Path object
  static std::string
  filename_get(const rObject& o)
  {
    if (o.is_a<Path>())
      return o->as<Path>()->as_string();
    type_check<String>(o);
    return o->as<String>()->value_get();
  }

  rObject
  execute_parsed(parser::parse_result_type p,
                 libport::Symbol fun, std::string e)
  {
    runner::Interpreter& run = interpreter();

    // Report potential errors
    {
      ast::rNary errs = new ast::Nary();
      p->process_errors(*errs);
      run(errs.get());
    }

    ast::rConstAst ast = parser::transform(p->ast_get());
    if (!ast)
      RAISE(e);

    runner::Interpreter* sub = new runner::Interpreter(run, ast, fun);
    // So that it will resist to the call to yield_until_terminated,
    // and will be reclaimed at the end of the scope.
    sched::rJob job = sub;
    libport::Finally finally;
    runner().register_child(sub, finally);
    sub->start_job();
    try
    {
      run.yield_until_terminated(*job);
    }
    catch (const sched::ChildException& ce)
    {
      // Kill the sub-job and propagate.
      ce.rethrow_child_exception();
    }
    return sub->result_get();
  }

  rObject system_class;

  /*--------------------.
  | System primitives.  |
  `--------------------*/

#define SERVER_FUNCTION(Function)               \
  static void                                   \
  system_ ## Function()                         \
  {                                             \
    urbiserver->Function();                     \
  }

  SERVER_FUNCTION(reboot)
  SERVER_FUNCTION(shutdown)

#undef SERVER_FUNCTION

  static void
  system_sleep(const rObject&, libport::ufloat seconds)
  {
    runner::Runner& r = runner();
    if (seconds == std::numeric_limits<ufloat>::infinity())
      r.yield_until_terminated(r);
    else
      r.yield_until(r.scheduler_get().get_time()
                    + static_cast<libport::utime_t>(seconds * 1000000.0));
  }

  static float
  system_time()
  {
    return runner().scheduler_get().get_time() / 1000000.0;
  }

  static float
  system_shiftedTime()
  {
    runner::Runner& r = runner();
    return (r.scheduler_get().get_time() - r.time_shift_get()) / 1000000.0;
  }

  static void
  system_assert_(const rObject&,
                 const rObject& value, const std::string& assertion)
  {
    if (!is_true(value))
      RAISE("failed assertion: " + assertion);
  }

  static rObject
  system_eval(const rObject&, const std::string& code)
  {
    return execute_parsed(parser::parse(code, ast::loc()),
                          SYMBOL(eval),
                          "error executing command: " + code);
  }

  static void
  system_registerAtJob(const rObject&,
                       const rObject& condition,
                       const rObject& clause,
                       const rObject& on_leave)
  {
    runner::register_at_job(interpreter(),
			    condition, clause, on_leave);
  }

  static rObject
  system_scopeTag()
  {
    return new Tag(interpreter().scope_tag());
  }

  static rObject
  system_searchFile(const rObject&, const rObject& f)
  {
    const std::string& filename = filename_get(f);
    try
    {
      return new Path(urbiserver->find_file(filename));
    }
    catch (libport::file_library::Not_found&)
    {
      runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
      // Never reached
      assertion(false);
      return 0;
    }
  }

  static List::value_type
  system_searchPath()
  {
    List::value_type res;
    foreach (const libport::path& p, urbiserver->search_path.search_path_get())
      res.push_back(new Path(p));
    return res;
  }

  static rObject
  system_loadFile(const rObject&, const rObject& f)
  {
    const std::string& filename = filename_get(f);
    if (!libport::path(filename).exists())
      runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
    return
      execute_parsed(parser::parse_file(filename),
                     SYMBOL(loadFile),
		     "error loading file: " + filename);
  }

  static rObject
  system_currentRunner()
  {
    return runner().as_task();
  }

  static float
  system_cycle()
  {
    return runner().scheduler_get().cycle_get();
  }

  static libport::Symbol
  system_fresh()
  {
    return libport::Symbol::fresh();
  }

  static rObject
  system_lobby()
  {
    return runner().lobby_get();
  }

  static void
  system_nonInterruptible()
  {
    runner().non_interruptible_set(true);
  }

  static void
  system_quit()
  {
    runner().lobby_get()->connection_get().close();
  }

  static void
  system_spawn(const rObject&,
	       const rCode& code,
               const rObject& clear_tags)
  {
    runner::Runner& r = runner();
    runner::Interpreter* new_runner =
      new runner::Interpreter(interpreter(),
                              rObject(code),
                              libport::Symbol::fresh(r.name_get()));

    if (is_true(clear_tags))
      new_runner->tag_stack_clear();

    new_runner->time_shift_set(r.time_shift_get());
    new_runner->start_job();
  }

  static rObject
  system_stats()
  {
    Dictionary::value_type res;
    const sched::scheduler_stats_type& stats =
      runner().scheduler_get().stats_get();

    // If statistics have just been reset, return "nil" since we cannot
    // return anything significant.
    if (stats.empty())
      return nil_class;

    // The space after "Symbol(" is mandatory to avoid triggering an error in
    // symbol generation code
#define ADDSTAT(Suffix, Function, Divisor)      \
    res[libport::Symbol("cycles" # Suffix)] =   \
      new Float(stats.Function() / Divisor)
    ADDSTAT(, size, 1);
    ADDSTAT(Max, max, 1e6);
    ADDSTAT(Mean, mean, 1e6);
    ADDSTAT(Min, min, 1e6);
    ADDSTAT(StdDev, standard_deviation, 1e6);
    ADDSTAT(Variance, variance, 1e3);
#undef ADDSTAT
    return new Dictionary(res);
  }

  static void
  system_resetStats()
  {
    runner().scheduler_get().stats_reset();
  }

  // This should give a backtrace as an urbi object.
  static void
  system_backtrace()
  {
    // FIXME: This method sucks a bit, because show_backtrace sucks a
    // bit, because our channeling/message-sending system sucks a lot.
    runner::Runner::backtrace_type bt = runner().backtrace_get();
    bt.pop_back();
    foreach (const runner::Runner::frame_type& elt,
	     boost::make_iterator_range(boost::rbegin(bt),
					boost::rend(bt)))
      runner().send_message("backtrace", elt.first + " (" + elt.second + ")");
  }

  static List::value_type
  system_jobs()
  {
    List::value_type res;
    foreach(sched::rJob job, runner().scheduler_get().jobs_get())
      res.push_back(dynamic_cast<runner::Runner*>(job.get())->as_task());
    return res;
  }

  static int
  system_aliveJobs()
  {
    return sched::Job::alive_jobs();
  }

  static void
  system_breakpoint()
  {
    return;
  }

#define SERVER_SET_VAR(Function, Variable, Value)       \
  static void                                           \
  system_ ## Function ()                                \
  {                                                     \
    urbiserver->Variable = Value;                       \
  }

  SERVER_SET_VAR(stopall, stopall, true)

#undef SERVER_SET_VAR

  static rObject
  system_getenv(const rObject&, const std::string& name)
  {
    char* res = getenv(name.c_str());
    return res ? new String(res) : nil_class;
  }

  static rObject
  system_setenv(const rObject&, const std::string& name, rObject value)
  {
    rString v = value->call(SYMBOL(asString))->as<String>();
    setenv(name.c_str(), v->value_get().c_str(), 1);
    return v;
  }

  static rObject
  system_unsetenv(const rObject&, const std::string& name)
  {
    rObject res = system_getenv(0, name);
    unsetenv(name.c_str());
    return res;
  }

  static libport::InstanceTracker<Lobby>::set_type
  system_lobbies()
  {
    return Lobby::instances_get();
  }

  static void
  system_loadModule(const rObject&, const std::string& name)
  {
    static bool initialized = false;

    if (!initialized)
    {
      initialized = true;
      lt_dlinit();
    }
    lt_dlhandle handle = lt_dlopenext(name.c_str());
    if (!handle)
      RAISE("Failed to open `" + name + "': " + lt_dlerror());

    // Reload uobjects
    uobjects_reload();

    // Reload CxxObjects
    CxxObject::create();
    CxxObject::initialize(global_class);
    CxxObject::cleanup();
  }

  static libport::cli_args_type urbi_arguments_;
  static boost::optional<std::string> urbi_program_name_;

  void
  system_push_argument(const std::string& arg)
  {
    urbi_arguments_.push_back(arg);
  }

  void
  system_set_program_name(const std::string& name)
  {
    urbi_program_name_ = name;
  }

  static const libport::cli_args_type&
  system_arguments()
  {
    return urbi_arguments_;
  }

  static boost::optional<std::string>
  system_programName()
  {
    return urbi_program_name_;
  }

  static void
  system__exit(const rObject&, int status)
  {
    exit(status);
  }

  static int
  system_system(const rObject&, const std::string& s)
  {
    int res = system(s.c_str());
    switch (res)
    {
    case -1:
      // FIXME: This is potentially widly used, see also path.cc.
      RAISE(libport::format("%1%: %2%", strerror(errno), s));
      break;
    case 127:
      RAISE(libport::format("shell failed: %1%", s));
      break;
    }
    return res;
  }

  void
  system_class_initialize()
  {
#define DECLARE(Name)                                                   \
    system_class->slot_set(SYMBOL(Name),                                \
                           make_primitive(&system_##Name))              \

    DECLARE(_exit);
    DECLARE(aliveJobs);
    DECLARE(arguments);
    DECLARE(assert_);
    DECLARE(backtrace);
    DECLARE(breakpoint);
    DECLARE(currentRunner);
    DECLARE(cycle);
    DECLARE(eval);
    DECLARE(fresh);
    DECLARE(getenv);
    DECLARE(jobs);
    DECLARE(loadFile);
    DECLARE(loadModule);
    DECLARE(lobbies);
    DECLARE(lobby);
    DECLARE(nonInterruptible);
    DECLARE(programName);
    DECLARE(quit);
    DECLARE(reboot);
    DECLARE(registerAtJob);
    DECLARE(resetStats);
    DECLARE(scopeTag);
    DECLARE(searchFile);
    DECLARE(searchPath);
    DECLARE(setenv);
    DECLARE(shiftedTime);
    DECLARE(shutdown);
    DECLARE(sleep);
    DECLARE(spawn);
    DECLARE(stats);
    DECLARE(stopall);
    DECLARE(system);
    DECLARE(time);
    DECLARE(unsetenv);

#undef DECLARE
  }

} // namespace object
<|endoftext|>


<commit_before>#include <cstdlib>
#include <cstdio>

#include "parser.h"
#include "../fancy_exception.h"
#include "../utils.h"
#include "../bootstrap/core_classes.h"

/* prototype of bison-generated parser function */
extern int yyparse();
extern void yyrestart(FILE*);
extern yy_buffer_state* yy_create_buffer(FILE*, int);
extern yy_buffer_state* yy_scan_string(const char*);
extern int yy_switch_to_buffer(yy_buffer_state*);
extern int yy_delete_buffer(yy_buffer_state*);

namespace fancy {
  namespace parser {

    string current_file;
    stack<parser_buffer> parse_buffers;
    list<string> load_path;
    FancyObject* last_value = nil;

    void parse_file(string &filename)
    {
      // put the path of the file into the load_path vector
      // this makes requiring files in the same directory easier
      string filepath = dirname_for_path(filename);
      if(!is_whitespace(filepath)) {
        load_path.push_back(filepath);
        load_path.unique(); // remove double entries
      }

      if(push_buffer(filename)) {
        try {
          yyparse();
        } catch(FancyException* ex) {
          errorln("GOT UNCAUGHT EXCEPTION, ABORTING.");
          errorln(ex->to_s());
          exit(1);
        }

        pop_buffer();
      }
    }

    FancyObject* parse_string(const string &code)
    {
      parser_buffer buf;
      buf.buffstate = yy_scan_string(code.c_str());
      buf.lineno = yylineno;
      buf.file = NULL;
      buf.filename = "";

      yylineno = 1;
      yy_switch_to_buffer(buf.buffstate);

      try {
        yyparse();
      } catch(FancyException* ex) {
        errorln("GOT UNCAUGHT EXCEPTION, ABORTING.");
        errorln(ex->to_s());
        exit(1);
      }

      // delete string buffer
      yy_delete_buffer(buf.buffstate);

      // reset to what we had before
      if(!parse_buffers.empty()) {
        parser_buffer prev = parse_buffers.top();
        yy_switch_to_buffer(prev.buffstate);
        yylineno = prev.lineno;
        current_file = prev.filename;
      }

      // finally, return the last evaluated value
      return last_value;
    }

    bool push_buffer(const string &filename)
    {
      parser_buffer buf;
      FILE *f = find_open_file(filename);
      if(!f) {
        error("");
        perror(filename.c_str());
        return false;
      }
      buf.buffstate = yy_create_buffer(f, YY_BUF_SIZE);
      buf.file = f;
      buf.filename = filename;
      buf.lineno = yylineno;
      parse_buffers.push(buf);

      current_file = filename;
      yylineno = 1;

      yy_switch_to_buffer(buf.buffstate);
      return true;
    }

    void pop_buffer()
    {
      if(!parse_buffers.empty()) {
        parser_buffer buf = parse_buffers.top();
        parse_buffers.pop();

        fclose(buf.file);
        yy_delete_buffer(buf.buffstate);

        if(!parse_buffers.empty()) {
          parser_buffer prev = parse_buffers.top();
          yy_switch_to_buffer(prev.buffstate);
          yylineno = prev.lineno;
          current_file = prev.filename;
        }
      }
    }

    FILE* find_open_file(const string &filename)
    {
      FILE *f = 0;

      // try direct filename first
      f = fopen(filename.c_str(), "r");

      // if that failed, try with each path in load_path prepended to
      // the filename until we succeed
      if(!f) {
        for(list<string>::iterator it = load_path.begin();
            it != load_path.end();
            it++) {
          f = fopen(((*it) + "/" + filename).c_str(), "r");
          if(f) {
            return f;
          }
        }
      }
      // at this point we failed and f = 0
      return f;
    }

    string dirname_for_path(const string &path)
    {
      size_t found = path.find_last_of("/\\");
      return path.substr(0,found);
    }
    string filename_for_path(const string &path)
    {
      size_t found = path.find_last_of("/\\");
      return path.substr(found + 1);
    }

    bool is_whitespace(const string &str)
    {
      size_t found = str.find_first_not_of(" \t\r\n");
      return str.substr(found) == "";
    }

  }
}

<commit_msg>parser/parser.cc: removed unnecessary try-catch block around yyparse() call<commit_after>#include <cstdlib>
#include <cstdio>

#include "parser.h"
#include "../fancy_exception.h"
#include "../utils.h"
#include "../bootstrap/core_classes.h"

/* prototype of bison-generated parser function */
extern int yyparse();
extern void yyrestart(FILE*);
extern yy_buffer_state* yy_create_buffer(FILE*, int);
extern yy_buffer_state* yy_scan_string(const char*);
extern int yy_switch_to_buffer(yy_buffer_state*);
extern int yy_delete_buffer(yy_buffer_state*);

namespace fancy {
  namespace parser {

    string current_file;
    stack<parser_buffer> parse_buffers;
    list<string> load_path;
    FancyObject* last_value = nil;

    void parse_file(string &filename)
    {
      // put the path of the file into the load_path vector
      // this makes requiring files in the same directory easier
      string filepath = dirname_for_path(filename);
      if(!is_whitespace(filepath)) {
        load_path.push_back(filepath);
        load_path.unique(); // remove double entries
      }

      if(push_buffer(filename)) {
        try {
          yyparse();
        } catch(FancyException* ex) {
          errorln("GOT UNCAUGHT EXCEPTION, ABORTING.");
          errorln(ex->to_s());
          exit(1);
        }

        pop_buffer();
      }
    }

    FancyObject* parse_string(const string &code)
    {
      parser_buffer buf;
      buf.buffstate = yy_scan_string(code.c_str());
      buf.lineno = yylineno;
      buf.file = NULL;
      buf.filename = "";

      yylineno = 1;
      yy_switch_to_buffer(buf.buffstate);

      yyparse();

      // delete string buffer
      yy_delete_buffer(buf.buffstate);

      // reset to what we had before
      if(!parse_buffers.empty()) {
        parser_buffer prev = parse_buffers.top();
        yy_switch_to_buffer(prev.buffstate);
        yylineno = prev.lineno;
        current_file = prev.filename;
      }

      // finally, return the last evaluated value
      return last_value;
    }

    bool push_buffer(const string &filename)
    {
      parser_buffer buf;
      FILE *f = find_open_file(filename);
      if(!f) {
        error("");
        perror(filename.c_str());
        return false;
      }
      buf.buffstate = yy_create_buffer(f, YY_BUF_SIZE);
      buf.file = f;
      buf.filename = filename;
      buf.lineno = yylineno;
      parse_buffers.push(buf);

      current_file = filename;
      yylineno = 1;

      yy_switch_to_buffer(buf.buffstate);
      return true;
    }

    void pop_buffer()
    {
      if(!parse_buffers.empty()) {
        parser_buffer buf = parse_buffers.top();
        parse_buffers.pop();

        fclose(buf.file);
        yy_delete_buffer(buf.buffstate);

        if(!parse_buffers.empty()) {
          parser_buffer prev = parse_buffers.top();
          yy_switch_to_buffer(prev.buffstate);
          yylineno = prev.lineno;
          current_file = prev.filename;
        }
      }
    }

    FILE* find_open_file(const string &filename)
    {
      FILE *f = 0;

      // try direct filename first
      f = fopen(filename.c_str(), "r");

      // if that failed, try with each path in load_path prepended to
      // the filename until we succeed
      if(!f) {
        for(list<string>::iterator it = load_path.begin();
            it != load_path.end();
            it++) {
          f = fopen(((*it) + "/" + filename).c_str(), "r");
          if(f) {
            return f;
          }
        }
      }
      // at this point we failed and f = 0
      return f;
    }

    string dirname_for_path(const string &path)
    {
      size_t found = path.find_last_of("/\\");
      return path.substr(0,found);
    }
    string filename_for_path(const string &path)
    {
      size_t found = path.find_last_of("/\\");
      return path.substr(found + 1);
    }

    bool is_whitespace(const string &str)
    {
      size_t found = str.find_first_not_of(" \t\r\n");
      return str.substr(found) == "";
    }

  }
}

<|endoftext|>


<commit_before>#include <istream>

#include "parsers/bpn.hh"
#include "parsers/parse.hh"
#include "parsers/prod.hh"
#include "parsers/tina.hh"
#include "parsers/xml.hh"

namespace pnmc { namespace parsers {

/*------------------------------------------------------------------------------------------------*/

std::shared_ptr<pn::net>
parse(const conf::pnmc_configuration& conf, std::istream& in)
{
  std::shared_ptr<pn::net> net_ptr;

  switch (conf.file_type)
  {
    case (conf::input_format::bpn)  : return parsers::bpn(in);
    case (conf::input_format::prod) : return parsers::prod(in);
    case (conf::input_format::tina) : return parsers::tina(in);
    case (conf::input_format::xml)  : return parsers::xml(in);
  }
}

/*------------------------------------------------------------------------------------------------*/

}} // namespace pnmc::parsers
<commit_msg>Avoid (useless) warning about a non-void function returning nothing.<commit_after>#include <istream>

#include "parsers/bpn.hh"
#include "parsers/parse.hh"
#include "parsers/prod.hh"
#include "parsers/tina.hh"
#include "parsers/xml.hh"

namespace pnmc { namespace parsers {

/*------------------------------------------------------------------------------------------------*/

std::shared_ptr<pn::net>
parse(const conf::pnmc_configuration& conf, std::istream& in)
{
  std::shared_ptr<pn::net> net_ptr;

  switch (conf.file_type)
  {
    case (conf::input_format::bpn)  : return parsers::bpn(in);
    case (conf::input_format::prod) : return parsers::prod(in);
    case (conf::input_format::tina) : return parsers::tina(in);
    case (conf::input_format::xml)  : break;
  }
  return parsers::xml(in);
}

/*------------------------------------------------------------------------------------------------*/

}} // namespace pnmc::parsers
<|endoftext|>


<commit_before>/*
 * linker32.cpp
 *
 *  Created on: Jul 23, 2014
 *      Author: Pimenta
 */

#include <cstdint>
#include <cstring>
#include <cstdio>
#include <fstream>
#include <set>
#include <map>
#include <string>

using namespace std;

typedef uint32_t uword_t;

#ifndef MEM_WORDS
#define MEM_WORDS 0x2000
#endif

#ifndef WORD_WIDTH
#define WORD_WIDTH 32
#endif

struct ObjectFile32 {
    uword_t offset;
    uword_t text_offset;
    map<string, uword_t> exported;
    map<string, set<uword_t>> imported;
    set<uword_t> absolute;
    uword_t mem_size;
    uword_t* mem;

    ~ObjectFile32() {
      delete[] mem;
    }

    void initStart() {
      offset = 0;
      text_offset = 0;
      imported["start"].emplace(2);
      mem_size = 3;
      mem = new uword_t[3];
      mem[0] = 0;
      mem[1] = 0;
      mem[2] = 0;
    }

    void read(const char* fn, uword_t offs) {
      offset = offs;

      fstream f(fn, fstream::in | fstream::binary);

      uword_t tmp;

      // read text section offset
      f.read((char*)&text_offset, sizeof(uword_t));

      // read number of exported symbols
      f.read((char*)&tmp, sizeof(uword_t));

      // read exported symbols
      for (uword_t i = 0; i < tmp; ++i) {
        string sym;
        uword_t addr;

        // string
        {
          char c;
          f.read(&c, sizeof(char));
          while (c != '\0') {
            sym += c;
            f.read(&c, sizeof(char));
          }
        }

        // address
        f.read((char*)&addr, sizeof(uword_t));

        exported[sym] = addr;
      }

      // read number of symbols of pending references
      f.read((char*)&tmp, sizeof(uword_t));

      // read symbols of pending references
      for (uword_t i = 0; i < tmp; ++i) {
        string sym;

        // string
        {
          char c;
          f.read(&c, sizeof(char));
          while (c != '\0') {
            sym += c;
            f.read(&c, sizeof(char));
          }
        }

        uword_t tmp2;

        // read number of references to current symbol
        f.read((char*)&tmp2, sizeof(uword_t));

        // read references to current symbol
        for (uword_t j = 0; j < tmp2; ++j) {
          uword_t addr;
          f.read((char*)&addr, sizeof(uword_t));
          imported[sym].emplace(addr);
        }
      }

      // read number of absolute addresses
      f.read((char*)&tmp, sizeof(uword_t));

      // read absolute addresses
      for (uword_t i = 0; i < tmp; ++i) {
        uword_t addr;
        f.read((char*)&addr, sizeof(uword_t));
        absolute.emplace(addr);
      }

      // read assembled code size
      f.read((char*)&mem_size, sizeof(uword_t));

      // read assembled code
      mem = new uword_t[mem_size];
      f.read((char*)mem, sizeof(uword_t)*mem_size);

      f.close();
    }
};

int linker32(int argc, char* argv[]) {
  if (argc < 3) {
    fprintf(stderr, "Usage mode: subleq-ld <object_files...> <meminit_file>\n");
    return 0;
  }

  // read object files
  ObjectFile32 files[argc - 1];
  files[0].initStart();
  for (int i = 1; i < argc - 1; ++i)
    files[i].read(argv[i], files[i - 1].offset + files[i - 1].mem_size);

  uword_t mem_size = 0;
  uword_t* mem = new uword_t[MEM_WORDS];
  map<string, uword_t> symbols;
  map<string, set<uword_t>> references;
  set<uword_t> absolutes;

  for (auto& file : files) {
    // assemble global symbol table
    for (auto& sym : file.exported) {
      symbols[sym.first] = sym.second + file.offset;
    }

    // assemble global reference table
    for (auto& sym : file.imported) {
      set<uword_t>& refs = references[sym.first];
      for (auto addr : sym.second) {
        refs.emplace(addr + file.offset);
      }
    }

    // assemble global absolute address table
    for (auto addr : file.absolute) {
      absolutes.emplace(addr + file.offset);
    }

    // relocate addresses
    for (uword_t i = file.text_offset; i < file.mem_size; ++i) {
      auto it = file.absolute.find(i);
      if (it == file.absolute.end()) {
        file.mem[i] += file.offset;
      }
    }

    // copy object code
    memcpy(&mem[mem_size], file.mem, file.mem_size*sizeof(uword_t));
    mem_size += file.mem_size;
  }

  // solve references
  for (auto ref = references.begin(); ref != references.end();) {
    auto sym = symbols.find(ref->first);
    if (sym == symbols.end()) {
      ref++;
    }
    else {
      for (auto addr : ref->second) {
        mem[addr] = sym->second;
      }
      references.erase(ref++);
    }
  }

  // output mif
  fstream f(argv[argc - 1], fstream::out);
  char buf[20];
  f << "DEPTH = " << MEM_WORDS << ";\n";
  f << "WIDTH = " << WORD_WIDTH << ";\n";
  f << "ADDRESS_RADIX = HEX;\n";
  f << "DATA_RADIX = HEX;\n";
  f << "CONTENT\n";
  f << "BEGIN\n";
  f << "\n";
  for (uword_t i = 0; i < mem_size; ++i) {
    sprintf(buf, "%08x", i);
    f << buf;
    sprintf(buf, "%08x", mem[i]);
    f << " : " << buf << ";\n";
  }
  f << "\n";
  f << "END;\n";
  f.close();

  delete[] mem;

  return 0;
}
<commit_msg>Now the linker subleq32 takes and outputs relative address table instead of absolute<commit_after>/*
 * linker32.cpp
 *
 *  Created on: Jul 23, 2014
 *      Author: Pimenta
 */

#include <cstdint>
#include <cstring>
#include <cstdio>
#include <fstream>
#include <set>
#include <map>
#include <string>

using namespace std;

typedef uint32_t uword_t;

#ifndef MEM_WORDS
#define MEM_WORDS 0x2000
#endif

#ifndef WORD_WIDTH
#define WORD_WIDTH 32
#endif

struct ObjectFile32 {
    uword_t offset;
    map<string, uword_t> exported;
    map<string, set<uword_t>> imported;
    set<uword_t> relative;
    uword_t mem_size;
    uword_t* mem;

    ~ObjectFile32() {
      delete[] mem;
    }

    void read(const char* fn, uword_t offs) {
      offset = offs;

      fstream f(fn, fstream::in | fstream::binary);

      uword_t tmp;

      // read number of exported symbols
      f.read((char*)&tmp, sizeof(uword_t));

      // read exported symbols
      for (uword_t i = 0; i < tmp; ++i) {
        string sym;
        uword_t addr;

        // string
        {
          char c;
          f.read(&c, sizeof(char));
          while (c != '\0') {
            sym += c;
            f.read(&c, sizeof(char));
          }
        }

        // address
        f.read((char*)&addr, sizeof(uword_t));

        exported[sym] = addr;
      }

      // read number of symbols of pending references
      f.read((char*)&tmp, sizeof(uword_t));

      // read symbols of pending references
      for (uword_t i = 0; i < tmp; ++i) {
        string sym;

        // string
        {
          char c;
          f.read(&c, sizeof(char));
          while (c != '\0') {
            sym += c;
            f.read(&c, sizeof(char));
          }
        }

        uword_t tmp2;

        // read number of references to current symbol
        f.read((char*)&tmp2, sizeof(uword_t));

        // read references to current symbol
        for (uword_t j = 0; j < tmp2; ++j) {
          uword_t addr;
          f.read((char*)&addr, sizeof(uword_t));
          imported[sym].emplace(addr);
        }
      }

      // read number of relative addresses
      f.read((char*)&tmp, sizeof(uword_t));

      // read relative addresses
      for (uword_t i = 0; i < tmp; ++i) {
        uword_t addr;
        f.read((char*)&addr, sizeof(uword_t));
        relative.emplace(addr);
      }

      // read assembled code size
      f.read((char*)&mem_size, sizeof(uword_t));

      // read assembled code
      mem = new uword_t[mem_size];
      f.read((char*)mem, sizeof(uword_t)*mem_size);

      f.close();
    }
};

int linker32(int argc, char* argv[]) {
  if (argc < 3) {
    fprintf(stderr, "Usage mode: subleq-ld <object_files...> <meminit_file>\n");
    return 0;
  }

  // read object files
  ObjectFile32 files[argc - 2];
  files[0].read(argv[1], 0);
  for (int i = 2; i < argc - 1; ++i)
    files[i].read(argv[i], files[i - 1].offset + files[i - 1].mem_size);

  uword_t mem_size = 0;
  uword_t* mem = new uword_t[MEM_WORDS];
  map<string, uword_t> symbols;
  map<string, set<uword_t>> references;
  set<uword_t> relatives;

  for (auto& file : files) {
    // assemble global symbol table
    for (auto& sym : file.exported) {
      symbols[sym.first] = sym.second + file.offset;
    }

    // assemble global reference table
    for (auto& sym : file.imported) {
      set<uword_t>& refs = references[sym.first];
      for (auto addr : sym.second) {
        refs.emplace(addr + file.offset);
      }
    }

    // assemble global relative address table
    for (auto addr : file.relative) {
      relatives.emplace(addr + file.offset);
      file.mem[addr] += file.offset; // relocating
    }

    // copy object code
    memcpy(&mem[mem_size], file.mem, file.mem_size*sizeof(uword_t));
    mem_size += file.mem_size;
  }

  // solve references
  for (auto ref = references.begin(); ref != references.end();) {
    auto sym = symbols.find(ref->first);
    if (sym == symbols.end()) {
      ref++;
    }
    else {
      for (auto addr : ref->second) {
        mem[addr] = sym->second;
      }
      references.erase(ref++);
    }
  }

  // output mif
  fstream f(argv[argc - 1], fstream::out);
  char buf[20];
  f << "DEPTH = " << MEM_WORDS << ";\n";
  f << "WIDTH = " << WORD_WIDTH << ";\n";
  f << "ADDRESS_RADIX = HEX;\n";
  f << "DATA_RADIX = HEX;\n";
  f << "CONTENT\n";
  f << "BEGIN\n";
  f << "\n";
  for (uword_t i = 0; i < mem_size; ++i) {
    sprintf(buf, "%08x", i);
    f << buf;
    sprintf(buf, "%08x", mem[i]);
    f << " : " << buf << ";\n";
  }
  f << "\n";
  f << "END;\n";
  f.close();

  delete[] mem;

  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 Roman Neuhauser
// Distributed under the MIT license (see LICENSE file)
// vim: sw=2 sts=2 ts=2 fdm=marker cms=\ //\ %s

// shared_ptr
#include <memory>

#include <iostream>
#include <istream>
#include <ostream>
#include <fstream>
#include <string>
#include <vector>

#define EX_OK           0       /* successful termination */
#define EX_USAGE        64      /* command line usage error */
#define EX_DATAERR      65      /* data format error */
#define EX_NOINPUT      66      /* cannot open input */

#include "boost/ref.hpp"
#include "boost/foreach.hpp"
#include "boost/format.hpp"
#include "boost/date_time/gregorian/gregorian.hpp"
#include "boost/regex.hpp"

#include "iniphile/input.hpp"
#include "iniphile/ast.hpp"
#include "iniphile/output.hpp"

#define foreach BOOST_FOREACH

using std::shared_ptr;

using std::cin;
using std::cerr;
using std::endl;
using std::ios;
using std::getline;
using std::ostream;
using std::ifstream;
using std::ofstream;
using std::string;
using std::vector;

using boost::cref;
using boost::format;
using namespace boost::gregorian;
using boost::regex;
using boost::smatch;

namespace
{

struct expand_sink // {{{
{
  expand_sink(string const &prefix, date const &today)
  : prefix(prefix)
  , today(today)
  {}
private:
  string const &prefix;
  date const &today;
public:
  string
  operator()(smatch const &expando) const
  {
    auto sexpando = expando.str();
    if (sexpando == "%D") return to_iso_extended_string(today);
    if (sexpando == "%P") return prefix;
    return "LOGDEMUX-BUG";
  }
}; // }}}

class rule
{
public:
  rule(string const &prefix, string const &match, string const &sink, bool final, ostream &diag) // {{{
  : sink(sink)
  , prefix(prefix)
  , final(final)
  , pat(regex(match, regex::perl))
  , opened_on()
  , os()
  , diag(diag)
  {
  } // }}}
  bool
  handle(date const &today, string const &line) // {{{
  {
    if (!regex_search(line, pat))
      return false;
    if (opened_on != today)
      reopen(today);
    os << line << endl;
    return final;
  } // }}}
private:
  string const sink;
  string const prefix;
  bool final;
  regex pat;
  date opened_on;
  ofstream os;
  ostream &diag;

  void
  reopen(date const &today) // {{{
  {
    if (os.is_open()) os.close();
    os.clear();
    auto fname = expand(sink, today);
    os.open(fname.c_str(), ios::app | ios::binary);
    if (os.fail())
      diag << "failed to open " << fname << endl;
    opened_on = today;
  } // }}}
  string
  expand(string fmt, date const &d) const // {{{
  {
    return regex_replace(
      fmt
    , regex("%[DP]\\>")
    , cref(expand_sink(prefix, d))
    );
  } // }}}
};

class ruleset
{
public:
  ruleset(iniphile::ast::node const &ini, string const &prefix, ostream &diag)
  {
    foreach (auto const &rname, iniphile::get(ini, "rules.order", vector<string>()))
      rules.push_back(shared_ptr<rule>(new rule(
        prefix
      , iniphile::get(ini, rname + ".match", string(""))
      , iniphile::get(ini, rname + ".sink", string(""))
      , iniphile::get(ini, rname + ".final", false)
      , diag
      )));
  }
  void
  handle(date const &now, string const &line) // {{{
  {
    foreach (auto &r, rules)
      if (r->handle(now, line))
        break;
  } // }}}
private:
  vector<shared_ptr<rule>> rules;
};

date
today() // {{{
{
  return day_clock::local_day();
} // }}}

template<class Fmt>
int
complain(int exitcode, Fmt msg)
{
  cerr << msg << endl;
  return exitcode;
}

}

int
main(int argc, char **argv)
{
  string self = argc > 0 ? argv[0] : "logdemux";
  string bself = regex_replace(
    self
  , regex("^(.*/)?([^/]+)(.exe)?$", regex::perl)
  , "$2"
  );

  if (argc < 3)
    return complain(
      EX_USAGE
    , format("usage: %1% rules prefix") % bself
    );

  string ini = argv[1];
  string prefix = argv[2];
  ifstream sini;
  sini.open(ini);
  if (sini.fail())
    return complain(
      EX_NOINPUT
    , format("%1%: rules file '%2%' missing") % bself % ini
    );

  auto cfg = iniphile::parse(sini, cerr);
  sini.close();
  if (!cfg)
    return complain(
      EX_DATAERR
    , format("%1%: rules file '%2%' broken") % bself % ini
    );

  ruleset rules(iniphile::normalize(*cfg), prefix, cerr);

  string line;
  while (cin.good()) {
    while (getline(cin, line)) {
      rules.handle(today(), line);
    }
  }

  return EX_OK;
}
<commit_msg>rule::pat initialization w/o a redundant copy<commit_after>// Copyright (c) 2012 Roman Neuhauser
// Distributed under the MIT license (see LICENSE file)
// vim: sw=2 sts=2 ts=2 fdm=marker cms=\ //\ %s

// shared_ptr
#include <memory>

#include <iostream>
#include <istream>
#include <ostream>
#include <fstream>
#include <string>
#include <vector>

#define EX_OK           0       /* successful termination */
#define EX_USAGE        64      /* command line usage error */
#define EX_DATAERR      65      /* data format error */
#define EX_NOINPUT      66      /* cannot open input */

#include "boost/ref.hpp"
#include "boost/foreach.hpp"
#include "boost/format.hpp"
#include "boost/date_time/gregorian/gregorian.hpp"
#include "boost/regex.hpp"

#include "iniphile/input.hpp"
#include "iniphile/ast.hpp"
#include "iniphile/output.hpp"

#define foreach BOOST_FOREACH

using std::shared_ptr;

using std::cin;
using std::cerr;
using std::endl;
using std::ios;
using std::getline;
using std::ostream;
using std::ifstream;
using std::ofstream;
using std::string;
using std::vector;

using boost::cref;
using boost::format;
using namespace boost::gregorian;
using boost::regex;
using boost::smatch;

namespace
{

struct expand_sink // {{{
{
  expand_sink(string const &prefix, date const &today)
  : prefix(prefix)
  , today(today)
  {}
private:
  string const &prefix;
  date const &today;
public:
  string
  operator()(smatch const &expando) const
  {
    auto sexpando = expando.str();
    if (sexpando == "%D") return to_iso_extended_string(today);
    if (sexpando == "%P") return prefix;
    return "LOGDEMUX-BUG";
  }
}; // }}}

class rule
{
public:
  rule(string const &prefix, string const &match, string const &sink, bool final, ostream &diag) // {{{
  : sink(sink)
  , prefix(prefix)
  , final(final)
  , pat(match, regex::perl)
  , opened_on()
  , os()
  , diag(diag)
  {
  } // }}}
  bool
  handle(date const &today, string const &line) // {{{
  {
    if (!regex_search(line, pat))
      return false;
    if (opened_on != today)
      reopen(today);
    os << line << endl;
    return final;
  } // }}}
private:
  string const sink;
  string const prefix;
  bool final;
  regex pat;
  date opened_on;
  ofstream os;
  ostream &diag;

  void
  reopen(date const &today) // {{{
  {
    if (os.is_open()) os.close();
    os.clear();
    auto fname = expand(sink, today);
    os.open(fname.c_str(), ios::app | ios::binary);
    if (os.fail())
      diag << "failed to open " << fname << endl;
    opened_on = today;
  } // }}}
  string
  expand(string fmt, date const &d) const // {{{
  {
    return regex_replace(
      fmt
    , regex("%[DP]\\>")
    , cref(expand_sink(prefix, d))
    );
  } // }}}
};

class ruleset
{
public:
  ruleset(iniphile::ast::node const &ini, string const &prefix, ostream &diag)
  {
    foreach (auto const &rname, iniphile::get(ini, "rules.order", vector<string>()))
      rules.push_back(shared_ptr<rule>(new rule(
        prefix
      , iniphile::get(ini, rname + ".match", string(""))
      , iniphile::get(ini, rname + ".sink", string(""))
      , iniphile::get(ini, rname + ".final", false)
      , diag
      )));
  }
  void
  handle(date const &now, string const &line) // {{{
  {
    foreach (auto &r, rules)
      if (r->handle(now, line))
        break;
  } // }}}
private:
  vector<shared_ptr<rule>> rules;
};

date
today() // {{{
{
  return day_clock::local_day();
} // }}}

template<class Fmt>
int
complain(int exitcode, Fmt msg)
{
  cerr << msg << endl;
  return exitcode;
}

}

int
main(int argc, char **argv)
{
  string self = argc > 0 ? argv[0] : "logdemux";
  string bself = regex_replace(
    self
  , regex("^(.*/)?([^/]+)(.exe)?$", regex::perl)
  , "$2"
  );

  if (argc < 3)
    return complain(
      EX_USAGE
    , format("usage: %1% rules prefix") % bself
    );

  string ini = argv[1];
  string prefix = argv[2];
  ifstream sini;
  sini.open(ini);
  if (sini.fail())
    return complain(
      EX_NOINPUT
    , format("%1%: rules file '%2%' missing") % bself % ini
    );

  auto cfg = iniphile::parse(sini, cerr);
  sini.close();
  if (!cfg)
    return complain(
      EX_DATAERR
    , format("%1%: rules file '%2%' broken") % bself % ini
    );

  ruleset rules(iniphile::normalize(*cfg), prefix, cerr);

  string line;
  while (cin.good()) {
    while (getline(cin, line)) {
      rules.handle(today(), line);
    }
  }

  return EX_OK;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 Roman Neuhauser
// Distributed under the MIT license (see LICENSE file)
// vim: sw=2 sts=2 ts=2 fdm=marker cms=\ //\ %s

// shared_ptr
#include <memory>

#include <iostream>
#include <istream>
#include <ostream>
#include <fstream>
#include <string>
#include <vector>

#define EX_OK           0       /* successful termination */
#define EX_USAGE        64      /* command line usage error */
#define EX_DATAERR      65      /* data format error */
#define EX_NOINPUT      66      /* cannot open input */

#include "boost/foreach.hpp"
#include "boost/format.hpp"
#include "boost/date_time/gregorian/gregorian.hpp"
#include "boost/regex.hpp"

#include "iniphile/input.hpp"
#include "iniphile/ast.hpp"
#include "iniphile/output.hpp"

#define foreach BOOST_FOREACH

using std::shared_ptr;

using std::cin;
using std::cerr;
using std::endl;
using std::ios;
using std::getline;
using std::ifstream;
using std::ofstream;
using std::string;
using std::vector;

using boost::format;

using namespace boost::gregorian;

using boost::regex;

namespace
{

class rule
{
public:
  rule(string const &prefix, string const &match, string const &sink, bool final) // {{{
  : sink(sink)
  , prefix(prefix)
  , final(final)
  , pat(regex(match, regex::perl))
  , opened_on()
  , os()
  {
  } // }}}
  bool
  handle(date const &today, string const &line) // {{{
  {
    if (!regex_search(line, pat))
      return false;
    if (opened_on != today)
      reopen(os, today);
    os << line << endl;
    return final;
  } // }}}
private:
  string const sink;
  string const prefix;
  bool final;
  regex pat;
  date opened_on;
  ofstream os;

  void
  reopen(ofstream &os, date const &today) // {{{
  {
    if (os.is_open()) os.close();
    os.open(expand(sink, today).c_str(), ios::app | ios::binary);
    opened_on = today;
  } // }}}
  string
  expand(string fmt, date const &d) const // {{{
  {
    fmt = regex_replace(fmt, regex("%D"), to_iso_extended_string(d));
    fmt = regex_replace(fmt, regex("%P"), prefix);
    return fmt;
  } // }}}
};

template<class Ini = iniphile::ast::node>
class ruleset
{
public:
  ruleset(Ini const &ini, string const &prefix)
  : ini(ini)
  , prefix(prefix)
  {
    foreach (auto const &rname, iniphile::get(ini, "rules.order", vector<string>()))
      create_rule(rname);
  }
  void
  handle(date const &now, string const &line) // {{{
  {
    foreach (auto &r, rules)
      if (r->handle(now, line))
        break;
  } // }}}
private:
  Ini const &ini;
  string const &prefix;
  vector<shared_ptr<rule>> rules;

  void
  create_rule(string const &rname) // {{{
  {
    rules.push_back(shared_ptr<rule>(new rule(
      prefix
    , iniphile::get(ini, rname + ".match", string(""))
    , iniphile::get(ini, rname + ".sink", string(""))
    , iniphile::get(ini, rname + ".final", false)
    )));
  } // }}}
};

date
today() // {{{
{
  return day_clock::local_day();
} // }}}

template<class Fmt>
int
complain(int exitcode, Fmt msg)
{
  cerr << msg << endl;
  return exitcode;
}

}

int
main(int argc, char **argv)
{
  string self = argc > 0 ? argv[0] : "logdemux";
  string bself = self.substr(self.find_last_of("\\/") + 1);

  if (argc < 3)
    return complain(
      EX_USAGE
    , format("usage: %1% rules prefix") % bself
    );

  string ini = argv[1];
  string prefix = argv[2];
  ifstream sini;
  sini.open(ini);
  if (sini.fail())
    return complain(
      EX_NOINPUT
    , format("%1%: rules file '%2%' missing") % bself % ini
    );

  auto cfg = iniphile::parse(sini, cerr);
  if (!cfg)
    return complain(
      EX_DATAERR
    , format("%1%: rules file '%2%' broken") % bself % ini
    );

  ruleset<> rules(iniphile::normalize(*cfg), prefix);

  string line;
  while (cin.good()) {
    while (getline(cin, line)) {
      rules.handle(today(), line);
    }
  }

  return EX_OK;
}
<commit_msg>ruleset need not be a template<commit_after>// Copyright (c) 2012 Roman Neuhauser
// Distributed under the MIT license (see LICENSE file)
// vim: sw=2 sts=2 ts=2 fdm=marker cms=\ //\ %s

// shared_ptr
#include <memory>

#include <iostream>
#include <istream>
#include <ostream>
#include <fstream>
#include <string>
#include <vector>

#define EX_OK           0       /* successful termination */
#define EX_USAGE        64      /* command line usage error */
#define EX_DATAERR      65      /* data format error */
#define EX_NOINPUT      66      /* cannot open input */

#include "boost/foreach.hpp"
#include "boost/format.hpp"
#include "boost/date_time/gregorian/gregorian.hpp"
#include "boost/regex.hpp"

#include "iniphile/input.hpp"
#include "iniphile/ast.hpp"
#include "iniphile/output.hpp"

#define foreach BOOST_FOREACH

using std::shared_ptr;

using std::cin;
using std::cerr;
using std::endl;
using std::ios;
using std::getline;
using std::ifstream;
using std::ofstream;
using std::string;
using std::vector;

using boost::format;

using namespace boost::gregorian;

using boost::regex;

namespace
{

class rule
{
public:
  rule(string const &prefix, string const &match, string const &sink, bool final) // {{{
  : sink(sink)
  , prefix(prefix)
  , final(final)
  , pat(regex(match, regex::perl))
  , opened_on()
  , os()
  {
  } // }}}
  bool
  handle(date const &today, string const &line) // {{{
  {
    if (!regex_search(line, pat))
      return false;
    if (opened_on != today)
      reopen(os, today);
    os << line << endl;
    return final;
  } // }}}
private:
  string const sink;
  string const prefix;
  bool final;
  regex pat;
  date opened_on;
  ofstream os;

  void
  reopen(ofstream &os, date const &today) // {{{
  {
    if (os.is_open()) os.close();
    os.open(expand(sink, today).c_str(), ios::app | ios::binary);
    opened_on = today;
  } // }}}
  string
  expand(string fmt, date const &d) const // {{{
  {
    fmt = regex_replace(fmt, regex("%D"), to_iso_extended_string(d));
    fmt = regex_replace(fmt, regex("%P"), prefix);
    return fmt;
  } // }}}
};

class ruleset
{
public:
  ruleset(iniphile::ast::node const &ini, string const &prefix)
  : ini(ini)
  , prefix(prefix)
  {
    foreach (auto const &rname, iniphile::get(ini, "rules.order", vector<string>()))
      create_rule(rname);
  }
  void
  handle(date const &now, string const &line) // {{{
  {
    foreach (auto &r, rules)
      if (r->handle(now, line))
        break;
  } // }}}
private:
  iniphile::ast::node const &ini;
  string const &prefix;
  vector<shared_ptr<rule>> rules;

  void
  create_rule(string const &rname) // {{{
  {
    rules.push_back(shared_ptr<rule>(new rule(
      prefix
    , iniphile::get(ini, rname + ".match", string(""))
    , iniphile::get(ini, rname + ".sink", string(""))
    , iniphile::get(ini, rname + ".final", false)
    )));
  } // }}}
};

date
today() // {{{
{
  return day_clock::local_day();
} // }}}

template<class Fmt>
int
complain(int exitcode, Fmt msg)
{
  cerr << msg << endl;
  return exitcode;
}

}

int
main(int argc, char **argv)
{
  string self = argc > 0 ? argv[0] : "logdemux";
  string bself = self.substr(self.find_last_of("\\/") + 1);

  if (argc < 3)
    return complain(
      EX_USAGE
    , format("usage: %1% rules prefix") % bself
    );

  string ini = argv[1];
  string prefix = argv[2];
  ifstream sini;
  sini.open(ini);
  if (sini.fail())
    return complain(
      EX_NOINPUT
    , format("%1%: rules file '%2%' missing") % bself % ini
    );

  auto cfg = iniphile::parse(sini, cerr);
  if (!cfg)
    return complain(
      EX_DATAERR
    , format("%1%: rules file '%2%' broken") % bself % ini
    );

  ruleset rules(iniphile::normalize(*cfg), prefix);

  string line;
  while (cin.good()) {
    while (getline(cin, line)) {
      rules.handle(today(), line);
    }
  }

  return EX_OK;
}
<|endoftext|>


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

#ifndef _NDNOTXT_HXX
#include <ndnotxt.hxx>
#endif

#include <svtools/embedhlp.hxx>

class SwGrfFmtColl;
class SwDoc;
class SwOLENode;
class SwOLELink;

class SwOLEListener_Impl;
class SwOLEObj
{
    friend class SwOLENode;

    const SwOLENode* pOLENd;
    SwOLEListener_Impl* pListener;

    //Entweder Ref oder Name sind bekannt, wenn nur der Name bekannt ist, wird
    //dir Ref bei Anforderung durch GetOleRef() vom Sfx besorgt.
    svt::EmbeddedObjectRef xOLERef;
    String aName;

    SwOLEObj( const SwOLEObj& rObj );   //nicht erlaubt.
    SwOLEObj();

    void SetNode( SwOLENode* pNode );

public:
    SwOLEObj( const svt::EmbeddedObjectRef& pObj );
    SwOLEObj( const String &rName );
    ~SwOLEObj();

    BOOL UnloadObject();
    String GetDescription();

#ifndef _FESHVIEW_ONLY_INLINE_NEEDED
    com::sun::star::uno::Reference < com::sun::star::embed::XEmbeddedObject > GetOleRef();
    svt::EmbeddedObjectRef& GetObject();
    const String& GetCurrentPersistName() const { return aName; }
    BOOL IsOleRef() const;  //Damit das Objekt nicht unnoetig geladen werden muss.
#endif
};

// --------------------
// SwOLENode
// --------------------

class SwOLENode: public SwNoTxtNode
{
    friend class SwNodes;
    mutable SwOLEObj aOLEObj;
    Graphic*    pGraphic;
    sal_Int64   nViewAspect;
    String sChartTblName;       // bei Chart Objecten: Name der ref. Tabelle
    BOOL   bOLESizeInvalid;     //Soll beim SwDoc::PrtOLENotify beruecksichtig
                                //werden (zum Beispiel kopiert). Ist nicht
                                //Persistent.

    SwOLENode(  const SwNodeIndex &rWhere,
                const svt::EmbeddedObjectRef&,
                SwGrfFmtColl *pGrfColl,
                SwAttrSet* pAutoAttr = 0 );

    SwOLENode(  const SwNodeIndex &rWhere,
                const String &rName,
                SwGrfFmtColl *pGrfColl,
                SwAttrSet* pAutoAttr = 0 );

    // aOLEObj besitzt einen privaten Copy-CTOR, wir brauchen auch einen:
    SwOLENode( const SwOLENode & );

public:
    const SwOLEObj& GetOLEObj() const { return aOLEObj; }
          SwOLEObj& GetOLEObj()       { return aOLEObj; }
    ~SwOLENode();

    virtual SwCntntNode *SplitNode( const SwPosition & );
        // steht in ndcopy.cxx
    virtual SwCntntNode* MakeCopy( SwDoc*, const SwNodeIndex& ) const;

    virtual Size GetTwipSize() const;
    Graphic* GetGraphic();
    void GetNewReplacement();

    virtual BOOL SavePersistentData();
    virtual BOOL RestorePersistentData();

    BOOL IsInGlobalDocSection() const;
    BOOL IsOLEObjectDeleted() const;

    BOOL IsOLESizeInvalid() const   { return bOLESizeInvalid; }
    void SetOLESizeInvalid( BOOL b ){ bOLESizeInvalid = b; }

    sal_Int64 GetAspect() const { return nViewAspect; }
    void SetAspect( sal_Int64 nAspect) { nViewAspect = nAspect; }

    // OLE-Object aus dem "Speicher" entfernen
    // inline void Unload() { aOLEObj.Unload(); }
    String GetDescription() const { return aOLEObj.GetDescription(); }

#ifndef _FESHVIEW_ONLY_INLINE_NEEDED
    const String& GetChartTblName() const       { return sChartTblName; }
    void SetChartTblName( const String& rNm )   { sChartTblName = rNm; }
#endif
};

// Inline Metoden aus Node.hxx - erst hier ist der TxtNode bekannt !!
inline SwOLENode *SwNode::GetOLENode()
{
     return ND_OLENODE == nNodeType ? (SwOLENode*)this : 0;
}
inline const SwOLENode *SwNode::GetOLENode() const
{
     return ND_OLENODE == nNodeType ? (const SwOLENode*)this : 0;
}

#endif  // _NDOLE_HXX

<commit_msg>INTEGRATION: CWS mav14 (1.8.158); FILE MERGED 2005/01/06 14:07:41 mav 1.8.158.4: #i35475# support embedded links 2005/01/06 13:19:37 mav 1.8.158.3: #i35475# support embedded links 2004/12/09 20:28:43 mav 1.8.158.2: RESYNC: (1.8-1.9); FILE MERGED 2004/12/01 11:20:22 mav 1.8.158.1: #i35475# handle embedded links by link dialog<commit_after>/*************************************************************************
 *
 *  $RCSfile: ndole.hxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: kz $ $Date: 2005-01-18 14:57:51 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _NDOLE_HXX
#define _NDOLE_HXX

#ifndef _NDNOTXT_HXX
#include <ndnotxt.hxx>
#endif

#include <svtools/embedhlp.hxx>

class SwGrfFmtColl;
class SwDoc;
class SwOLENode;
class SwOLELink;

class SwOLEListener_Impl;
class SwEmbedObjectLink;
class SwOLEObj
{
    friend class SwOLENode;

    const SwOLENode* pOLENd;
    SwOLEListener_Impl* pListener;

    //Entweder Ref oder Name sind bekannt, wenn nur der Name bekannt ist, wird
    //dir Ref bei Anforderung durch GetOleRef() vom Sfx besorgt.
    svt::EmbeddedObjectRef xOLERef;
    String aName;

    SwOLEObj( const SwOLEObj& rObj );   //nicht erlaubt.
    SwOLEObj();

    void SetNode( SwOLENode* pNode );

public:
    SwOLEObj( const svt::EmbeddedObjectRef& pObj );
    SwOLEObj( const String &rName );
    ~SwOLEObj();

    BOOL UnloadObject();
    String GetDescription();

#ifndef _FESHVIEW_ONLY_INLINE_NEEDED
    com::sun::star::uno::Reference < com::sun::star::embed::XEmbeddedObject > GetOleRef();
    svt::EmbeddedObjectRef& GetObject();
    const String& GetCurrentPersistName() const { return aName; }
    BOOL IsOleRef() const;  //Damit das Objekt nicht unnoetig geladen werden muss.
#endif
};

// --------------------
// SwOLENode
// --------------------

class SwOLENode: public SwNoTxtNode
{
    friend class SwNodes;
    mutable SwOLEObj aOLEObj;
    Graphic*    pGraphic;
    sal_Int64   nViewAspect;
    String sChartTblName;       // bei Chart Objecten: Name der ref. Tabelle
    BOOL   bOLESizeInvalid;     //Soll beim SwDoc::PrtOLENotify beruecksichtig
                                //werden (zum Beispiel kopiert). Ist nicht
                                //Persistent.

    SwEmbedObjectLink*  mpObjectLink;
    String maLinkURL;

    SwOLENode(  const SwNodeIndex &rWhere,
                const svt::EmbeddedObjectRef&,
                SwGrfFmtColl *pGrfColl,
                SwAttrSet* pAutoAttr = 0 );

    SwOLENode(  const SwNodeIndex &rWhere,
                const String &rName,
                SwGrfFmtColl *pGrfColl,
                SwAttrSet* pAutoAttr = 0 );

    // aOLEObj besitzt einen privaten Copy-CTOR, wir brauchen auch einen:
    SwOLENode( const SwOLENode & );

public:
    const SwOLEObj& GetOLEObj() const { return aOLEObj; }
          SwOLEObj& GetOLEObj()       { return aOLEObj; }
    ~SwOLENode();

    virtual SwCntntNode *SplitNode( const SwPosition & );
        // steht in ndcopy.cxx
    virtual SwCntntNode* MakeCopy( SwDoc*, const SwNodeIndex& ) const;

    virtual Size GetTwipSize() const;
    Graphic* GetGraphic();
    void GetNewReplacement();

    virtual BOOL SavePersistentData();
    virtual BOOL RestorePersistentData();

    BOOL IsInGlobalDocSection() const;
    BOOL IsOLEObjectDeleted() const;

    BOOL IsOLESizeInvalid() const   { return bOLESizeInvalid; }
    void SetOLESizeInvalid( BOOL b ){ bOLESizeInvalid = b; }

    sal_Int64 GetAspect() const { return nViewAspect; }
    void SetAspect( sal_Int64 nAspect) { nViewAspect = nAspect; }

    // OLE-Object aus dem "Speicher" entfernen
    // inline void Unload() { aOLEObj.Unload(); }
    String GetDescription() const { return aOLEObj.GetDescription(); }

    sal_Bool UpdateLinkURL_Impl();
    void BreakFileLink_Impl();
    void DisconnectFileLink_Impl();

    void CheckFileLink_Impl();

#ifndef _FESHVIEW_ONLY_INLINE_NEEDED
    const String& GetChartTblName() const       { return sChartTblName; }
    void SetChartTblName( const String& rNm )   { sChartTblName = rNm; }
#endif
};

// Inline Metoden aus Node.hxx - erst hier ist der TxtNode bekannt !!
inline SwOLENode *SwNode::GetOLENode()
{
     return ND_OLENODE == nNodeType ? (SwOLENode*)this : 0;
}
inline const SwOLENode *SwNode::GetOLENode() const
{
     return ND_OLENODE == nNodeType ? (const SwOLENode*)this : 0;
}

#endif  // _NDOLE_HXX

<|endoftext|>