diff --git a/wb/lib/wb/src/wb_print_wbl.cpp b/wb/lib/wb/src/wb_print_wbl.cpp
index ebc5eed3334dd9c205c0f5bd75b1f72ebef24837..24a2deee24869536b4b02cd64377fcd8905648ac 100644
--- a/wb/lib/wb/src/wb_print_wbl.cpp
+++ b/wb/lib/wb/src/wb_print_wbl.cpp
@@ -1,38 +1,38 @@
-/*
- * ProviewR   Open Source Process Control.
- * Copyright (C) 2005-2019 SSAB EMEA AB.
+/* 
+ * Proview   Open Source Process Control.
+ * Copyright (C) 2005-2017 SSAB EMEA AB.
  *
- * This file is part of ProviewR.
+ * This file is part of Proview.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 2 of
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation, either version 2 of 
  * the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * This program is distributed in the hope that it will be useful 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with ProviewR. If not, see <http://www.gnu.org/licenses/>
+ * You should have received a copy of the GNU General Public License 
+ * along with Proview. If not, see <http://www.gnu.org/licenses/>
  *
- * Linking ProviewR statically or dynamically with other modules is
- * making a combined work based on ProviewR. Thus, the terms and
- * conditions of the GNU General Public License cover the whole
+ * Linking Proview statically or dynamically with other modules is
+ * making a combined work based on Proview. Thus, the terms and 
+ * conditions of the GNU General Public License cover the whole 
  * combination.
  *
  * In addition, as a special exception, the copyright holders of
- * ProviewR give you permission to, from the build function in the
- * ProviewR Configurator, combine ProviewR with modules generated by the
- * ProviewR PLC Editor to a PLC program, regardless of the license
+ * Proview give you permission to, from the build function in the
+ * Proview Configurator, combine Proview with modules generated by the
+ * Proview PLC Editor to a PLC program, regardless of the license
  * terms of these modules. You may copy and distribute the resulting
- * combined work under the terms of your choice, provided that every
- * copy of the combined work is accompanied by a complete copy of
- * the source code of ProviewR (the version used to produce the
- * combined work), being distributed under the terms of the GNU
+ * combined work under the terms of your choice, provided that every 
+ * copy of the combined work is accompanied by a complete copy of 
+ * the source code of Proview (the version used to produce the 
+ * combined work), being distributed under the terms of the GNU 
  * General Public License plus this exception.
- */
+ **/
 
 /**
  * @file wb_print_wbl.cpp
@@ -41,46 +41,392 @@
  *
  */
 
+#include <cfloat>
 #include <assert.h>
 #include <stdio.h>
+#include <ostream>
+#include <cstring>
+
+#include "wb_print_wbl.h"
 
 #include "pwr_version.h"
-#include "co_string.h"
 #include "co_time.h"
+#include "co_cdh.h"
 
-#include "wb_print_wbl.h"
+#include "wb_attribute.h"
+#include "wb_object.h"
 #include "wb_volume.h"
-
-wb_print_wbl::wb_print_wbl(std::ostream& os, int levelIndentation)
-    : m_errCnt(0), m_lineCnt(0), m_idxFlag(true), m_noFoCodeFlag(false),
-      m_timeFlag(true), m_level(0), m_levelInd(levelIndentation),
-      m_keepName(false), m_isTemplateObject(false), m_os(os), m_body_cache(0)
+#include "wb_bdef.h"
+
+wb_print_wbl::wb_print_wbl(ostream& os, int levelIndentation) :
+  m_errCnt(0),
+  m_idxFlag(true),
+  m_noFoCodeFlag(false),
+  m_timeFlag(true),
+  m_level(0),
+  m_levelInd(levelIndentation),
+  m_keepName(false),
+  m_isTemplateObject(false),
+  m_os(os)
 {
   memset(m_indBuf, ' ', sizeof(m_indBuf));
-  m_indBuf[sizeof(m_indBuf) - 1] = 0;
+  m_indBuf[sizeof(m_indBuf) -1] = 0;
 }
 
+
 wb_print_wbl::~wb_print_wbl()
 {
-  printf("-- Writing line: %d\n", m_lineCnt);
-  bodyCacheFree();
 }
 
