Index: /trunk/SophyaLib/HiStats/basedtable.cc
===================================================================
--- /trunk/SophyaLib/HiStats/basedtable.cc	(revision 2830)
+++ /trunk/SophyaLib/HiStats/basedtable.cc	(revision 2831)
@@ -11,4 +11,21 @@
 */
 
+/*!
+  if fgl == true , return LongForm string
+  \verbatim
+  ----------------------------------------------  
+  FieldType         ShortForm     LongForm
+  ----------------------------------------------  
+  IntegerField          I         Integer
+  LongField             L         Long Integer
+  FloatField            F         Float
+  DoubleField           D         Double
+  ComplexField         Zx4        Complex
+  DoubleComplexField   Zx8        DoubleComplex
+  StringField           S         String
+  DateTimeField         T         DateTime
+  ----------------------------------------------  
+  \endverbatim
+*/
 string BaseDataTable::ColTypeToString(FieldType ft, bool fgl)
 {
@@ -43,5 +60,5 @@
     else rs = "S";
     break;
-  case DateField :
+  case DateTimeField :
     if (fgl) rs = "DateTime";
     else rs = "T";
@@ -52,4 +69,18 @@
   }
   return rs;
+}
+
+BaseDataTable::FieldType BaseDataTable::StringToColType(string const & sctyp)
+{
+  if ( (sctyp == "Integer") || (sctyp == "I") )  return IntegerField;
+  else if ( (sctyp == "Long Integer") || (sctyp == "L") )  return LongField;
+  else if ( (sctyp == "Float") || (sctyp == "F") )  return FloatField;
+  else if ( (sctyp == "Double") || (sctyp == "D") )  return DoubleField;
+  else if ( (sctyp == "Complex") || (sctyp == "Zx4") )  return ComplexField;
+  else if ( (sctyp == "DoubleComplex") || (sctyp == "Zx8") || (sctyp == "Z") )  
+    return DoubleComplexField;
+  else if ( (sctyp == "String") || (sctyp == "S") )  return StringField;
+  else if ( (sctyp == "DateTime") || (sctyp == "T") )  return DateTimeField;
+  else return DoubleField;
 }
 
@@ -252,4 +283,53 @@
 }
 
+#define BADVAL -1.e39
+
+TVector<r_8> BaseDataTable::GetColumnD(sa_size_t k) const
+{
+  if ((k < 0) || (k >= NVar())) 
+    throw RangeCheckError("BaseDataTable::GetColumnD() out of range column index k");
+  sa_size_t sk = mNames[k].ser;
+  sa_size_t i = 0; 
+  TVector<r_8> rv(NEntry());
+
+  for (sa_size_t is=0; is<NbSegments(); is++) {
+    switch (mNames[k].type) {
+    case IntegerField :
+      for(sa_size_t j=0; j<SegmentSize(); j++,i++)
+	rv(i) = mIColsP[sk]->GetCstSegment(is)[j];
+      break;
+    case LongField :
+      for(sa_size_t j=0; j<SegmentSize(); j++,i++)
+	rv(i) = mLColsP[sk]->GetCstSegment(is)[j];
+      break;
+    case FloatField :
+      for(sa_size_t j=0; j<SegmentSize(); j++,i++)
+	rv(i) = mFColsP[sk]->GetCstSegment(is)[j];
+      break;
+    case DoubleField :
+    case DateTimeField :
+      for(sa_size_t j=0; j<SegmentSize(); j++,i++)
+	rv(i) = mDColsP[sk]->GetCstSegment(is)[j];
+      break;
+    case ComplexField :
+      for(sa_size_t j=0; j<SegmentSize(); j++,i++)
+	rv(i) = mYColsP[sk]->GetCstSegment(is)[j].real();
+      break;
+    case DoubleComplexField :
+      for(sa_size_t j=0; j<SegmentSize(); j++,i++)
+	rv(i) = mZColsP[sk]->GetCstSegment(is)[j].real();
+      break;
+    case StringField :
+      for(sa_size_t j=0; j<SegmentSize(); j++,i++)
+	rv = atof(mSColsP[sk]->GetCstSegment(is)[j].c_str());
+      break;
+    default:
+      for(sa_size_t j=0; j<SegmentSize(); j++,i++)  rv(i) = BADVAL;
+      break;
+    }
+  }
+  return rv ; 
+}
+
 void BaseDataTable::CopyMerge(BaseDataTable const& a, bool cp)
 {
@@ -276,8 +356,26 @@
 }
 
