Index: trunk/SophyaLib/HiStats/basedtable.cc
===================================================================
--- trunk/SophyaLib/HiStats/basedtable.cc	(revision 2827)
+++ 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;
   }