+
+
+
+
+
+
+//
+// printAttribute
+//
+void wb_print_wbl::printAttribute(wb_volume& v, 
+                                  wb_attribute& attr, 
+                                  wb_attribute& tattr, ///< template 
+                                  wb_adef& adef, 
+				  int force)
+{
+  if ( !force &&
+       (adef.flags() & PWR_MASK_POINTER || 
+	adef.flags() & PWR_MASK_NOWBL))
+    return;
+
+  if (attr.isClass() && adef.cid() == pwr_eClass_Buffer)
+    printBuffer(v, attr, tattr, adef);
+  else if (attr.isClass())
+    printClass(v, attr, tattr, adef);
+  else {
+    switch (adef.cid()) {
+    case pwr_eClass_Param:
+    case pwr_eClass_Input:
+    case pwr_eClass_Intern:
+    case pwr_eClass_Output:
+    case pwr_eClass_ObjXRef:
+      printParameter(v, attr, tattr, adef);
+      break;
+    default:
+      m_os << "! %%WBDUMP-E-Error Unknown attribute class: " 
+           << adef.name() << ", cid: " << adef.cid() << endl;
+      m_errCnt++;
+      break;
+    }
+  }
+  
+}
+
+//
+// printBody
+//
+void wb_print_wbl::printBody(wb_volume& v, 
+                             wb_object& o, 
+                             wb_object& templ,
+                             wb_cdef& cdef,
+                             pwr_eBix bix)
+{
+  wb_adef adef;
+  wb_attribute attr;
+  wb_attribute tattr;
+  const char* bname;
+  char timestr[40] = " ";
+  int force = 0;
+    
+  wb_bdef bdef = cdef.bdef(bix);
+    
+
+  if (!bdef)
+    return;
+
+  bname = bdef.name();
+
+  wb_bdef tbdef = templ.bdef(bix);
+  if (!tbdef) {
+    m_errCnt++;
+    m_os << "Couldn't find template body def for object " << o.name() << endl;
+    return;
+  }
+    
+  if ( m_timeFlag) {
+    // Get body time
+    pwr_tTime btime;
+    switch ( bix) {
+    case pwr_eBix_rt:
+      btime = o.rbTime();
+
+      // Bugcheck in 4.2 btime can be corrupt
+      if ( btime.tv_nsec < 0 || btime.tv_nsec >= 1000000000)
+	break;
+
+      strcpy( timestr, " ");
+      time_AtoAscii( &btime, time_eFormat_DateAndTime, &timestr[1], sizeof(timestr)-1);
+      break;
+    case pwr_eBix_dev:
+      btime = o.dbTime();
+      strcpy( timestr, " ");
+      time_AtoAscii( &btime, time_eFormat_DateAndTime, &timestr[1], sizeof(timestr)-1);
+      break;
+    default: ;
+    }
+  }
+
+  indent(1) << "Body " << bdef.name() << timestr << endl;
+  for (adef = bdef.adef(); adef; adef = adef.next()) {
+    if ( cdef.cid() == pwr_eClass_Param && strcmp( adef.name(), "Size") == 0) {
+      // Print Size for Pointers that is not private
+      wb_attribute flags_attr = o.attribute(bname, "Flags");
+      pwr_tMask *flagsp = (pwr_tMask *)flags_attr.value();
+      if (*flagsp & PWR_MASK_POINTER && !(*flagsp & PWR_MASK_PRIVATE))
+	force = 1;
+    }
+
+    attr = o.attribute(bname, adef.name());
+    tattr = templ.attribute(bname, adef.name());
+    //    if (tattr == attr)
+    //  continue;
+    printAttribute(v, attr, tattr, adef, force);
+  }
+
+  indent(-1) << "EndBody" << endl;
+    
+  return;
+}
+
+
+//
+// printBuffer
+//
+void wb_print_wbl::printBuffer(wb_volume& v,
+                              wb_attribute& attr,
+                              wb_attribute& tattr,
+                              wb_adef& adef) 
+{
+  pwr_tCid subClass = attr.subClass();
+  wb_object templ;
+  wb_object sysbo;
+  wb_attribute tattr2;
+  wb_attribute attr2;
+  wb_adef adef2;
+  const char* bname;
+
+  if ( strcmp( attr.name(), "Template") == 0 && cdh_isClassVolumeClass( v.cid()))
+    // The parser can't handle subclasses in template objects yet...
+    return;
+
+  wb_object co = v.object(cdh_ClassIdToObjid(subClass));
+  if (!co) {
+    m_os << "! %WBDUMP-E-Error Unknown sub class: " << subClass << endl;
+    m_errCnt++;
+    return;
+  }
+
+  wb_cdef cdef = v.cdef(subClass);
+  if (!cdef) {
+    m_os << "! %WBDUMP-E-Error Unknown sub class: " << subClass << endl;
+    m_errCnt++;
+    return;
+  }
+
+  wb_name t("Template");
+  
+  templ = co.child(t);
+  if (!templ) {
+    m_errCnt++;
+    m_os << "! %WBDUMP-E-Error Template not found for class " << cdef.longName() << endl;
+    return;
+  }
+
+  wb_bdef bdef = cdef.bdef(pwr_eBix_sys);
+  if (!bdef) {
+    m_os << "! %WBDUMP-E-Error sub class: " << subClass 
+         << " not defined" << endl;
+    m_errCnt++;
+    return;
+  }    
+  bname = bdef.name();
+
+  for (int i = 0; i < adef.nElement(); i++) {
+    if (adef.flags() & PWR_MASK_ARRAY)
+      indent(1) << "Buffer " << adef.name() << "[" << i << "]" << endl;
+    else
+      indent(1) << "Buffer " << adef.name() << endl;
+
+
+    adef2 = bdef.adef(); 
+    attr2 = attr.first(i);
+    
+    while (1) {
+      tattr2 = templ.attribute(bname, adef2.name());
+      printAttribute(v, attr2, tattr2, adef2, 0);
+
+      if (!(adef2 = adef2.next()))
+        break;
+      
+      if (!(attr2 = attr2.after()))
+        break;
+    }                   
+
+    indent(-1) << "EndBuffer" << endl;
+  }
+}
+
+//
+// printClass
+//
+void wb_print_wbl::printClass(wb_volume& v,
+                              wb_attribute& attr,
+                              wb_attribute& tattr,
+                              wb_adef& adef) 
+{
+  pwr_tCid subClass = attr.subClass();
+  wb_object templ;
+  wb_object sysbo;
+  wb_attribute tattr2;
+  wb_attribute attr2;
+  wb_adef adef2;
+
+  //  if ( strcmp( attr.name(), "Template") == 0 && v.cid() == pwr_eClass_ClassVolume)
+    // The parser can't handle subclasses in template objects yet...
+  //  return;
+
+  wb_cdef cdef = v.cdef(attr.cid());
+  if (!cdef) {
+    m_os << "! %WBDUMP-E-Error Unknown sub class: " << subClass << endl;
+    m_errCnt++;
+    return;
+  }
+
+  wb_bdef bdef = cdef.bdef(pwr_eBix_sys);
+  if (!bdef) {
+    m_os << "! %WBDUMP-E-Error sub class: " << subClass 
+         << " not defined" << endl;
+    m_errCnt++;
+    return;
+  }    
+
+  for (int i = 0; i < adef.nElement(); i++) {
+    attr2 = attr.first(i);
+    tattr2 = tattr.first(i);
+  
+    while ( attr2.oddSts()) {
+
+      adef2 = bdef.adef( attr2.attrName()); 
+      
+      printAttribute(v, attr2, tattr2, adef2, 0);
+    
+      attr2 = attr2.after();
+      if ( tattr2.oddSts())
+	tattr2 = tattr2.after();
+    }
+  }
+
+#if 0
+  wb_object co = v.object(cdh_ClassIdToObjid(subClass));
+  if (!co) {
+    m_os << "! %WBDUMP-E-Error Unknown sub class: " << subClass << endl;
+    m_errCnt++;
+    return;
+  }
+
+  wb_cdef cdef = v.cdef(subClass);
+  if (!cdef) {
+    m_os << "! %WBDUMP-E-Error Unknown sub class: " << subClass << endl;
+    m_errCnt++;
+    return;
+  }
+
+  wb_name t("Template");
+  
+  templ = co.child(t);
+  if (!templ) {
+    m_errCnt++;
+    m_os << "! %WBDUMP-E-Error Template not found for class " << cdef.longName() << endl;
+    return;
+  }
+
+  wb_bdef bdef = cdef.bdef(pwr_eBix_sys);
+  if (!bdef) {
+    m_os << "! %WBDUMP-E-Error sub class: " << subClass 
+         << " not defined" << endl;
+    m_errCnt++;
+    return;
+  }    
+  bname = bdef.name();
+
+  for (int i = 0; i < adef.nElement(); i++) {
+
+    if (adef.flags() & PWR_MASK_ARRAY)
+      indent(1) << "Buffer " << adef.name() << "[" << i << "]" << endl;
+    else
+      indent(1) << "Buffer " << adef.name() << endl;
+
+
+    adef2 = bdef.adef(); 
+    attr2 = attr.first(i);
+    
+    while (1) {
+      tattr2 = templ.attribute(bname, adef2.name());
+      printAttribute(v, attr2, tattr2, adef2, 0);
+
+      if (!(adef2 = adef2.next()))
+        break;
+      
+      if (!(attr2 = attr2.after()))
+        break;
+    }                   
+
+    indent(-1) << "EndBuffer" << endl;
+
+    if (adef.flags() & PWR_MASK_ARRAY)
+      indent(1) << "Buffer " << adef.name() << "[" << i << "]" << endl;
+    else
+      indent(1) << "Buffer " << adef.name() << endl;
+
+
+    adef2 = bdef.adef(); 
+    attr2 = attr.first(i);
+    
+    while (1) {
+      strcpy( aname, adef.subName());
+      strcat( aname, ".");
+      strcat( aname, attr2.name());
+
+      attr2
+      tattr2 = templ.attribute(bname, adef2.name());
+      printAttribute(v, attr2, tattr2, adef2, 0);
+
+      if (!(adef2 = adef2.next()))
+        break;
+      
+      if (!(attr2 = attr2.after()))
+        break;
+    }                   
+
+  }
+#endif
+}
+
 //
 // printHierarchy
 //
 void wb_print_wbl::printHierarchy(wb_volume& v, wb_object& o)
 {
   if (v.object() == o)
-    indent(1) << "SObject " << v.name() << ":\n";
+    indent(1) << "SObject " << v.name() << ":" << endl;
   else
-    indent(1) << "SObject " << o.parent().longName() << '\n';
-
+    indent(1) << "SObject " << o.parent().longName() << endl;
+  
   printObject(v, o);
-
-  indent(-1) << "EndSObject\n";
+  
+  indent(-1) << "EndSObject" << endl;
 }
 
+
 //
 // printObject
 //