-void BaseDataTable::Print(int num, int nmax) const 
-{
-  // A faire
-  return;
+/*!
+  Formatted (text) output of the table, for lines lstart <= l_index < lend , with step lstep
+  \param os : output stream (formatted output)
+  \param lstart : start row (line) index
+  \param lend : end row (line) index 
+  \param lstep : row index increment
+*/
+ostream& BaseDataTable::Print(ostream& os, sa_size_t lstart, sa_size_t lend, sa_size_t lstep) const
+{
+  os << "##### BaseDataTable::Print() - Table(NRow=" << NEntry() << " , NCol=" 
+     << NVar() << ") ##### " << endl;
+  os << "#! " ;
+  for (size_t i=0; i<NVar(); i++) {
+    string nom = mNames[i].nom;
+    nom += ':'; nom += ColTypeToString(mNames[i].type);
+    os << setw(12) << nom << " ";
+  }
+  os << endl;
+  os << "##########################################################################" << endl;
+  for (sa_size_t l=lstart; l<lend; l+=lstep)
+    os << TableRowToString(l, true) << endl;
+  return os;
 }
 
@@ -312,11 +410,56 @@
 }
 
-//! NOT YET IMPLEMENTED ! - Fills table from an ascii file
-int    BaseDataTable::FillFromASCIIFile(string const& fn)
-//	Remplit le ntuple a partir d'un fichier ASCII.
-//	Renvoie le nombre de lignes ajoutees.
-{
-// a faire
-return(0);
+//! Fills table from an ascii (text) file
+/*
+  Return number of non empt lines (added to table)
+  \param is : input ascii (text) stream
+  \param clm : Lines starting with clm are ignored (comments)
+  \param sep : separator between different fields (columns)
+*/
+sa_size_t  BaseDataTable::FillFromASCIIFile(istream& is, char clm, const char* sep)
+{
+  string str;
+  if (mVarMTV == NULL) mVarMTV = new MuTyV[NVar()];
+  sa_size_t iv, nl;
+  nl = 0;
+  while (!is.eof()) {
+    str = "";
+    getline(is, str);
+    if (is.good() || is.eof()) {
+      size_t l = str.length();
+      if ((l == 0) || (str[0]==clm)) continue;
+      for(iv=0; iv<NVar(); iv++) mVarMTV[iv] = 0.;
+      iv = 0;
+      size_t q = 0;
+      size_t p = 0;
+      while ( (q < l) && (iv < NVar()) ) {
+	p = str.find_first_not_of(sep,q);
+	if (p >= l)  break;
+	if (str[p] == '\'')    {  // Decodage d'un string
+	  q = str.find('\'',p+1);
+	  if (q < l)  { 
+	    mVarMTV[iv] = str.substr(p+1,q-p-1);
+	    q++;
+	  }
+	  else mVarMTV[iv] = str.substr(p+1,l-p-1);
+	  iv++;
+	}
+	else {
+	  q = str.find_first_of(sep,p);
+	  if (q > l) q = l;
+	  mVarMTV[iv] = str.substr(p,q-p);
+	  iv++;
+	}
+	if (mNames[iv-1].type == DateTimeField) {
+	  string tts = (string)mVarMTV[iv-1];
+	  mVarMTV[iv-1] = TimeStamp(tts);
+	}
+      }
+      AddLine(mVarMTV);
+      nl++;
+    }
+  }  // Fin boucle lignes fichier
+  cout << "BaseDataTable::FillFromASCIIFile()/Info: " << nl << " lines decoded from stream " << endl; 
+  return(nl);
 }
 
@@ -364,5 +507,4 @@
 }
 
