mummy  1.0.2
MummyLineOrientedTextFileReader.cxx
Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 //
00003 //  $Id: MummyLineOrientedTextFileReader.cxx 470 2009-06-12 17:43:02Z hoffman $
00004 //
00005 //  $Author: hoffman $
00006 //  $Date: 2009-06-12 13:43:02 -0400 (Fri, 12 Jun 2009) $
00007 //  $Revision: 470 $
00008 //
00009 //  Copyright (C) 2007 Kitware, Inc.
00010 //
00011 //----------------------------------------------------------------------------
00012 
00013 #include "MummyLineOrientedTextFileReader.h"
00014 #include "MummyLog.h"
00015 #include "MummySettings.h"
00016 
00017 #include "gxsys/RegularExpression.hxx"
00018 #include "gxsys/ios/fstream"
00019 #include "gxsys/ios/sstream"
00020 
00021 
00022 //----------------------------------------------------------------------------
00023 MummyLineOrientedTextFileReader::MummyLineOrientedTextFileReader()
00024 {
00025   //this->FileName; // correctly constructed empty
00026   //this->Lines; // correctly constructed empty
00027   this->ExcludeMarkedLines = false;
00028   //this->BeginExcludeRegex; // correctly constructed empty
00029   //this->EndExcludeRegex; // correctly constructed empty
00030 }
00031 
00032 
00033 //----------------------------------------------------------------------------
00034 MummyLineOrientedTextFileReader::~MummyLineOrientedTextFileReader()
00035 {
00036 }
00037 
00038 
00039 //----------------------------------------------------------------------------
00040 gxsys_stl::string MummyLineOrientedTextFileReader::GetFileName()
00041 {
00042   return this->FileName;
00043 }
00044 
00045 
00046 //----------------------------------------------------------------------------
00047 void MummyLineOrientedTextFileReader::SetFileName(const char *filename)
00048 {
00049   if (filename)
00050     {
00051     this->FileName = filename;
00052     }
00053   else
00054     {
00055     this->FileName = "";
00056     }
00057 
00058   this->Update();
00059 }
00060 
00061 
00062 //----------------------------------------------------------------------------
00063 bool MummyLineOrientedTextFileReader::GetExcludeMarkedLines()
00064 {
00065   return this->ExcludeMarkedLines;
00066 }
00067 
00068 
00069 //----------------------------------------------------------------------------
00070 void MummyLineOrientedTextFileReader::SetExcludeMarkedLines(bool excludeMarkedLines)
00071 {
00072   this->ExcludeMarkedLines = excludeMarkedLines;
00073 }
00074 
00075 
00076 //----------------------------------------------------------------------------
00077 gxsys_stl::string MummyLineOrientedTextFileReader::GetBeginExcludeRegex()
00078 {
00079   return this->BeginExcludeRegex;
00080 }
00081 
00082 
00083 //----------------------------------------------------------------------------
00084 void MummyLineOrientedTextFileReader::SetBeginExcludeRegex(const gxsys_stl::string& beginExcludeRegex)
00085 {
00086   this->BeginExcludeRegex = beginExcludeRegex;
00087 }
00088 
00089 
00090 //----------------------------------------------------------------------------
00091 gxsys_stl::string MummyLineOrientedTextFileReader::GetEndExcludeRegex()
00092 {
00093   return this->EndExcludeRegex;
00094 }
00095 
00096 
00097 //----------------------------------------------------------------------------
00098 void MummyLineOrientedTextFileReader::SetEndExcludeRegex(const gxsys_stl::string& endExcludeRegex)
00099 {
00100   this->EndExcludeRegex = endExcludeRegex;
00101 }
00102 
00103 
00104 //----------------------------------------------------------------------------
00105 void MummyLineOrientedTextFileReader::Update()
00106 {
00107   gxsys_ios::ifstream file(this->GetFileName().c_str());
00108 
00109   this->Lines.clear();
00110 
00111   if (file)
00112     {
00113     char line[4100];
00114 
00115     bool trackBtxEtxLevel = !this->GetBeginExcludeRegex().empty() &&
00116       !this->GetEndExcludeRegex().empty();
00117     int btxEtxLevel = 0;
00118     bool isLineComment = false;
00119 
00120     gxsys::RegularExpression reLineComment;
00121     reLineComment.compile("^[\\t ]*//");
00122 
00123     gxsys::RegularExpression reBTX;
00124     gxsys::RegularExpression reETX;
00125     if (trackBtxEtxLevel)
00126       {
00127       reBTX.compile(this->GetBeginExcludeRegex().c_str());
00128       reETX.compile(this->GetEndExcludeRegex().c_str());
00129       }
00130     //
00131     // Old hard-coded values were eerily similar to BTX/ETX regexes found in
00132     // the VTK source tree in Wrapping/vtkParse.l... ;)
00133     //
00134     //reBTX.compile("^[\\t ]*//BTX.*$");
00135     //reETX.compile("^[\\t ]*//ETX.*$");
00136 
00137     while (!file.eof())
00138       {
00139       line[0] = 0;
00140       file.getline(line, 4099);
00141 
00142       isLineComment = reLineComment.find(line);
00143 
00144       if (trackBtxEtxLevel && reBTX.find(line))
00145         {
00146         btxEtxLevel++;
00147         }
00148 
00149       this->Lines.push_back(LineData(line, isLineComment, btxEtxLevel));
00150 
00151       if (trackBtxEtxLevel && reETX.find(line))
00152         {
00153         btxEtxLevel--;
00154         }
00155       }
00156     }
00157 
00158 
00159 #if 0
00160   // Dump it out with Trace to see what the settings and the output
00161   // data look like... This is a Print-method-in-waiting...
00162   //
00163   gxsys_stl::ostringstream oss;
00164 
00165   oss << "FileName: " << this->FileName << gxsys_stl::endl;
00166   oss << "ExcludeMarkedLines: " << this->ExcludeMarkedLines << gxsys_stl::endl;
00167   oss << "BeginExcludeRegex: " << this->BeginExcludeRegex << gxsys_stl::endl;
00168   oss << "EndExcludeRegex: " << this->EndExcludeRegex << gxsys_stl::endl;
00169 
00170   oss << "Lines:" << gxsys_stl::endl;
00171 
00172   unsigned int i = 1;
00173   gxsys_stl::vector<LineData>::iterator itLines;
00174 
00175   for (itLines = this->Lines.begin(); itLines != this->Lines.end();
00176     ++itLines)
00177     {
00178     LineData line = *itLines;
00179 
00180     // Comment?
00181     //
00182     if (line.IsLineComment)
00183       {
00184       oss << "C | ";
00185       }
00186     else
00187       {
00188       oss << "  | ";
00189       }
00190 
00191     // BTX/ETX level:
00192     //
00193     if (line.BtxEtxLevel)
00194       {
00195 
00196       oss << line.BtxEtxLevel;
00197 
00198 
00199       oss << " | ";
00200       }
00201     else
00202       {
00203       oss << "  | ";
00204       }
00205 
00206     // Line number, i - 4 digits with leading zeroes:
00207     //
00208     char f = oss.fill();
00209     gxsys_stl::streamsize w = oss.width();
00210     oss.fill('0');
00211     oss.width(4);
00212     oss << i;
00213     oss.fill(f);
00214     oss.width(w);
00215 
00216     // The line itself:
00217     //
00218     oss << ": " << line.Line << gxsys_stl::endl;
00219 
00220     ++i;
00221     }
00222 
00223   Trace(oss.str().c_str());
00224 #endif
00225 }
00226 
00227 
00228 //----------------------------------------------------------------------------
00229 unsigned int MummyLineOrientedTextFileReader::GetNumberOfLines()
00230 {
00231   return static_cast<unsigned int>(this->Lines.size());
00232 }
00233 
00234 
00235 //----------------------------------------------------------------------------
00236 gxsys_stl::string MummyLineOrientedTextFileReader::GetLine(unsigned int lineNumber)
00237 {
00238   if (lineNumber<1 || lineNumber>this->GetNumberOfLines())
00239     {
00240     LogWarning(mw_NoSuchLineNumber, "lineNumber out of range in GetLine");
00241     return "";
00242     }
00243 
00244   return this->Lines.at(lineNumber-1).Line;
00245 }
00246 
00247 
00248 //----------------------------------------------------------------------------
00249 bool MummyLineOrientedTextFileReader::GetIsLineComment(unsigned int lineNumber)
00250 {
00251   if (lineNumber<1 || lineNumber>this->GetNumberOfLines())
00252     {
00253     LogWarning(mw_NoSuchLineNumber, "lineNumber out of range in GetIsLineComment");
00254     return false;
00255     }
00256 
00257   return this->Lines.at(lineNumber-1).IsLineComment;
00258 }
00259 
00260 
00261 //----------------------------------------------------------------------------
00262 int MummyLineOrientedTextFileReader::GetBtxEtxLevel(unsigned int lineNumber)
00263 {
00264   if (lineNumber<1 || lineNumber>this->GetNumberOfLines())
00265     {
00266     LogWarning(mw_NoSuchLineNumber, "lineNumber out of range in GetBtxEtxLevel");
00267     return 0;
00268     }
00269 
00270   return this->Lines.at(lineNumber-1).BtxEtxLevel;
00271 }
00272 
00273 
00274 //----------------------------------------------------------------------------
00275 bool MummyLineOrientedTextFileReader::IsLineExcluded(unsigned int lineNumber)
00276 {
00277   return this->GetExcludeMarkedLines() &&
00278     this->GetBtxEtxLevel(lineNumber) > 0;
00279 }
00280 
00281 
00282 //----------------------------------------------------------------------------
00283 void MummyLineOrientedTextFileReader::GetCommentBlockBefore(unsigned int lineNumber, gxsys_stl::vector<gxsys_stl::string>& block, unsigned int smallestAcceptableLineNumber)
00284 {
00285   if (lineNumber<2 || lineNumber>this->GetNumberOfLines())
00286     {
00287     LogWarning(mw_NoSuchLineNumber, "lineNumber out of range in GetCommentBlockBefore");
00288     return;
00289     }
00290 
00291   // We seek the comment block before a class or method declaration in a
00292   // header file. Like this line-numbered example from vtkObject.h:
00293   //
00294   //    52:
00295   //    53:  // Description:
00296   //    54:  // Create an object with Debug turned off, modified time initialized
00297   //    55:  // to zero, and reference counting on.
00298   //    56:  static vtkObject *New();
00299   //    57:
00300   //
00301   // If given lineNumber==56 as input, we should compute begin==53 and end==55
00302   // and return the comment block as a vector of line strings from
00303   // begin to end inclusive...
00304 
00305   unsigned int begin = 0;
00306   unsigned int end = 0;
00307   unsigned int i = lineNumber;
00308 
00309   // Find the first comment before lineNumber, saving its index in 'end'.
00310   // If no line comments occur before lineNumber, end will be 0.
00311   //
00312   while (0 == end && i>1)
00313     {
00314     i--;
00315     if (GetIsLineComment(i) && 0==GetBtxEtxLevel(i))
00316       {
00317       end = i;
00318       }
00319     }
00320 
00321   // Now find the first non-comment before end, saving the index of the comment
00322   // line *after* it in 'begin'.
00323   //
00324   if (0 != end)
00325     {
00326     while (0 == begin && i>1)
00327       {
00328       i--;
00329       if (!GetIsLineComment(i) && 0==GetBtxEtxLevel(i))
00330         {
00331         begin = i + 1;
00332         }
00333       }
00334 
00335     // Didn't find a non-comment line before 'end'... Comment block must start
00336     // right at line 1.
00337     //
00338     if (0 == begin)
00339       {
00340       begin = 1;
00341       }
00342     }
00343 
00344   // If end==0 then there are no comment lines prior to lineNumber.
00345   //
00346   if (0 == end)
00347     {
00348     LogFileLineWarningMsg(this->FileName.c_str(), lineNumber, mw_UndocumentedEntity,
00349       "No comment lines prior to line " << lineNumber << ". Undocumented class or method?");
00350     }
00351   else if (smallestAcceptableLineNumber > begin)
00352         {
00353         block.push_back(std::string("//Undocumented Block"));
00354         }
00355   else
00356     {
00357     gxsys_stl::string s;
00358 
00359     gxsys::RegularExpression reBeginsWithWhiteSpace;
00360     reBeginsWithWhiteSpace.compile("^([\\t ]*)[^\\t ].*");
00361     size_t from = 0;
00362     size_t to = 0;
00363 
00364     for (i= begin; i<=end; ++i)
00365           {
00366       s = GetLine(i);
00367 
00368       if (reBeginsWithWhiteSpace.find(s))
00369         {
00370         from = reBeginsWithWhiteSpace.match(1).size();
00371         to = s.size() - from;
00372         s = s.substr(from, to);
00373         }
00374 
00375       block.push_back(s);
00376       }
00377     }
00378 }
00379 
00380 
00381 //----------------------------------------------------------------------------
00382 void MummyLineOrientedTextFileReader::GetFirstCommentBlock(gxsys_stl::vector<gxsys_stl::string>& block)
00383 {
00384   // Find the first non-comment line after the first comment line and use it
00385   // to call GetCommentBlockBefore...
00386   //
00387   unsigned int i = 1;
00388   unsigned int n = this->GetNumberOfLines();
00389   bool foundFirstComment = false;
00390 
00391   for (i= 1; i<=n; ++i)
00392     {
00393     if (this->GetIsLineComment(i) && 0==GetBtxEtxLevel(i))
00394       {
00395       foundFirstComment = true;
00396       }
00397     else if (foundFirstComment)
00398       {
00399             this->GetCommentBlockBefore(i+1, block, 1);
00400           break;
00401       }
00402     }
00403 }