@@ -88,32 +434,32 @@ void wb_print_wbl::printObject(wb_volume& v, wb_object& o, bool recursive)
 {
   wb_object to = o;
   wb_object templ;
-  cdh_uObjid uid;
+  cdh_uObjid	uid;
   unsigned int idx;
   wb_cdef cdef = v.cdef(o);
-  if (!cdef) {
-    m_os << "! %WBDUMP-E-Error Failed to get object class\n";
+  if ( !cdef) {
+    m_os << "! %WBDUMP-E-Error Failed to get object class" << endl;
     m_errCnt++;
     // return;
-    cdef = v.cdef(pwr_eClass_ClassLost);
+    cdef = v.cdef( pwr_eClass_ClassLost);
   }
   const char* cname = cdef.name();
-  char* block;
+  char *block;
   int size;
 
-  if (o.docBlock(&block, &size) && !streq(block, "")) {
-    indent(0) << "!/**\n";
+  if ( o.docBlock( &block, &size) && strcmp( block, "") != 0) {
+    indent(0) << "!/**" << endl;
     indent(0) << "! ";
-    for (char* s = block; *s; s++) {
-      if (*s == '\n') {
-        m_os << *s;
-        indent(0) << "! ";
-        continue;
+    for ( char *s = block; *s; s++) {
+      if ( *s == '\n') {
+	m_os << *s;
+	indent(0) << "! ";
+	continue;
       }
       m_os << *s;
     }
-    m_os << '\n';
-    indent(0) << "!*/\n";
+    m_os << endl;
+    indent(0) << "!*/" << endl;
   }
 
   indent(1) << "Object " << o.name() << " " << cname;
@@ -142,163 +488,182 @@ void wb_print_wbl::printObject(wb_volume& v, wb_object& o, bool recursive)
       idx = uid.c.aix;
       break;
     default:
-      idx = (unsigned long)o.oix();
+      idx = (unsigned long) o.oix();
     }
     m_os << " " << idx;
   }
-  if (m_timeFlag) {
+  if ( m_timeFlag) {
     // Get oh time
     char timestr[40];
     pwr_tTime ohtime = o.ohTime();
-    time_AtoAscii(&ohtime, time_eFormat_DateAndTime, timestr, sizeof(timestr));
+    time_AtoAscii( &ohtime, time_eFormat_DateAndTime, timestr, sizeof(timestr));
 
     m_os << " " << timestr;
   }
-  m_os << '\n';
+  m_os << endl;
 
   wb_object co = v.object(cdh_ClassIdToObjid(cdef.cid()));
   wb_name t("Template");
-
+  
   templ = co.child(t);
   if (!templ) {
     m_errCnt++;
-    m_os << "Template not found for class " << cdef.name() << '\n';
+    m_os << "Template not found for class " << cdef.name() << endl;
     return;
   }
 
-  if (v.cid() == pwr_eClass_ClassVolume && streq(o.name(), "Template"))
+  if ( v.cid() == pwr_eClass_ClassVolume &&
+       strcmp( o.name(), "Template") == 0)
     m_isTemplateObject = true;
   else
     m_isTemplateObject = false;
-
-  printBody(v, o.oid(), templ.oid(), cdef.cid(), pwr_eBix_rt);
-  printBody(v, o.oid(), templ.oid(), cdef.cid(), pwr_eBix_dev);
+  
+ 
+  printBody(v, o, templ, cdef, pwr_eBix_rt);
+  printBody(v, o, templ, cdef, pwr_eBix_dev);
 
   if (recursive) {
-    if (!(m_noFoCodeFlag && isFoCodeObject(v, o))) {
+    if ( !(m_noFoCodeFlag && isFoCodeObject( v, o))) {
       for (to = o.first(); to; to = to.after())
-        printObject(v, to);
+	printObject(v, to);
     }
-  }
+  }    
 
-  indent(-1) << "EndObject\n";
+  indent(-1) << "EndObject" << endl;
 }
-
+
 //
-// printVolume
+// printParameter
 //
-void wb_print_wbl::printVolume(wb_volume& v, bool recursive)
+void wb_print_wbl::printParameter(wb_volume& v, 
+                                  wb_attribute& attr, 
+                                  wb_attribute& tattr, ///< template 
+                                  wb_adef& adef)
 {
-  if (!v) {
-    m_os << "%WBDUMP-E-Error Not a valid volume\n";
+
+  int nElement = adef.nElement();
+  int varSize = adef.size() / nElement;
+  char* valueb = (char *)attr.value();
+  char* val;
+  char* tvalueb;
+  char* tval;
+  char* svalp;
+  int varOffset;
+  bool parValOk;
+  bool print_all = false;
+  const char* name = adef.subName();   
+
+  if (valueb == NULL) {
+    m_os << "! %WBDUMP-E-Error Failed to get attribute address for " 
+         << adef.name() << endl;
     m_errCnt++;
     return;
   }
 
-  char timstr[40];
-  time_AtoAscii(0, time_eFormat_DateAndTime, timstr, sizeof(timstr));
-  indent() << "!     Generated by wb_print_wbl " << timstr << "\n";
-  indent() << "!     Volume " << v.name() << " \n";
-  indent() << "!     Version " pwrv_cPwrVersionStr "\n";
-
-  wb_object o = v.object();
-  const char* cname = v.cdef(v.cid()).name();
-
-  indent(1) << "Volume " << v.name() << " " << cname << " "
-            << cdh_VolumeIdToString(0, 0, v.vid(), 0, 0) << " \n";
-
-  // Print volume body
-  pwr_tOid oid;
-  oid.vid = v.vid();
-  oid.oix = 0;
-  wb_object vo = v.object(oid);
-  wb_cdef cdef = v.cdef(vo);
-
-  wb_object co = v.object(cdh_ClassIdToObjid(v.cid()));
-  wb_name t("Template");
-
-  wb_object templ = co.child(t);
-  if (!templ) {
-    m_errCnt++;
-    m_os << "Template not found for class " << cdef.name() << '\n';
+  if (adef.type() == pwr_eType_Text) {
+    printText(v, adef, valueb, adef.size());
     return;
   }
-  printBody(v, oid, templ.oid(), cdef.cid(), pwr_eBix_sys);
 
-  // Print top objects and their children
-  if (recursive) {
-    for (; o; o = o.after())
-      printObject(v, o, recursive);
+  if ( tattr.evenSts()) {
+    // Template attribute not found, should not happen
+    tvalueb = (char *)calloc( 1, attr.size());
+    print_all = true;
   }
+  else if ( attr == tattr || m_isTemplateObject)
+    // This is the template object itself, print all nonzero
+    tvalueb = (char *)calloc( 1, tattr.size());
+  else
+    tvalueb = (char *)tattr.value();
+
+  for (int i = 0; i < nElement; i++) {
+    switch (adef.type()) {
+    case pwr_eType_Boolean:
+    case pwr_eType_Float32:
+    case pwr_eType_Float64:
+    case pwr_eType_Char:
+    case pwr_eType_String:
+    case pwr_eType_ProString:
+    case pwr_eType_Int8:
+    case pwr_eType_Int16:
+    case pwr_eType_Int32:
+    case pwr_eType_Int64:
+    case pwr_eType_UInt8:
+    case pwr_eType_UInt16:
+    case pwr_eType_UInt32:
+    case pwr_eType_UInt64:
+    case pwr_eType_Objid:
+    case pwr_eType_TypeId:
+    case pwr_eType_CastId:
+    case pwr_eType_DisableAttr:
+    case pwr_eType_ClassId:
+    case pwr_eType_AttrRef:
+    case pwr_eType_Time:
+    case pwr_eType_VolumeId:
+    case pwr_eType_ObjectIx:
+    case pwr_eType_RefId:
+    case pwr_eType_DeltaTime:
+    case pwr_eType_Mask:
+    case pwr_eType_Enum:
+    case pwr_eType_Status:
+    case pwr_eType_NetStatus:
+    case pwr_eType_DataRef:
+      varOffset = varSize * i;
+      val = valueb + varOffset;
+      tval = tvalueb + varOffset;
+            
+      if (memcmp(val, tval, varSize) == 0 && !(adef.flags() & PWR_MASK_ALWAYSWBL) && !print_all)
+        continue;
 
-  indent(-1) << "EndVolume\n";
-}
-
-//
-// indent
-//
-std::ostream& wb_print_wbl::indent(int levelIncr)
-{
-  m_lineCnt++;
-  if (m_lineCnt == 0)
-    printf("\n");
-  if (m_lineCnt % 1000 == 0) {
-    printf("-- Writing line: %d\r", m_lineCnt);
-    fflush(stdout);
+      parValOk = printValue(v, adef, val, varSize, &svalp);
+      if (parValOk)
+        indent();
+      else
+        m_os << "! %WBDUMP-E-Error ";
+      
+      if (adef.flags() & PWR_MASK_ARRAY) {
+        m_os << "Attr " << name << "[" << i << "] = " << svalp << endl;
+      } else {
+        m_os << "Attr " << name << " = " << svalp << endl;
+      }
+      break;
+    case pwr_eType_Array:
+      m_os << "! %WBDUMP-E-Error Type pwr_eType_Array is not yet implemented" << endl;
+      m_errCnt++;
+      break;
+    case pwr_eType_Buffer:
+      m_os << "! %WBDUMP-E-Error Type pwr_eType_Buffer is not yet implemented" << endl; 
+      m_errCnt++;
+      break;
+    case pwr_eType_Struct:
+      m_os << "! %WBDUMP-E-Error Type pwr_eType_Struct is not yet implemented" << endl;
+      m_errCnt++;
+      break;
+    default:
+      m_os << "! %WBDUMP-E-Error Attribute " << adef.name() 
+           << " is of unknown type: " <<  adef.type() <<  endl;
+      m_errCnt++;
+      break;
+    }
   }
-
-  if (levelIncr < 0)
-    m_level += levelIncr;
-
-  assert(m_level >= 0);
-
-  m_indBuf[m_level * m_levelInd] = '\0';
-
-  m_os << m_indBuf;
-
-  m_indBuf[m_level * m_levelInd] = ' ';
-
-  if (levelIncr > 0)
-    m_level += levelIncr;
-
-  return m_os;
+  if ( tattr.evenSts() || attr == tattr)
+    free( tvalueb);
 }
-
-bool wb_print_wbl::isFoCodeObject(wb_volume& v, wb_object& o)
-{
-  pwr_tInt32 compmethod;
-
-  // Check if object has GraphPlcNode body and compmethod 58
-  wb_cdef cd = v.cdef(o);
-  if (!cd)
-    return false;
-
-  wb_object go = cd.classBody("GraphPlcNode");
-  if (!go)
-    return false;
-
-  wb_attribute a = v.attribute(go, "compmethod");
-  if (!a)
-    return false;
-
-  a.value(&compmethod);
-
-  if (compmethod == 58)
-    return true;
-  return false;
-}
-
+
 //
 // printText
 //
-void wb_print_wbl::printText(
-    wb_volume& v, const char* aname, const char* text, int varSize)
+void wb_print_wbl::printText(wb_volume& v, 
+                             wb_adef& adef,
+                             const char *text,
+                             int varSize)
 {
   const char* ip;
   int i;
   int end = varSize - 1;
+  const char* name = adef.subName();   
 
-  indent() << "Attr " << aname << " = \"";
+  indent() << "Attr " << name << " = \"";
 
   for (ip = text, i = 0; *ip != 0 && i < end; ip++) {
     if (*ip == '"')
@@ -307,17 +672,21 @@ void wb_print_wbl::printText(
       m_os << "\\";
     m_os << *ip;
   }
-
-  m_os << "\"\n";
-
-  return;
+    
+  m_os << "\"" << endl;
+    
+  return;      
 }
 
+
 //
 // printValue
 //
-bool wb_print_wbl::printValue(wb_volume& v, pwr_eType type, unsigned int flags,
-    void* val, int varSize, char** svalp)
+bool wb_print_wbl::printValue (wb_volume& v,
+                               wb_adef& adef,
+                               void *val,
+                               int varSize,
+                               char **svalp) 
 {
   unsigned long sts;
   char timbuf[24];
@@ -326,96 +695,94 @@ bool wb_print_wbl::printValue(wb_volume& v, pwr_eType type, unsigned int flags,
   bool retval = true;
   pwr_tOid oid;
   wb_object o;
+  
 
   sval[0] = '\0';
 
-  if (flags & PWR_MASK_POINTER) {
-    sprintf(sval, "%u", *(unsigned int*)val);
+  if (adef.flags() & PWR_MASK_POINTER) {
+    sprintf(sval, "%u", *(unsigned int *) val);
     *svalp = sval;
     return TRUE;
   }
 
-  switch (type) {
+  switch (adef.type()) {
   case pwr_eType_Boolean:
-    sprintf(sval, "%d", *(pwr_tBoolean*)val);
+    sprintf(sval, "%d", *(pwr_tBoolean *) val);
     break;
   case pwr_eType_Float32:
-    if (*(pwr_tFloat32*)val == FLT_MIN)
-      strcpy(sval, "FLT_MIN");
-    else if (*(pwr_tFloat32*)val == FLT_MAX)
-      strcpy(sval, "FLT_MAX");
+    if ( *(pwr_tFloat32 *)val == FLT_MIN)
+      strcpy( sval, "FLT_MIN");
+    else if ( *(pwr_tFloat32 *)val == FLT_MAX)
+      strcpy( sval, "FLT_MAX");
     else
-      sprintf(sval, "%.*e", FLT_DIG, *(pwr_tFloat32*)val);
+      sprintf(sval, "%.*e", FLT_DIG, *(pwr_tFloat32 *) val);
     break;
   case pwr_eType_Float64:
-    sprintf(sval, "%.*e", DBL_DIG, *(pwr_tFloat64*)val);
+    sprintf(sval, "%.*e", DBL_DIG, *(pwr_tFloat64 *) val);
     break;
   case pwr_eType_Char:
-    if (*(pwr_tChar*)val == 0)
+    if (*(pwr_tChar *) val == 0)
       sprintf(sval, "\"\"");
     else
-      sprintf(sval, "\"%c\"", *(pwr_tChar*)val);
+      sprintf(sval, "\"%c\"", *(pwr_tChar *) val);
     break;
   case pwr_eType_Int8:
-    sprintf(sval, "%d", *(pwr_tInt8*)val);
+    sprintf(sval, "%d", *(pwr_tInt8 *) val);
     break;
   case pwr_eType_Int16:
-    sprintf(sval, "%d", *(pwr_tInt16*)val);
+    sprintf(sval, "%d", *(pwr_tInt16 *) val);
     break;
   case pwr_eType_Int32:
-    if (*(pwr_tInt32*)val == INT_MIN)
-      strcpy(sval, "INT_MIN");
-    else if (*(pwr_tInt32*)val == INT_MAX)
-      strcpy(sval, "INT_MAX");
+    if ( *(pwr_tInt32 *)val == INT_MIN)
+      strcpy( sval, "INT_MIN");
+    else if ( *(pwr_tInt32 *)val == INT_MAX)
+      strcpy( sval, "INT_MAX");
     else
-      sprintf(sval, "%d", *(pwr_tInt32*)val);
+      sprintf(sval, "%d", *(pwr_tInt32 *) val);
     break;
   case pwr_eType_Int64:
-    sprintf(sval, pwr_dFormatInt64, *(pwr_tInt64*)val);
+    sprintf(sval, pwr_dFormatInt64, *(pwr_tInt64 *) val);
     break;
   case pwr_eType_UInt8:
-    sprintf(sval, "%u", *(pwr_tUInt8*)val);
+    sprintf(sval, "%u", *(pwr_tUInt8 *) val);
     break;
   case pwr_eType_UInt16:
-    sprintf(sval, "%u", *(pwr_tUInt16*)val);
+    sprintf(sval, "%u", *(pwr_tUInt16 *) val);
     break;
   case pwr_eType_UInt32:
   case pwr_eType_DisableAttr:
-    sprintf(sval, "%u", *(pwr_tUInt32*)val);
+    sprintf(sval, "%u", *(pwr_tUInt32 *) val);
     break;
   case pwr_eType_UInt64:
-    sprintf(sval, pwr_dFormatUInt64, *(pwr_tUInt64*)val);
+    sprintf(sval, pwr_dFormatUInt64, *(pwr_tUInt64 *) val);
     break;
   case pwr_eType_Mask:
-    sprintf(sval, "%u", *(pwr_tUInt32*)val);
+    sprintf(sval, "%u", *(pwr_tUInt32 *) val);
     break;
   case pwr_eType_Enum:
-    sprintf(sval, "%u", *(pwr_tUInt32*)val);
+    sprintf(sval, "%u", *(pwr_tUInt32 *) val);
     break;
   case pwr_eType_RefId:
     sprintf(sval, "0");
     break;
   case pwr_eType_Objid:
-    if (cdh_ObjidIsNull(*(pwr_tOid*)val))
+    if (cdh_ObjidIsNull(*(pwr_tOid *) val))
       sprintf(sval, "\"_O0.0.0.0:0\"");
     else {
-      o = v.object(*(pwr_tOid*)val);
+      o = v.object(*(pwr_tOid *)val);
       if (o) {
-        if (o.oid().vid >= cdh_cUserVolMin && o.oid().vid != v.vid()
-            && !m_keepName) {
-          // Other user volume. Loadfile might not be created yet at load time.
-          cdh_OidToString(str, sizeof(str), *(pwr_tObjid*)val, 1);
-          sprintf(sval, "\"%s\"", str);
-        } else
-          sprintf(sval, "\"%s\"", o.longName().c_str());
-      } else {
-        cdh_OidToString(str, sizeof(str), *(pwr_tObjid*)val, 1);
-        sprintf(sval, "\"%s\"", str);
+	if ( o.oid().vid >= cdh_cUserVolMin && o.oid().vid != v.vid() && !m_keepName)
+	  // Other user volume. Loadfile might not be created yet at load time.
+	  sprintf(sval, "\"%s\"", cdh_ObjidToString(*(pwr_tObjid *)val, 1));
+	else
+	  sprintf(sval, "\"%s\"", o.longName().c_str());	  
       }
-    }
+      else 
+        sprintf(sval, "\"%s\"", cdh_ObjidToString(*(pwr_tObjid *)val, 1));
+    }    
     break;
   case pwr_eType_ObjectIx:
-    if (*(pwr_tObjectIx*)val == 0)
+    if ( *(pwr_tObjectIx *) val == 0)
       sprintf(sval, "0");
     else {
       cdh_ObjectIxToString(str, sizeof(str), *(pwr_tObjectIx*)val, 1);
@@ -423,88 +790,93 @@ bool wb_print_wbl::printValue(wb_volume& v, pwr_eType type, unsigned int flags,
     }
     break;
   case pwr_eType_VolumeId:
-    if (*(pwr_tVolumeId*)val == 0)
+    if ( *(pwr_tVolumeId *) val == 0)
       sprintf(sval, "0");
     else
-      sprintf(sval, "\"%s\"",
-          cdh_VolumeIdToString(0, 0, *(pwr_tVolumeId*)val, 1, 0));
+      sprintf(sval, "\"%s\"", cdh_VolumeIdToString(0, 0, *(pwr_tVolumeId *) val,1,0));
     break;
   case pwr_eType_ClassId:
-    if (*(pwr_tClassId*)val == 0)
+    if (*(pwr_tClassId *) val == 0)
       sprintf(sval, "0");
     else {
-      wb_cdef cdef = v.cdef(*(pwr_tCid*)val);
+      wb_cdef cdef = v.cdef(*(pwr_tCid *)val);
       if (cdef)
         sprintf(sval, "\"%s\"", cdef.longName().c_str());
       else {
-        sprintf(sval, "Unknown class, identity: %d", (*(pwr_tClassId*)val));
+        sprintf(sval, "Unknown class, identity: %d", (*(pwr_tClassId *) val));
         m_errCnt++;
         retval = false;
       }
+            
     }
     break;
   case pwr_eType_TypeId: /** @todo Modify when wb_tdef is OK q*/
   case pwr_eType_CastId:
-    if (*(pwr_tTypeId*)val == 0)
+    if (*(pwr_tTypeId *) val == 0)
       sprintf(sval, "0");
     else {
-      oid = cdh_TypeIdToObjid(*(pwr_tTid*)val);
+      oid = cdh_TypeIdToObjid(*(pwr_tTid *)val);
       o = v.object(oid);
       if (o)
         sprintf(sval, "\"%s\"", o.longName().c_str());
       else {
-        sprintf(sval, "Unknown type, identity: %d", (*(pwr_tTypeId*)val));
+        sprintf(sval, "Unknown type, identity: %d", (*(pwr_tTypeId *) val));
         m_errCnt++;
         retval = false;
       }
-    }
+    }    
     break;
   case pwr_eType_AttrRef: /** @todo */
     if (cdh_ObjidIsNull(((pwr_sAttrRef*)val)->Objid))
       sprintf(sval, "\"_O0.0.0.0:0\"");
     else {
       try {
-        wb_attribute a = v.attribute((pwr_sAttrRef*)val);
-        if (a)
-          sprintf(sval, "\"%s\"", a.longName().c_str());
-        else {
-          sprintf(sval, "\"%s\"", cdh_AttrRefToString((pwr_sAttrRef*)val, 1));
-        }
-      } catch (wb_error&) {
-        if (ldh_isSymbolicVid(((pwr_sAttrRef*)val)->Objid.vid))
-          sprintf(sval, "\"%s\"", cdh_AttrRefToString((pwr_sAttrRef*)val, 1));
-        else {
-          sprintf(sval, "Unknown attribute reference");
-          m_errCnt++;
-          retval = FALSE;
-        }
+	wb_attribute a = v.attribute((pwr_sAttrRef*)val);
+	if (a)
+	  sprintf(sval, "\"%s\"", a.longName().c_str());
+	else {
+	  sprintf(sval, "\"%s\"", cdh_AttrRefToString((pwr_sAttrRef*)val, 1));
+	}
+      } catch ( wb_error &e) {
+	if ( ldh_isSymbolicVid( ((pwr_sAttrRef *)val)->Objid.vid))
+	  sprintf(sval, "\"%s\"", cdh_AttrRefToString((pwr_sAttrRef*)val, 1));
+	else {
+	  sprintf(sval, "Unknown attribute reference");
+	  m_errCnt++;
+	  retval = FALSE;
+	}
       }
     }
+#if 0      
+    } else {
+      ConvertObjectName( root, sp, conv_name);
+      sprintf(sval, "\"%s\"", conv_name);
+    }
+#endif
     break;
   case pwr_eType_DataRef:
     if (cdh_ObjidIsNull(((pwr_tDataRef*)val)->Aref.Objid))
       sprintf(sval, "0");
     else {
-      wb_attribute a = v.attribute(&((pwr_tDataRef*)val)->Aref);
+      wb_attribute a = v.attribute( &((pwr_tDataRef*)val)->Aref);
       if (a)
         sprintf(sval, "\"%s\"", a.longName().c_str());
       else {
-        sprintf(sval, "\"%s\"",
-            cdh_AttrRefToString(&((pwr_tDataRef*)val)->Aref, 1));
+        sprintf(sval, "\"%s\"", cdh_AttrRefToString(&((pwr_tDataRef*)val)->Aref, 1));
       }
     }
 
     break;
   case pwr_eType_String:
   case pwr_eType_ProString: {
-    char* s = sval;
-    char* t = (char*)val;
+    char *s = sval;
+    char *t = (char *)val;
     *s++ = '"';
-    for (int i = 0; i < varSize; i++) {
-      if (*t == 0)
-        break;
-      if (*t == '"')
-        *s++ = '\\';
+    for ( int i = 0; i < varSize; i++) {
+      if ( *t == 0)
+	break;
+      if ( *t == '"')
+	*s++ = '\\'; 
       *s++ = *t++;
     }
     *s++ = '"';
@@ -513,523 +885,157 @@ bool wb_print_wbl::printValue(wb_volume& v, pwr_eType type, unsigned int flags,
     break;
   }
   case pwr_eType_Time: {
-    if (memcmp(val, &pwr_cAtMin, sizeof(pwr_tTime)) == 0)
-      strcpy(sval, "ATTIME_MIN");
-    else if (memcmp(val, &pwr_cAtMax, sizeof(pwr_tTime)) == 0)
-      strcpy(sval, "ATTIME_MAX");
+    if ( memcmp( val, &pwr_cAtMin, sizeof(pwr_tTime)) == 0)
+      strcpy( sval, "ATTIME_MIN");
+    else if ( memcmp( val, &pwr_cAtMax, sizeof(pwr_tTime)) == 0)
+      strcpy( sval, "ATTIME_MAX");
     else if (memcmp(val, &pwr_cNotATime, sizeof(pwr_tTime)) == 0)
       strcpy(sval, "NotATime");
     else {
-      sts = time_AtoAscii(
-          (pwr_tTime*)val, time_eFormat_DateAndTime, timbuf, sizeof(timbuf));
+      sts = time_AtoAscii((pwr_tTime *)val, time_eFormat_DateAndTime,
+			  timbuf, sizeof(timbuf)); 
       if (ODD(sts)) {
-        sprintf(sval, "\"%s\"", timbuf);
+	sprintf(sval, "\"%s\"", timbuf);
       } else {
-        sprintf(sval, "Bad time value");
-        m_errCnt++;
-        retval = FALSE;
+	sprintf(sval, "Bad time value");
+	m_errCnt++;
+	retval = FALSE;
       }
     }
     break;
   }
   case pwr_eType_DeltaTime: {
-    if (memcmp(val, &pwr_cDtMin, sizeof(pwr_tDeltaTime)) == 0)
-      strcpy(sval, "DTTIME_MIN");
-    else if (memcmp(val, &pwr_cDtMax, sizeof(pwr_tDeltaTime)) == 0)
-      strcpy(sval, "DTTIME_MAX");
+    if ( memcmp( val, &pwr_cDtMin, sizeof(pwr_tDeltaTime)) == 0)
+      strcpy( sval, "DTTIME_MIN");
+    else if ( memcmp( val, &pwr_cDtMax, sizeof(pwr_tDeltaTime)) == 0)
+      strcpy( sval, "DTTIME_MAX");
     else if (memcmp(val, &pwr_cNotADeltaTime, sizeof(pwr_tDeltaTime)) == 0)
       strcpy(sval, "NotADeltaTime");
-    else {
-      sts = time_DtoAscii((pwr_tDeltaTime*)val, 1, timbuf, sizeof(timbuf));
+     else {
+      sts = time_DtoAscii((pwr_tDeltaTime *)val, 1, timbuf, sizeof(timbuf));
       if (ODD(sts)) {
-        sprintf(sval, "\"%s\"", timbuf);
+	sprintf(sval, "\"%s\"", timbuf);
       } else {
-        sprintf(sval, "Bad time value");
-        m_errCnt++;
-        retval = FALSE;
+	sprintf(sval, "Bad time value");
+	m_errCnt++;
+	retval = FALSE;
       }
     }
     break;
   }
   case pwr_eType_Status:
-    sprintf(sval, "%d", *(pwr_tStatus*)val);
+    sprintf(sval, "%d", *(pwr_tStatus *) val);
     break;
   case pwr_eType_NetStatus:
-    sprintf(sval, "%d", *(pwr_tNetStatus*)val);
+    sprintf(sval, "%d", *(pwr_tNetStatus *) val);
     break;
   default:
-    sprintf(sval, "Unknown attribute type: %d", type);
+    sprintf(sval, "Unknown attribute type: %d", adef.type());
     m_errCnt++;
     retval = FALSE;
     break;
-  }
-
-  *svalp = sval;
-  return retval;
 }
 
-void wb_print_wbl::printBody(
-    wb_volume& vol, pwr_tOid oid, pwr_tOid toid, pwr_tCid cid, pwr_eBix bix)
+*svalp = sval;
+return retval;
+}
+
+//
+// printVolume
+//
+void wb_print_wbl::printVolume(wb_volume& v, bool recursive)
 {
-  ldh_sParDef* bd;
-  int rows;
-  int size;
-  char bname[10];
-  pwr_tStatus sts;
-  char *body, *tbody;
-  char timestr[40] = " ";
-  char* svalp;
-
-  switch (bix) {
-  case pwr_eBix_rt:
-    if (cdh_CidToVid(cid) == 1)
-      strcpy(bname, "SysBody");
-    else
-      strcpy(bname, "RtBody");
-    break;
-  case pwr_eBix_dev:
-    strcpy(bname, "DevBody");
-    break;
-  default:;
-  }
-
-  if (m_timeFlag) {
-    // Get body time
-    pwr_tTime btime;
-    wb_object o = vol.object(oid);
-    switch (bix) {
-    case pwr_eBix_rt:
-      btime = o.rbTime();
-
-      // Bugcheck in 4.2 btime can be corrupt
-      if (btime.tv_nsec < 0 || btime.tv_nsec >= 1000000000)
-        break;
-
-      strcpy(timestr, " ");
-      time_AtoAscii(
-          &btime, time_eFormat_DateAndTime, &timestr[1], sizeof(timestr) - 1);
-      break;
-    case pwr_eBix_dev:
-      btime = o.dbTime();
-      strcpy(timestr, " ");
-      time_AtoAscii(
-          &btime, time_eFormat_DateAndTime, &timestr[1], sizeof(timestr) - 1);
-      break;
-    default:;
-    }
-  }
-
-  sts = ldh_GetObjectBody((ldh_tSession)&vol, oid, bname, (void**)&body, &size);
-  if (sts == LDH__NOSUCHOBJ)
-    return;
-  if (EVEN(sts))
-    throw wb_error(sts);
-
-  sts = getBody(vol, cid, bname, size, &bd, &rows, &tbody);
-  if (sts == LDH__NOSUCHBODY)
+  if (!v) {
+    m_os << "%WBDUMP-E-Error Not a valid volume" << endl;
+    m_errCnt++;
     return;
-  else if (EVEN(sts))
-    throw wb_error(sts);
-
-  indent(1) << "Body " << bname << timestr << '\n';
-
-  for (int i = 0; i < rows; i++) {
-    if (bd[i].ParClass == pwr_eClass_Param && streq(bd[i].ParName, "Size")
-        && bd[i].Par->Param.Info.Flags & PWR_MASK_POINTER
-        && !(bd[i].Par->Param.Info.Flags & PWR_MASK_PRIVATE)) {
-      // Print Size for Pointers that is not private
-    } else if (bd[i].Par->Param.Info.Flags & PWR_MASK_POINTER
-        || bd[i].Par->Param.Info.Flags & PWR_MASK_NOWBL)
-      continue;
-    switch (bd[i].ParClass) {
-    case pwr_eClass_Input:
-    case pwr_eClass_Intern:
-    case pwr_eClass_Output:
-    case pwr_eClass_Param:
-      if (cdh_tidIsCid(bd[i].Par->Param.TypeRef)) {
-        if (bd[i].Par->Param.Info.Flags & PWR_MASK_ARRAY) {
-          for (unsigned int j = 0; j < bd[i].Par->Param.Info.Elements; j++) {
-            char aname[220];
-            sprintf(aname, "%s[%d]", bd[i].ParName, j);
-            printClass(vol, &bd[i], &body[bd[i].Par->Param.Info.Offset]
-                    + bd[i].Par->Param.Info.Size
-                        / bd[i].Par->Param.Info.Elements * j,
-                &tbody[bd[i].Par->Param.Info.Offset]
-                    + bd[i].Par->Param.Info.Size
-                        / bd[i].Par->Param.Info.Elements * j,
-                aname);
-          }
-        } else
-          printClass(vol, &bd[i], &body[bd[i].Par->Param.Info.Offset],
-              &tbody[bd[i].Par->Param.Info.Offset], bd[i].ParName);
-        break;
-      }
-    // No break if not class
-    case pwr_eClass_ObjXRef:
-      if (bd[i].Par->Param.Info.Flags & PWR_MASK_ARRAY) {
-        for (unsigned int j = 0; j < bd[i].Par->Param.Info.Elements; j++) {
-          if (bd[i].Par->Param.Info.Flags & PWR_MASK_ALWAYSWBL
-              || attrCmp(&body[bd[i].Par->Param.Info.Offset
-                             + bd[i].Par->Param.Info.Size
-                                 / bd[i].Par->Param.Info.Elements * j],
-                     &tbody[bd[i].Par->Param.Info.Offset
-                         + bd[i].Par->Param.Info.Size
-                             / bd[i].Par->Param.Info.Elements * j],
-                     bd[i].Par->Param.Info.Size
-                         / bd[i].Par->Param.Info.Elements,
-                     bd[i].Par->Param.Info.Type)
-                  != 0) {
-            printValue(vol, bd[i].Par->Param.Info.Type,
-                bd[i].Par->Param.Info.Flags, &body[bd[i].Par->Param.Info.Offset]
-                    + bd[i].Par->Param.Info.Size
-                        / bd[i].Par->Param.Info.Elements * j,
-                bd[i].Par->Param.Info.Size / bd[i].Par->Param.Info.Elements,
-                &svalp);
-            indent() << "Attr " << bd[i].ParName << "[" << j << "] = " << svalp
-                     << '\n';
-          }
-        }
-      } else {
-        if (bd[i].Par->Param.Info.Flags & PWR_MASK_ALWAYSWBL
-            || attrCmp(&body[bd[i].Par->Param.Info.Offset],
-                   &tbody[bd[i].Par->Param.Info.Offset],
-                   bd[i].Par->Param.Info.Size, bd[i].Par->Param.Info.Type)
-                != 0) {
-          if (bd[i].Par->Param.Info.Type == pwr_eType_Text) {
-            printText(vol, bd[i].ParName, &body[bd[i].Par->Param.Info.Offset],
-                bd[i].Par->Param.Info.Size);
-            break;
-          }
-          printValue(vol, bd[i].Par->Param.Info.Type,
-              bd[i].Par->Param.Info.Flags, &body[bd[i].Par->Param.Info.Offset],
-              bd[i].Par->Param.Info.Size, &svalp);
-          indent() << "Attr " << bd[i].ParName << " = " << svalp << '\n';
-        }
-      }
-      break;
-    case pwr_eClass_Buffer:
-      printBuffer(vol, &bd[i], &body[bd[i].Par->Param.Info.Offset]);
-      break;
-    default:;
-    }
   }
-  indent(-1) << "EndBody\n";
 
-  free(body);
-}
+  char timstr[40];
+  time_AtoAscii(0, time_eFormat_DateAndTime, timstr, sizeof(timstr));
+  indent() << "!     Generated by wb_print_wbl " << timstr << "\n";
+  indent() << "!     Volume " << v.name() << " \n";
+  indent() << "!     Version " pwrv_cPwrVersionStr "\n";
 
-void wb_print_wbl::printBuffer(wb_volume& vol, ldh_sParDef* par_bd, char* body)
-{
-  pwr_tStatus sts;
-  int rows;
-  char* tbody;
-  ldh_sParDef* bd;
-  char* svalp;
+  wb_object o = v.object();
+  const char* cname = v.cdef(v.cid()).name();
+    
+    
+  indent(1) << "Volume " << v.name() << " " <<  cname << " "
+            << cdh_VolumeIdToString(0, 0, v.vid(), 0, 0) << " " << endl;
 
-  if (m_isTemplateObject)
-    return;
 
-  sts = getBody(
-      vol, par_bd->Par->Buffer.Class, "SysBody", 0, &bd, &rows, &tbody);
-  if (EVEN(sts)) {
-    m_os << "! %WBDUMP-E-Error Unknown sub class: " << par_bd->Par->Buffer.Class
-         << '\n';
+  // Print volume body
+  pwr_tOid oid;
+  oid.vid = v.vid();
+  oid.oix= 0;
+  wb_object vo = v.object( oid);
+  wb_cdef cdef = v.cdef(vo);
+
+  wb_object co = v.object(cdh_ClassIdToObjid(v.cid()));
+  wb_name t("Template");
+  
+  wb_object templ = co.child(t);
+  if (!templ) {
     m_errCnt++;
+    m_os << "Template not found for class " << cdef.name() << endl;
     return;
   }
+  printBody(v, vo, templ, cdef, pwr_eBix_sys);
 
-  for (unsigned int k = 0; k < par_bd->Par->Param.Info.Elements; k++) {
-    if (par_bd->Par->Param.Info.Flags & PWR_MASK_ARRAY)
-      indent(1) << "Buffer " << par_bd->ParName << "[" << k << "]\n";
-    else
-      indent(1) << "Buffer " << par_bd->ParName << '\n';
-
-    for (int i = 0; i < rows; i++) {
-      switch (bd[i].ParClass) {
-      case pwr_eClass_Input:
-      case pwr_eClass_Intern:
-      case pwr_eClass_Output:
-      case pwr_eClass_Param:
-      case pwr_eClass_AttrXRef:
-      case pwr_eClass_ObjXRef:
-        if (bd[i].Par->Param.Info.Flags & PWR_MASK_ARRAY) {
-          for (unsigned int j = 0; j < bd[i].Par->Param.Info.Elements; j++) {
-            if (bd[i].Par->Param.Info.Flags & PWR_MASK_ALWAYSWBL
-                || attrCmp(&body[bd[i].Par->Param.Info.Offset
-                               + bd[i].Par->Param.Info.Size
-                                   / bd[i].Par->Param.Info.Elements * j],
-                       &tbody[bd[i].Par->Param.Info.Offset],
-                       bd[i].Par->Param.Info.Size
-                           / bd[i].Par->Param.Info.Elements,
-                       bd[i].Par->Param.Info.Type)
-                    != 0) {
-              printValue(vol, bd[i].Par->Param.Info.Type,
-                  bd[i].Par->Param.Info.Flags,
-                  &body[bd[i].Par->Param.Info.Offset]
-                      + bd[i].Par->Param.Info.Size
-                          / bd[i].Par->Param.Info.Elements * j,
-                  bd[i].Par->Param.Info.Size / bd[i].Par->Param.Info.Elements,
-                  &svalp);
-              indent() << "Attr " << bd[i].ParName << "[" << j
-                       << "] = " << svalp << '\n';
-            }
-          }
-        } else {
-          if (bd[i].Par->Param.Info.Flags & PWR_MASK_ALWAYSWBL
-              || attrCmp(&body[bd[i].Par->Param.Info.Offset],
-                     &tbody[bd[i].Par->Param.Info.Offset],
-                     bd[i].Par->Param.Info.Size, bd[i].Par->Param.Info.Type)
-                  != 0) {
-            printValue(vol, bd[i].Par->Param.Info.Type,
-                bd[i].Par->Param.Info.Flags,
-                &body[bd[i].Par->Param.Info.Offset], bd[i].Par->Param.Info.Size,
-                &svalp);
-            indent() << "Attr " << bd[i].ParName << " = " << svalp << '\n';
-          }
-        }
-        break;
-      case pwr_eClass_Buffer:
-        printBuffer(vol, &bd[i], &body[bd[i].Par->Param.Info.Offset]);
-        break;
-      default:
-        m_os << "! %WBDUMP-E-Error Undefined parameter class in buffer"
-             << par_bd->ParName << '\n';
-        m_errCnt++;
-      }
-    }
-    indent(-1) << "EndBuffer\n";
-
-    body += par_bd->Par->Param.Info.Size / par_bd->Par->Param.Info.Elements;
+  // Print top objects and their children 
+  if (recursive) {
+    for (; o; o = o.after())
+      printObject(v, o, recursive);
   }
+    
+  indent(-1) << "EndVolume" << endl;
 }
 
+
 //
-// printClass
+// indent
 //
-void wb_print_wbl::printClass(wb_volume& vol, ldh_sParDef* par_bd, char* body,
-    char* tbody, char* par_path)
+ostream& wb_print_wbl::indent(int levelIncr)
 {
-  pwr_tStatus sts;
-  int rows;
-  ldh_sParDef* bd;
-  char* svalp;
-  char* tb;
-
-  sts = getBody(vol, par_bd->Par->Param.TypeRef, "RtBody",
-      par_bd->Par->Param.Info.Size / par_bd->Par->Param.Info.Elements, &bd,
-      &rows, &tb);
-  if (EVEN(sts))
-    sts = getBody(vol, par_bd->Par->Param.TypeRef, "SysBody",
-        par_bd->Par->Param.Info.Size / par_bd->Par->Param.Info.Elements, &bd,
-	&rows, &tb);
-  if (EVEN(sts)) {
-    m_os << "! %WBDUMP-E-Error Unknown sub class: " << par_bd->Par->Buffer.Class
-         << '\n';
-    m_errCnt++;
-    return;
-  }
 
-  for (int i = 0; i < rows; i++) {
-    switch (bd[i].ParClass) {
-    case pwr_eClass_Input:
-    case pwr_eClass_Intern:
-    case pwr_eClass_Output:
-    case pwr_eClass_Param:
-      if (cdh_tidIsCid(bd[i].Par->Param.TypeRef)) {
-        char aname[210];
-        if (bd[i].Par->Param.Info.Flags & PWR_MASK_ARRAY) {
-          for (unsigned int j = 0; j < bd[i].Par->Param.Info.Elements; j++) {
-            sprintf(aname, "%s.%s[%d]", par_path, bd[i].ParName, j);
-            printClass(vol, &bd[i], &body[bd[i].Par->Param.Info.Offset]
-                    + bd[i].Par->Param.Info.Size
-                        / bd[i].Par->Param.Info.Elements * j,
-                &tbody[bd[i].Par->Param.Info.Offset]
-                    + bd[i].Par->Param.Info.Size
-                        / bd[i].Par->Param.Info.Elements * j,
-                aname);
-          }
-        } else {
-          sprintf(aname, "%s.%s", par_path, bd[i].ParName);
-          printClass(vol, &bd[i], &body[bd[i].Par->Param.Info.Offset],
-              &tbody[bd[i].Par->Param.Info.Offset], aname);
-        }
-        break;
-      }
-    // No break if not class
+  if (levelIncr < 0)
+    m_level += levelIncr;
 
-    case pwr_eClass_ObjXRef:
-      if (bd[i].Par->Param.Info.Flags & PWR_MASK_ARRAY) {
-        for (unsigned int j = 0; j < bd[i].Par->Param.Info.Elements; j++) {
-          if (bd[i].Par->Param.Info.Flags & PWR_MASK_ALWAYSWBL
-              || attrCmp(&body[bd[i].Par->Param.Info.Offset
-                             + bd[i].Par->Param.Info.Size
-                                 / bd[i].Par->Param.Info.Elements * j],
-                     &tbody[bd[i].Par->Param.Info.Offset
-                         + bd[i].Par->Param.Info.Size
-                             / bd[i].Par->Param.Info.Elements * j],
-                     bd[i].Par->Param.Info.Size
-                         / bd[i].Par->Param.Info.Elements,
-                     bd[i].Par->Param.Info.Type)
-                  != 0) {
-            printValue(vol, bd[i].Par->Param.Info.Type,
-                bd[i].Par->Param.Info.Flags, &body[bd[i].Par->Param.Info.Offset]
-                    + bd[i].Par->Param.Info.Size
-                        / bd[i].Par->Param.Info.Elements * j,
-                bd[i].Par->Param.Info.Size / bd[i].Par->Param.Info.Elements,
-                &svalp);
-            indent() << "Attr " << par_path << "." << bd[i].ParName << "[" << j
-                     << "] = " << svalp << '\n';
-          }
-        }
-      } else {
-        if (bd[i].Par->Param.Info.Flags & PWR_MASK_ALWAYSWBL
-            || attrCmp(&body[bd[i].Par->Param.Info.Offset],
-                   &tbody[bd[i].Par->Param.Info.Offset],
-                   bd[i].Par->Param.Info.Size, bd[i].Par->Param.Info.Type)
-                != 0) {
-          if (bd[i].Par->Param.Info.Type == pwr_eType_Text) {
-            char aname[210];
-            sprintf(aname, "%s.%s", par_path, bd[i].ParName);
-            printText(vol, aname, &body[bd[i].Par->Param.Info.Offset],
-                bd[i].Par->Param.Info.Size);
-            break;
-          }
-          printValue(vol, bd[i].Par->Param.Info.Type,
-              bd[i].Par->Param.Info.Flags, &body[bd[i].Par->Param.Info.Offset],
-              bd[i].Par->Param.Info.Size, &svalp);
-          indent() << "Attr " << par_path << "." << bd[i].ParName << " = "
-                   << svalp << '\n';
-        }
-      }
-      break;
-    default:
-      m_os << "! %WBDUMP-E-Error Undefined parameter class in attribute "
-           << par_bd->ParName << '\n';
-      m_errCnt++;
-    }
-  }
-}
+  assert(m_level >= 0);
+    
+  m_indBuf[m_level * m_levelInd] = '\0';
 
-typedef struct {
-  pwr_tCid cid;
-  pwr_eBix bix;
-} pwbl_sBodyItemKey;
+  m_os << m_indBuf;
 
-typedef struct {
-  tree_sNode n;
-  pwbl_sBodyItemKey key;
-  ldh_sParDef* bd;
-  int rows;
-  char* tbody;
-} pwbl_sBodyItem;
+  m_indBuf[m_level * m_levelInd] = ' ';
 
-static int comp_cid(tree_sTable* tp, tree_sNode* x, tree_sNode* y)
-{
-  pwbl_sBodyItemKey* xKey = (pwbl_sBodyItemKey*)((char*)x + tp->keyOffset);
-  pwbl_sBodyItemKey* yKey = (pwbl_sBodyItemKey*)((char*)y + tp->keyOffset);
-
-  if (xKey->cid == yKey->cid) {
-    if (xKey->bix == yKey->bix)
-      return 0;
-    if (xKey->bix < yKey->bix)
-      return -1;
-    else
-      return 1;
-  }
-  if (xKey->cid < yKey->cid)
-    return -1;
-  else
-    return 1;
+  if (levelIncr > 0) 
+    m_level += levelIncr;
+    
+  return m_os;
 }
 
-pwr_tStatus wb_print_wbl::getBody(wb_volume& vol, pwr_tCid cid,
-    const char* bname, int tsize, ldh_sParDef** bdef, int* rows, char** tbody)
+bool wb_print_wbl::isFoCodeObject( wb_volume& v, wb_object& o)
 {
-  pwr_tStatus sts;
-  ldh_sParDef* bd;
-  char* tb;
-  int size;
-  pwbl_sBodyItemKey key;
-  pwr_eBix bix;
-  pwr_tOid toid;
-
-  if (!m_body_cache)
-    m_body_cache = tree_CreateTable(&sts, sizeof(pwbl_sBodyItemKey),
-        offsetof(pwbl_sBodyItem, key), sizeof(pwbl_sBodyItem), 100, comp_cid);
-
-  if (streq(bname, "DevBody"))
-    bix = pwr_eBix_dev;
-  else
-    bix = pwr_eBix_rt;
-
-  key.cid = cid;
-  key.bix = bix;
-  pwbl_sBodyItem* item = (pwbl_sBodyItem*)tree_Find(&sts, m_body_cache, &key);
-  if (ODD(sts)) {
-    *bdef = item->bd;
-    *tbody = item->tbody;
-    *rows = item->rows;
-    // printf( " found:  %10d %d\n", key.cid, key.bix);
-  } else {
-    sts = ldh_GetTrueObjectBodyDef(
-        (ldh_tSession)&vol, cid, (char*)bname, 1, &bd, rows);
-    if (EVEN(sts))
-      return sts;
-
-    if (m_isTemplateObject)
-      tb = (char*)calloc(1, tsize);
-    else {
-      toid.vid = cdh_CidToVid(cid);
-      toid.oix = cdh_cixToOix(cdh_cidToCix(cid), pwr_eBix_template, 0);
-
-      sts = ldh_GetObjectBody(
-          (ldh_tSession)&vol, toid, bname, (void**)&tb, &size);
-      if (EVEN(sts)) {
-        // Template attribute not found, should not happen
-        *tbody = (char*)calloc(1, tsize);
-
-        m_os << "! %WBDUMP-E-Error Template not found for body " << bname
-             << '\n';
-        m_errCnt++;
-      }
-    }
-
-    item = (pwbl_sBodyItem*)tree_Insert(&sts, m_body_cache, &key);
-    item->bd = bd;
-    item->rows = *rows;
-    item->tbody = tb;
-
-    *bdef = bd;
-    *tbody = tb;
-    // printf( "*insert: %10d %d\n", key.cid, key.bix);
-  }
-  return LDH__SUCCESS;
-}
+  pwr_tInt32 compmethod;
 
-void wb_print_wbl::bodyCacheFree()
-{
-  pwr_tStatus sts;
+  // Check if object has GraphPlcNode body and compmethod 58
+  wb_cdef cd = v.cdef( o);
+  if ( !cd)
+    return false;
 
-  if (!m_body_cache)
-    return;
+  wb_object go = cd.classBody( "GraphPlcNode");
+  if ( !go) 
+    return false;
 
-  for (pwbl_sBodyItem* item = (pwbl_sBodyItem*)tree_Minimum(&sts, m_body_cache);
-       item; item = (pwbl_sBodyItem*)tree_Successor(&sts, m_body_cache, item)) {
-    free(item->bd);
-    free(item->tbody);
-  }
+  wb_attribute a = v.attribute( go, "compmethod");
+  if ( !a) 
+    return false;
 
-  tree_DeleteTable(&sts, m_body_cache);
-  m_body_cache = 0;
-}
+  a.value( &compmethod);
 
-int wb_print_wbl::attrCmp(char* a1, char* a2, int size, pwr_eType type)
-{
-  switch (type) {
-  case pwr_eType_String:
-  case pwr_eType_Text:
-    return strcmp(a1, a2);
-  default:
-    return memcmp(a1, a2, size);
-  }
+  if ( compmethod == 58)
+    return true;
+  return false;
 }
diff --git a/wb/lib/wb/src/wb_print_wbl.h b/wb/lib/wb/src/wb_print_wbl.h
index f3ac9edf5a2818f3891a732ad7bf49130400a109..76e2c7b0013d0e8fd695fa67da5301c3924c45ae 100644
--- a/wb/lib/wb/src/wb_print_wbl.h
+++ b/wb/lib/wb/src/wb_print_wbl.h
@@ -1,38 +1,38 @@
-/*
- * ProviewR   Open Source Process Control.
- * Copyright (C) 2005-2019 SSAB EMEA AB.
+/* 
+ * Proview   Open Source Process Control.
+ * Copyright (C) 2005-2017 SSAB EMEA AB.
  *
- * This file is part of ProviewR.
+ * This file is part of Proview.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 2 of
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation, either version 2 of 
  * the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * This program is distributed in the hope that it will be useful 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with ProviewR. If not, see <http://www.gnu.org/licenses/>
+ * You should have received a copy of the GNU General Public License 
+ * along with Proview. If not, see <http://www.gnu.org/licenses/>
  *
- * Linking ProviewR statically or dynamically with other modules is
- * making a combined work based on ProviewR. Thus, the terms and
- * conditions of the GNU General Public License cover the whole
+ * Linking Proview statically or dynamically with other modules is
+ * making a combined work based on Proview. Thus, the terms and 
+ * conditions of the GNU General Public License cover the whole 
  * combination.
  *
  * In addition, as a special exception, the copyright holders of
- * ProviewR give you permission to, from the build function in the
- * ProviewR Configurator, combine ProviewR with modules generated by the
- * ProviewR PLC Editor to a PLC program, regardless of the license
+ * Proview give you permission to, from the build function in the
+ * Proview Configurator, combine Proview with modules generated by the
+ * Proview PLC Editor to a PLC program, regardless of the license
  * terms of these modules. You may copy and distribute the resulting
- * combined work under the terms of your choice, provided that every
- * copy of the combined work is accompanied by a complete copy of
- * the source code of ProviewR (the version used to produce the
- * combined work), being distributed under the terms of the GNU
+ * combined work under the terms of your choice, provided that every 
+ * copy of the combined work is accompanied by a complete copy of 
+ * the source code of Proview (the version used to produce the 
+ * combined work), being distributed under the terms of the GNU 
  * General Public License plus this exception.
- */
+ **/
 
 /**
  * @file wb_print_wbl.h
@@ -44,10 +44,11 @@
 #ifndef wb_print_wbl_h
 #define wb_print_wbl_h
 
-#include <ostream>
+#include <iostream>
+
+#include "pwr_class.h"
 
-#include "wb_ldh.h"
-#include "co_tree.h"
+using namespace std;
 
 class wb_adef;
 class wb_attribute;
@@ -55,68 +56,79 @@ class wb_cdef;
 class wb_object;
 class wb_volume;
 
-class wb_print_wbl {
+
+class wb_print_wbl 
+{
 protected:
-  int m_errCnt;
-  int m_lineCnt;
+  int  m_errCnt;
   bool m_idxFlag;
   bool m_noFoCodeFlag;
   bool m_timeFlag;
-  int m_level;
-  int m_levelInd;
+  int  m_level;
+  int  m_levelInd;
   char m_indBuf[256];
   bool m_keepName;
   bool m_isTemplateObject;
-  std::ostream& m_os;
-  tree_sTable* m_body_cache;
-
-  std::ostream& indent(int levelIncr = 0);
-
-  void printBody(
-      wb_volume& vol, pwr_tOid oid, pwr_tOid toid, pwr_tCid cid, pwr_eBix bix);
-  bool printValue(wb_volume& v, pwr_eType type, unsigned int flags, void* val,
-      int varSize, char** svalp);
-  void printBuffer(wb_volume& vol, ldh_sParDef* par_bd, char* body);
-  void printClass(wb_volume& vol, ldh_sParDef* par_bd, char* body, char* tbody,
-      char* par_path);
-  void printText(
-      wb_volume& v, const char* aname, const char* text, int varSize);
-  pwr_tStatus getBody(wb_volume& vol, pwr_tCid cid, const char* bname,
-      int tsize, ldh_sParDef** bdef, int* rows, char** tbody);
-  void bodyCacheFree();
-  int attrCmp(char* a1, char* a2, int size, pwr_eType type);
-  bool isFoCodeObject(wb_volume& v, wb_object& o);
+  ostream& m_os;
+    
+
+  ostream& indent(int levelIncr = 0);    
+
+  void printAttribute(wb_volume& v, 
+                      wb_attribute& attr, 
+                      wb_attribute& tattr, ///< template attribute
+                      wb_adef& adef,
+		      int force);
+
+  void printBody(wb_volume& v, 
+                 wb_object& o,
+                 wb_object& templ,
+                 wb_cdef& cdef, 
+                 pwr_eBix bix);
+
+  void printBuffer(wb_volume& v,
+                  wb_attribute& attr,
+                  wb_attribute& tattr, ///< template attribute
+                  wb_adef& adef);
+    
+  void printClass(wb_volume& v,
+                  wb_attribute& attr,
+                  wb_attribute& tattr, ///< template attribute
+                  wb_adef& adef);
+    
+  void printParameter(wb_volume& v, 
+                      wb_attribute& attr, 
+                      wb_attribute& tattr, ///< template attribute
+                      wb_adef& adef);
+
+  void printText(wb_volume& v, 
+                 wb_adef& adef,
+                 const char* text,
+                 int varSize);
+
+  bool printValue(wb_volume& v, 
+                  wb_adef& adef,
+                  void *val,
+                  int varSize,
+                  char **svalp);
+  bool isFoCodeObject( wb_volume& v, 
+		       wb_object& o);
+    
 
 public:
-  wb_print_wbl(std::ostream& os, int levelIndentation = 2);
+  wb_print_wbl(ostream& os, int levelIndentation = 2);
   ~wb_print_wbl();
 
-  int getErrCnt() const
-  {
-    return m_errCnt;
-  }
-  void resetErrCnt()
-  {
-    m_errCnt = 0;
-  }
-  void keepName()
-  {
-    m_keepName = true;
-  }
-  void noIndex()
-  {
-    m_idxFlag = false;
-    m_timeFlag = false;
-  }
-  void noFoCode()
-  {
-    m_noFoCodeFlag = true;
-  }
-
-  void printHierarchy(wb_volume& v, wb_object& o); ///< Prints a hierarchy
-  void printObject(
-      wb_volume& v, wb_object& o, bool recursive = true); ///< Prints an object
-  void printVolume(wb_volume& v, bool recursive = true); ///< Prints the volume
+  int getErrCnt() const { return m_errCnt;}
+  void resetErrCnt() {m_errCnt = 0; }
+  void keepName() { m_keepName = true;}
+  void noIndex() { m_idxFlag = false; m_timeFlag = false;}
+  void noFoCode() { m_noFoCodeFlag = true;}
+
+  void printHierarchy(wb_volume& v, wb_object& o); //< Prints a hierarchy
+  void printObject(wb_volume& v, wb_object& o, bool recursive = true); //< Prints an object
+  void printVolume(wb_volume& v, bool recursive = true); //< Prints the volume
+
 };
 
 #endif