-#define BADVAL -1.e39
 
 r_8  BaseDataTable::GetCell(sa_size_t n, sa_size_t k) const 
@@ -388,6 +530,6 @@
     break;
   case DoubleField :
-  case DateField :
-   rv = mDColsP[sk]->GetCstSegment(bid)[off];
+  case DateTimeField :
+    rv = mDColsP[sk]->GetCstSegment(bid)[off];
     break;
   case ComplexField :
@@ -445,4 +587,7 @@
     rv = mSColsP[sk]->GetCstSegment(bid)[off];
     break;
+  case DateTimeField :
+    rv = TimeStamp(mDColsP[sk]->GetCstSegment(bid)[off]);
+    break;
   default:
     rv = " ";
@@ -511,4 +656,5 @@
     break;
   case DoubleField :
+  case DateTimeField :
     for(size_t is=0; is<mDColsP[sk]->NbSegments(); is++) {
       const r_8* sp = mDColsP[sk]->GetCstSegment(is);
@@ -608,7 +754,7 @@
   for(int i=0; i<NVar(); i++) {
     s = mNames[i].nom;
-    s += ' ';
     size_t l = s.length();
-    for(size_t ii=l; ii<10; ii++) s += ' ';
+    for(size_t ii=l; ii<12; ii++) s += ' ';
+    if (i > 0) rets += ' ';   
     rets += s;
   }
@@ -616,6 +762,21 @@
 }
 
-
-string BaseDataTable::LineToString(sa_size_t n) const 
+/*!
+  Return a table row (line) as a string
+  \sa TableRowToString()
+*/
+string BaseDataTable::LineToString(sa_size_t n) const
+{
+  return TableRowToString(n, false);
+}
+
+/*!
+  \param n : table row index ( 0 ... NEntry()-1) 
+  \param qstr : if true , enclose strings in quotes ''
+  \param sep : separates fields using \b sep
+  \param fw : minimum field width
+ */
+string BaseDataTable::TableRowToString(sa_size_t n, bool qstr, 
+				       const char* sep, int fw) const 
 {
   if ((n < 0) || (n >= NEntry())) 
@@ -648,13 +809,20 @@
     case StringField :
       rv = mSColsP[sk]->GetCstSegment(bid)[off];
-    break;
+      break;
+    case DateTimeField :
+      rv = TimeStamp(mDColsP[sk]->GetCstSegment(bid)[off]);
+      break;
     default:
       rv = " ";
       break;
     }
-    string s = (string)rv;
-    s += ' ';
+    string s;
+    if ( (mNames[k].type == StringField) && (qstr) ) {
+      s = '\'';  s += (string)rv; s += '\''; 
+    }
+    else  s= (string)rv;
     size_t l = s.length();
-    for(size_t ii=l; ii<10; ii++) s += ' ';
+    for(size_t ii=l; ii<fw; ii++) s += ' ';
+    if (k > 0) rs += sep;
     rs += s;
   }
Index: /trunk/SophyaLib/HiStats/basedtable.h
===================================================================
--- /trunk/SophyaLib/HiStats/basedtable.h	(revision 2830)
+++ /trunk/SophyaLib/HiStats/basedtable.h	(revision 2831)
@@ -18,4 +18,5 @@
 #include "dvlist.h"
 #include "segdatablock.h"
+#include "tvector.h"
 
 namespace SOPHYA {
@@ -31,8 +32,11 @@
 		  FloatField=3, DoubleField=4,
 		  ComplexField=5, DoubleComplexField=6,
-		  StringField=7, DateField=8};
+		  StringField=7, DateTimeField=8};
   // <=====================================================> 
 
+  //! Return the column type as a string (long or short depending on fgl=true/false)
   static string     ColTypeToString(FieldType ft, bool fgl=false);
+  //! Return the column type corresponding to \b sctyp
+  static FieldType  StringToColType(string const & sctyp);
 
   // constructeur , destructeur 
@@ -82,4 +86,10 @@
   inline sa_size_t  AddStringColumn(string const & cnom) 
   { return AddColumn(StringField, cnom); }
+  //! Adds a column holding Date/Time value, named \b cnom 
+  inline sa_size_t  AddDateTimeColumn(const char * cnom) 
+  { return AddColumn(DateTimeField, cnom); }
+  //! Adds a column holding Date/Time value, named \b cnom 
+  inline sa_size_t  AddDateTimeColumn(string const & cnom) 
+  { return AddColumn(DateTimeField, cnom); }
   
   inline sa_size_t  AddColumn(FieldType ft, const char * cnom)
@@ -124,4 +134,14 @@
   virtual MuTyV *   GetLine(sa_size_t n) const ;
 
+  //! Return the information stored in column \b k of the table, converted to double 
+  virtual TVector<r_8>  GetColumnD(sa_size_t k) const ;
+
+  //! Return the information stored in column named \b nom of the table, converted to double 
+  inline TVector<r_8>  GetColumnD(char const * nom) const 
+  { return  GetColumnD(IndexNom(nom)) ; }
+  //! Return the information stored in column named \b nom of the table, converted to double 
+  inline TVector<r_8>  GetColumnD(string const & nom) const 
+  { return  GetColumnD(IndexNom(nom)) ; }
+
   //! Return the index for column name \b nom  
   sa_size_t         IndexNom(char const* nom) const ; 
@@ -146,16 +166,25 @@
   virtual void Clear() = 0;
 
-  //! Prints the table content - NOT YET IMPLEMENTED !
-  void              Print(int num, int nmax=1) const ;
-  
-//! Prints table definition and number of entries 
+  //! Prints  the table content (ascii dump)
+  virtual ostream&  Print(ostream& os, sa_size_t lstart, sa_size_t lend, 
+			  sa_size_t lstep=1) const ;
+  //! Prints  the table content (ascii dump) on stream \b os
+  inline ostream&   Print(ostream& os) const
+  { return Print(os, 0, NEntry(), 1); }
+  //! Prints  the table content (ascii dump) on stream \b os
+  inline ostream&   WriteASCII(ostream& os) const 
+  { return Print(os, 0, NEntry(), 1); }
+
+  
+  //! Prints table definition and number of entries 
   void              Show(ostream& os) const ; 
   //! Prints table definition and number of entries on the standard output stream \b cout
   inline void       Show() const { Show(cout) ; } 
   
+  //! Return the associated DVList (info) object. 
   DVList&           Info() const ; 
   
   // Remplissage depuis fichier ASCII 
-  int		    FillFromASCIIFile(string const& fn);
+  sa_size_t	    FillFromASCIIFile(istream& is, char clm='#', const char* sep=" \t");
   
   //-------------------------------------------------------------
@@ -175,4 +204,8 @@
   virtual string    LineHeaderToString() const;
   virtual string    LineToString(sa_size_t n) const;  
+
+  //! Return a table row (line), formatted and converted to a string
+  virtual string    TableRowToString(sa_size_t n, bool qstr, const char* sep=" ",
+				     int fw=12) const; 
 
   //  Pour la gestion de persistance PPF
Index: /trunk/SophyaLib/HiStats/datatable.cc
===================================================================
--- /trunk/SophyaLib/HiStats/datatable.cc	(revision 2830)
+++ /trunk/SophyaLib/HiStats/datatable.cc	(revision 2831)
@@ -79,4 +79,5 @@
       break;
     case DoubleField :
+    case DateTimeField :
       mDCols[sk].Share(a.mDCols[ska]); 
       break;
@@ -117,4 +118,5 @@
       break;
     case DoubleField :
+    case DateTimeField :
       mDCols[sk].Clone(a.mDCols[ska], true); 
       break;
@@ -214,4 +216,5 @@
     break;
   case DoubleField :
+  case DateTimeField :
     ser = mDCols.size();
     mDCols.push_back(SegDataBlock<r_8>(mSegSz));
Index: /trunk/SophyaLib/HiStats/fio_dtable.cc
===================================================================
--- /trunk/SophyaLib/HiStats/fio_dtable.cc	(revision 2830)
+++ /trunk/SophyaLib/HiStats/fio_dtable.cc	(revision 2831)
@@ -82,4 +82,5 @@
 	break;
       case BaseDataTable::DoubleField :
+      case BaseDataTable::DateTimeField :
 	s << dt->mDCols[sk]; 
 	break;
@@ -114,4 +115,5 @@
 	break;
       case BaseDataTable::DoubleField :
+      case BaseDataTable::DateTimeField :
 	s.PutPosTagTable(swdt->mDCols[sk].GetSwapPosTagTable()); 
 	break;
@@ -216,4 +218,5 @@
 	break;
       case BaseDataTable::DoubleField :
+      case BaseDataTable::DateTimeField :
 	s >> dt->mDCols[sk]; 
 	break;
@@ -255,4 +258,5 @@
 	break;
       case BaseDataTable::DoubleField :
+      case BaseDataTable::DateTimeField :
 	swpos.clear();
 	s.GetPosTagTable(swpos);
Index: /trunk/SophyaLib/HiStats/swppfdtable.cc
===================================================================
--- /trunk/SophyaLib/HiStats/swppfdtable.cc	(revision 2830)
+++ /trunk/SophyaLib/HiStats/swppfdtable.cc	(revision 2831)
@@ -17,10 +17,10 @@
    \warning 
    - When creating a table, the output PPF stream (POutPersist) must not be closed
-   (destroyed) before the call to the SwPPFDataTable object.
-   - It is not possible to make a complete (deep) copy of a table SwPPFDataTable
+   (destroyed) before the SwPPFDataTable object is written to the stream.
+   - It is not possible to make a complete (deep) copy of a SwPPFDataTable
    Copy constructor and equal operator shares the data.
-   - Although the destructor  DOES NOT save the 
-   table object itself to the memory. You have to use the << operator on the 
-   output PPF stream being used as swap
+   - The destructor  DOES NOT save the table object itself to the swap 
+   stream. The << operator should be used on the output PPF stream being 
+   used as swap in order to save the table. 
 
    \sa SOPHYA::MuTyV
@@ -92,5 +92,5 @@
   mYSwapper.SetInStream(*pis);
   mZSwapper.SetInStream(*pis);
-  mDSwapper.SetInStream(*pis);
+  mSSwapper.SetInStream(*pis);
 }
 
@@ -163,4 +163,5 @@
       break;
     case DoubleField :
+    case DateTimeField :
       mDCols[sk] = a.mDCols[ska]; 
       break;
@@ -196,4 +197,5 @@
       break;
     case DoubleField :
+    case DateTimeField :
       mDCols[sk].SwapOutBuffer();
       break;
@@ -293,4 +295,5 @@
     break;
   case DoubleField :
+  case DateTimeField :
     ser = mDCols.size();
     mDCols.push_back(SwSegDataBlock<r_8>( mDSwapper,mSegSz));
@@ -317,5 +320,5 @@
     break;
   case StringField :
-    ser = mDCols.size();
+    ser = mSCols.size();
     mSCols.push_back(SwSegDataBlock<string>(mSSwapper, mSegSz));
     mSColIdx.push_back(idx);
@@ -335,6 +338,6 @@
   // On est oblige de calculer les min-max lors du remplissage
   // On ne peut pas en effet 'relire' le swap pendant l'ecriture
-  mMin.push_back(0.);
-  mMax.push_back(0.);
+  mMin.push_back(9.E39);
+  mMax.push_back(-9.E39);
   mMinMaxNEnt.push_back(0);
 
