Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

cmt_awk.cxx

Go to the documentation of this file.
00001 //-----------------------------------------------------------
00002 // Copyright Christian Arnault LAL-Orsay CNRS
00003 // arnault@lal.in2p3.fr
00004 // See the complete license in cmt_license.txt "http://www.cecill.info". 
00005 //-----------------------------------------------------------
00006 
00007 #ifdef WIN32
00008 #include <direct.h>
00009 #define popen _popen
00010 #define pclose _pclose
00011 #endif
00012 
00013 #include "cmt_awk.h"
00014 #include "cmt_system.h"
00015 
00016 class Parser
00017 {
00018 public:
00019   Parser (Awk* awk, const cmt_string pattern, const cmt_regexp* expression) :
00020           m_pattern (pattern), m_expression (expression), m_awk(awk)
00021       {
00022       }
00023 
00030   Awk::condition parse (const cmt_string& text)
00031       {
00032         Awk::condition result = Awk::ok;
00033 
00034         cmt_string line;
00035         int pos;
00036         int max_pos;
00037 
00038         pos = 0;
00039         max_pos = text.size ();
00040 
00041         m_accumulator.erase (0);
00042 
00043         for (pos = 0; pos < max_pos;)
00044           {
00045             int eol = text.find (pos, '\n');
00046             
00047             if (eol == cmt_string::npos)
00048               {
00049                   // Last line, since there is no eol at all
00050                 text.substr (pos, line);
00051                 pos = max_pos;
00052               }
00053             else
00054               {
00055                 int length = 1;
00056 
00057                 int cr = text.find (pos, "\r\n");
00058 
00059                 if (cr == (eol-1))
00060                   {
00061                     eol = cr;
00062                     length = 2;
00063                   }
00064 
00065                 if (eol == pos)
00066                   {
00067                       // this is an empty line
00068                     line = "";
00069                     pos += length;
00070                   }
00071                 else
00072                   {
00073                       // The eol was found beyond the current position
00074                       // (ie. this is a non empty line)
00075                     text.substr (pos, eol - pos, line);
00076                     pos = eol + length;
00077                   }
00078               }
00079 
00080             if (m_awk != 0) m_awk->inc_line_number ();
00081 
00082               //cout << "parse> line=[" << line << "]" << endl;
00083 
00084             result = parse_line (line);
00085             if (result != Awk::ok) break;
00086           }
00087 
00088         return (result);
00089       }
00090 
00098   Awk::condition parse_line (const cmt_string& line)
00099       {
00100         Awk::condition result = Awk::ok;
00101         int length;
00102         cmt_string temp_line = line;
00103 
00104           //
00105           // We scan the line for handling backslashes.
00106           //
00107           // Really terminating backslashes (ie those only followed by spaces/tabs
00108           // mean continued line
00109           //
00110           //
00111 
00112         bool finished = true;
00113 
00114         length = temp_line.size ();
00115 
00116         if (length == 0)
00117           {
00118               // An empty line following a backslash terminates the continuation.
00119             finished = true;
00120           }
00121         else
00122           {
00123             int back_slash = temp_line.find_last_of ('\\');
00124         
00125             if (back_slash != cmt_string::npos)
00126               {
00127                   //
00128                   // This is the last backslash
00129                   // check if there are only space chars after it
00130                   //
00131             
00132                 bool at_end = true;
00133             
00134                 for (int i = (back_slash + 1); i < length; i++)
00135                   {
00136                     char c = temp_line[i];
00137                     if ((c != ' ') && (c != '\t'))
00138                       {
00139                         at_end = false;
00140                         break;
00141                       }
00142                   }
00143                 
00144                 if (at_end)
00145                   {
00146                     temp_line.erase (back_slash);
00147                     finished = false;
00148                   }
00149                 else
00150                   {
00151                       // This was not a trailing backslash.
00152                     finished = true;
00153                   }
00154               }
00155         
00156             m_accumulator += temp_line;
00157           }
00158 
00159           //cout << "parse_line1> accumulator=[" << m_accumulator << "]" << endl;
00160           //cout << "parse_line1> finished=[" << finished << "]" << endl;
00161 
00162         if (!finished)
00163           {
00164               // We still need to accumulate forthcoming lines
00165               // before parsing the resulting text.
00166             return (Awk::ok);
00167           }
00168 
00169           // now filter the complete accumulated line (if non empty)
00170 
00171         if (m_accumulator != "")
00172           {
00173             bool ok = false;
00174             
00175             if (m_expression != 0)
00176               {
00177                 if (m_expression->match (m_accumulator))
00178                   {
00179                     ok = true;
00180                   }
00181               }
00182             else
00183               {
00184                 if ((m_pattern == "") ||
00185                     (m_accumulator.find (m_pattern) != cmt_string::npos))
00186                   {
00187                     ok = true;
00188                   }
00189               }
00190             
00191             if (ok && (m_awk != 0))
00192               {
00193                   //cout << "parse_line> accumulator=[" << m_accumulator << "]" << endl;
00194 
00195                 m_awk->filter (m_accumulator);
00196                 result = m_awk->get_last_condition ();
00197               }
00198 
00199             m_accumulator.erase (0);
00200           }
00201         
00202         return (result);
00203       }
00204 
00205 private:
00206 
00207   cmt_string m_accumulator;
00208   cmt_string m_pattern;
00209   const cmt_regexp* m_expression;
00210   Awk* m_awk;
00211 };
00212 
00213 //------------------------------------------------
00214 Awk::Awk ()
00215 {
00216   m_condition = ok;
00217 }
00218 
00219 //------------------------------------------------
00220 Awk::~Awk ()
00221 {
00222 }
00223 
00224 //------------------------------------------------
00225 Awk::condition Awk::run (const cmt_string& text,
00226                          const cmt_string& pattern)
00227 {
00228   m_line_number = 0;
00229   m_condition = ok;
00230 
00231   begin ();
00232   if (m_condition != ok) return (m_condition);
00233 
00234   if (CmtSystem::testenv ("CMTTESTAWK"))
00235     {
00236       Parser p (this, pattern, 0);
00237 
00238       m_condition = p.parse (text);
00239       if (m_condition != ok) return (m_condition);
00240     }
00241   else
00242     {
00243       cmt_string line;
00244       int pos = 0;
00245       int max_pos;
00246 
00247       max_pos = text.size ();
00248 
00249       for (pos = 0; pos < max_pos;)
00250         {
00251           int cr = text.find (pos, "\r\n");
00252           int nl = text.find (pos, '\n');
00253           
00254             // Get the first end-of-line (either lf or cr-lf)
00255 
00256             //--------------------
00257             //
00258             //     cr    1    0
00259             //   nl
00260             //
00261             //    1      a    b
00262             //
00263             //    0      c    d
00264             //
00265             //--------------------
00266           
00267           int first = nl;
00268           
00269           if (cr != cmt_string::npos)
00270             {
00271                 // cases a or c
00272 
00273               if (nl == cmt_string::npos)
00274                 {
00275                     // case a
00276                   first = cr;
00277                 }
00278               else
00279                 {
00280                     // case c
00281                   first = (nl < cr) ? nl : cr;
00282                 }
00283             }
00284           
00285           if (first == cmt_string::npos)
00286             {
00287                 // This is likely the last line since there is no end-of-line
00288               text.substr (pos, line);
00289               pos = max_pos;
00290             }
00291           else if (first > pos)
00292             {
00293                 // The eol was found beyond the current position
00294                 // (ie. this is a non empty line)
00295               text.substr (pos, first - pos, line);
00296               pos = first + 1;
00297             }
00298           else
00299             {
00300                 // an empty line
00301               line = "";
00302               pos++;
00303             }
00304           
00305           m_line_number++;
00306           
00307           if (line != "")
00308             {
00309               if ((pattern == "") ||
00310                   (line.find (pattern) != cmt_string::npos))
00311                 {
00312                   filter (line);
00313                   if (m_condition != ok) return (m_condition);
00314                 }
00315             }
00316         }
00317     }
00318 
00319   end ();
00320 
00321   return (m_condition);
00322 }
00323 
00324 //------------------------------------------------
00325 Awk::condition Awk::run (const cmt_string& text,
00326                          const cmt_regexp& expression)
00327 {
00328   m_line_number = 0;
00329   m_condition = ok;
00330 
00331   begin ();
00332   if (m_condition != ok) return (m_condition);
00333 
00334   Parser p (this, "", &expression);
00335 
00336   m_condition = p.parse (text);
00337   if (m_condition != ok) return (m_condition);
00338 
00339     /*
00340   if (CmtSystem::testenv ("CMTTESTAWK"))
00341     {
00342     }
00343   else
00344     {
00345       cmt_string line;
00346       int pos = 0;
00347       int max_pos;
00348 
00349       max_pos = text.size ();
00350 
00351       for (pos = 0; pos < max_pos;)
00352         {
00353           int cr = text.find (pos, "\r\n");
00354           int nl = text.find (pos, '\n');
00355           
00356             // Get the first end-of-line (either lf or cr-lf)
00357           
00358           int first = nl;
00359           
00360           if (cr != cmt_string::npos)
00361             {
00362               if (nl == cmt_string::npos)
00363                 {
00364                   first = cr;
00365                 }
00366               else
00367                 {
00368                   first = (nl < cr) ? nl : cr;
00369                 }
00370             }
00371           
00372           if (first == cmt_string::npos)
00373             {
00374                 // This is likely the last line since there is no end-of-line
00375               text.substr (pos, line);
00376               pos = max_pos;
00377             }
00378           else if (first > pos)
00379             {
00380                 // The eol was found beyond the current position
00381                 // (ie. this is a non empty line)
00382               text.substr (pos, first - pos, line);
00383               pos = first + 1;
00384             }
00385           else
00386             {
00387                 // an empty line
00388               line = "";
00389               pos++;
00390             }
00391           
00392           m_line_number++;
00393           
00394           if (line != "")
00395             {
00396               if (expression.match (line))
00397                 {
00398                   filter (line);
00399                   if (m_condition != ok) return (m_condition);
00400                 }
00401             }
00402         }
00403     }
00404     */
00405 
00406   end ();
00407 
00408   return (m_condition);
00409 }
00410 
00411 //------------------------------------------------
00412 void Awk::stop ()
00413 {
00414   m_condition = stopped;
00415 }
00416 
00417 //------------------------------------------------
00418 void Awk::abort ()
00419 {
00420   m_condition = failed;
00421 }
00422 
00423 //------------------------------------------------
00424 void Awk::allow_continuation ()
00425 {
00426   m_continuation_allowed = true;
00427 }
00428 
00429 //------------------------------------------------
00430 Awk::condition Awk::get_last_condition () const
00431 {
00432   return (m_condition);
00433 }
00434 
00435 //------------------------------------------------
00436 void Awk::begin ()
00437 {
00438 }
00439 
00440 //------------------------------------------------
00441 void Awk::filter (const cmt_string& /*line*/)
00442 {
00443     //cout << "awk> " << line << endl;
00444 }
00445 
00446 //------------------------------------------------
00447 void Awk::end ()
00448 {
00449 }
00450 
00451 //------------------------------------------------
00452 void Awk::inc_line_number ()
00453 {
00454   m_line_number++;
00455 }
00456 
00457 //------------------------------------------------
00458 Awk::condition FAwk::run (const cmt_string& file_name,
00459                           const cmt_string& pattern)
00460 {
00461   if (!CmtSystem::test_file (file_name)) return (failed);
00462 
00463   CmtSystem::basename (file_name, m_file_name);
00464   CmtSystem::dirname (file_name, m_dir_name);
00465 
00466   cmt_string text;
00467 
00468   text.read (file_name);
00469 
00470   return (Awk::run (text, pattern));
00471 }
00472 
00473 //------------------------------------------------
00474 Awk::condition FAwk::run (const cmt_string& file_name,
00475                           const cmt_regexp& expression)
00476 {
00477   if (!CmtSystem::test_file (file_name)) return (failed);
00478 
00479   CmtSystem::basename (file_name, m_file_name);
00480   CmtSystem::dirname (file_name, m_dir_name);
00481 
00482   cmt_string text;
00483 
00484   text.read (file_name);
00485 
00486   return (Awk::run (text, expression));
00487 }
00488 
00489 //------------------------------------------------
00490 Awk::condition PAwk::run (const cmt_string& command, 
00491                           const cmt_string& pattern)
00492 {
00493   cmt_string line;
00494 
00495   m_line_number = 0;
00496   m_condition = ok;
00497 
00498   begin ();
00499   if (m_condition != ok) return (m_condition);
00500 
00501   FILE* f = popen (command.c_str (), "r"); 
00502   
00503   if (f == 0) return (failed);
00504 
00505   char buffer[8192]; 
00506   char* ptr;
00507 
00508   while ((ptr = fgets (buffer, sizeof (buffer), f)) != NULL) 
00509     {
00510       line = ptr;
00511 
00512       if (line.find ("\n") == cmt_string::npos)
00513         {
00514           cerr << "#CMT> Warning: Line too long and truncated in PAwk::run for command " << command << endl;
00515         }
00516 
00517       line.replace ("\n", "");
00518 
00519       m_line_number++;
00520 
00521       if (line != "")
00522         {
00523           if ((pattern == "") ||
00524               (line.find (pattern) != cmt_string::npos))
00525             {
00526               filter (line);
00527               if (m_condition != ok) return (m_condition);
00528             }
00529         }
00530     }
00531 
00532   pclose (f);
00533 
00534   end ();
00535 
00536   return (m_condition);
00537 }
00538 
00539 //------------------------------------------------
00540 Awk::condition PAwk::run (const cmt_string& command, 
00541                           const cmt_regexp& expression)
00542 {
00543   cmt_string line;
00544 
00545   m_line_number = 0;
00546   m_condition = ok;
00547 
00548   begin ();
00549   if (m_condition != ok) return (m_condition);
00550 
00551   FILE* f = popen (command.c_str (), "r"); 
00552   
00553   if (f == 0) return (failed);
00554 
00555   char buffer[256]; 
00556   char* ptr;
00557 
00558   while ((ptr = fgets (buffer, sizeof (buffer), f)) != NULL) 
00559     {
00560       line = ptr;
00561 
00562       line.replace ("\n", "");
00563 
00564       m_line_number++;
00565 
00566       if (line != "")
00567         {
00568           if (expression.match (line))
00569             {
00570               filter (line);
00571               if (m_condition != ok) return (m_condition);
00572             }
00573         }
00574     }
00575 
00576   pclose (f);
00577 
00578   end ();
00579 
00580   return (m_condition);
00581 }
00582 
00583 //----------------------------------------------------------
00584 PathScanner::PathScanner ()
00585 {
00586   _running = false;
00587   _level = 0;
00588 }
00589 
00590 //----------------------------------------------------------
00591 bool PathScanner::scan_path (const cmt_string& path, actor& a)
00592 {
00593   if (_running) return (false);
00594 
00595   _level = 0;
00596   _running = true;
00597 
00598   cmt_string compressed_path = path;
00599   CmtSystem::compress_path (compressed_path);
00600   scan_path (compressed_path, 0, a);
00601 
00602   _running = false;
00603   _level = 0;
00604 
00605   return (true);
00606 }
00607 
00608 //----------------------------------------------------------
00609 void PathScanner::scan_path (const cmt_string& path, int level, actor& a)
00610 {
00611   if (level > 10)
00612     {
00613       //cout << "#PathScanner::scan_path> too deep search path=" << path << endl;
00614       return;
00615     }
00616 
00617   //
00618   // Only do something if it is a directory.
00619   //
00620 
00621   if (!CmtSystem::test_directory (path)) return;
00622 
00623   CmtSystem::cmt_string_vector list;
00624   CmtSystem::cmt_string_vector entrylist;
00625 
00626   CmtSystem::scan_dir (path, list);
00627 
00628   if (list.size () == 0) return;
00629 
00630   _level++;
00631 
00632   // Will be set if at least one directory is a version directory
00633   bool has_package = false;
00634 
00635   cmt_string name;
00636   cmt_string version;
00637   cmt_string where;
00638 
00639   int i;
00640 
00641   for (i = 0; i < list.size (); i++)
00642     {
00643       const cmt_string& here = list[i];
00644 
00645       if (!CmtSystem::test_directory (here)) continue;
00646 
00647       name = "";
00648       version = "";
00649 
00650       cmt_string entry;
00651       CmtSystem::basename (here, entry);
00652       CmtSystem::dirname (path, where);
00653 
00654       // cout << "## here=" << here << " entry=" << entry << " where=" << where << endl;
00655 
00656       if ((level == 0) && (entry == "InstallArea")) continue;
00657 
00658       cmt_string req;
00659 
00660       req = here;
00661       req += CmtSystem::file_separator ();
00662       req += "mgr";
00663       req += CmtSystem::file_separator ();
00664       req += "requirements";
00665 
00666       if (CmtSystem::test_file (req))
00667         {
00668           // We have found <path>/mgr/requirements
00669           // this is an old directory convention. 
00670           // The version directory is the directory above
00671 
00672           version = entry;
00673           CmtSystem::basename (path, name);
00674 
00675           // cout << "#1" << endl;
00676 
00677           a.run (name, version, where);
00678           has_package = true;
00679 
00680           continue;
00681         }
00682 
00683       req = here;
00684       req += CmtSystem::file_separator ();
00685       req += "cmt";
00686       req += CmtSystem::file_separator ();
00687       req += "requirements";
00688 
00689       if (CmtSystem::test_file (req))
00690         {
00691           // We have found <path>/cmt/requirements
00692           // Question now is to detect the directory structure:
00693           //
00694           // if cmt/version.cmt exists it's a non-version-directory structure
00695           // else
00696           //   if there is a package statement in the requirements file we find it upward
00697           //   else
00698           //     if up is a version directory
00699           //     else
00700           //
00701 
00702           cmt_string vreq;
00703           vreq = here;
00704           vreq += CmtSystem::file_separator ();
00705           vreq += "cmt";
00706           vreq += CmtSystem::file_separator ();
00707           vreq += "version.cmt";
00708 
00709           if (CmtSystem::test_file (vreq))
00710             {
00711               version.read (vreq);
00712               int pos;
00713               pos = version.find ('\n');
00714               if (pos != cmt_string::npos) version.erase (pos);
00715               pos = version.find ('\r');
00716               if (pos != cmt_string::npos) version.erase (pos);
00717 
00718               //cout << "#2" << endl;
00719 
00720               a.run (entry, version, path);
00721               has_package = true;
00722               
00723               continue;
00724             }
00725 
00726           cmt_string p;
00727 
00728           p.read (req);
00729           int pos;
00730           pos = p.find ("package");
00731           if (pos != cmt_string::npos)
00732             {
00733               p.erase (0, pos+8);
00734               pos = p.find ('\n');
00735               if (pos != cmt_string::npos) p.erase (pos);
00736               pos = p.find ('\r');
00737               if (pos != cmt_string::npos) p.erase (pos);
00738               p.replace_all (" ", "");
00739               p.replace_all ("\t", "");
00740               if (p != "") name = p;
00741             }
00742 
00743           if (name != "")
00744             {
00745               // The package name was specified in the requirements file
00746 
00747               if (entry == name)
00748                 {
00749                   // The structure is without the version directory.
00750 
00751                   //cout << "#3" << endl;
00752 
00753                   a.run (name, "v1", path);
00754                   has_package = true;
00755                   
00756                   continue;
00757                 }
00758               
00759               version = entry;
00760               CmtSystem::basename (path, entry);
00761               
00762               if (entry == name)
00763                 {
00764                   // The structure is with the version directory.
00765                   
00766                   //cout << "#4" << endl;
00767 
00768                   a.run (name, version, where);
00769                   has_package = true;
00770                   
00771                   continue;
00772                 }
00773 
00774               // No directory structure matches the package name
00775               // Is it a typo in the requirements file ?
00776               // probably we should display it and quit...
00777             }
00778           else
00779             {
00780               version = entry;
00781               CmtSystem::basename (path, entry);
00782             }
00783 
00784           // The package name is not specified in the requirements file
00785           // or did not match the directory structure
00786           // We'll have to guess it from the structure
00787               
00788           if (CmtSystem::is_version_directory (version))
00789             {
00790               // cout << "#5" << endl;
00791 
00792               a.run (entry, version, where);
00793               has_package = true;
00794               
00795               continue;
00796             }
00797 
00798           name = version;
00799 
00800           where += CmtSystem::file_separator ();
00801           where += entry;
00802 
00803           // cout << "#6" << endl;
00804 
00805           a.run (name, "v1", where);
00806           has_package = true;
00807           
00808           continue;
00809         }
00810 
00811       //cout << "#7" << endl;
00812 
00813       scan_path (here, level + 1, a);
00814     }
00815 
00816   if (has_package)
00817     {
00818       //
00819       // At least one version was found here. Thus we want to scan further down.
00820       //
00821 
00822       for (i = 0; i < entrylist.size (); i++)
00823         {
00824           const cmt_string& e = entrylist[i];
00825 
00826           cmt_string p = path;
00827           p += CmtSystem::file_separator ();
00828           p += e;
00829 
00830             /*
00831           for (j = 1; j < _level; j++) cout << "  ";
00832           cout << "Restarting scan_path on p=" << p << endl;
00833             */
00834 
00835           cout << "#PathScanner::scan_path> Restarting scan_path on p=" << p << endl;
00836 
00837 
00838           scan_path (p, 1, a);
00839         }
00840     }
00841 
00842   _level--;
00843 }
00844 
00845 
00846 //----------------------------------------------------------
00847 bool PathScanner::scan_package (const cmt_string& path,
00848                                 const cmt_string& package)
00849 {
00850   //
00851   // Only do something if it is a directory.
00852   //
00853 
00854   if (!CmtSystem::test_directory (path)) return (false);
00855 
00856   cmt_string pattern = path;
00857   pattern += CmtSystem::file_separator ();
00858   pattern += package;
00859 
00860   if (!CmtSystem::test_directory (pattern)) return (false);
00861 
00862   CmtSystem::cmt_string_vector list;
00863 
00864   CmtSystem::scan_dir (pattern, list);
00865 
00866   if (list.size () == 0) 
00867     {
00868       return (false);
00869     }
00870 
00871   bool result = false;
00872 
00873   int i;
00874   for (i = 0; i < list.size (); i++)
00875     {
00876       const cmt_string& name = list[i];
00877 
00878       cmt_string version;
00879       CmtSystem::basename (name, version);
00880 
00881       if (version == "cmt")
00882         {
00883           cmt_string req;
00884 
00885           req = name;
00886           req += CmtSystem::file_separator ();
00887           req += "requirements";
00888 
00889           if (CmtSystem::test_file (req))
00890             {
00891               //cout << " -> no version" << endl;
00892 
00893               cmt_string req;
00894               
00895               req = name;
00896               req += CmtSystem::file_separator ();
00897               req += "version.cmt";
00898 
00899               cmt_string version;
00900               if (CmtSystem::test_file (req))
00901                 {
00902                   version.read (req);
00903                   int pos;
00904                   pos = version.find ('\n');
00905                   if (pos != cmt_string::npos) version.erase (pos);
00906                   pos = version.find ('\r');
00907                   if (pos != cmt_string::npos) version.erase (pos);
00908                 }
00909               else
00910                 {
00911                   version = "v*";
00912                 }
00913 
00914               cout << package << " " << version << " " << path << endl;
00915 
00916               result = true;
00917             }
00918         }
00919       else if (CmtSystem::is_version_directory (version))
00920         {
00921           cmt_string req;
00922 
00923           req = name;
00924           req += CmtSystem::file_separator ();
00925           req += "cmt";
00926           req += CmtSystem::file_separator ();
00927           req += "requirements";
00928 
00929           if (CmtSystem::test_file (req))
00930             {
00931               //cout << " -> cmt" << endl;
00932 
00933               cout << package << " " << version << " " << path << endl;
00934 
00935               result = true;
00936             }
00937           else
00938             {
00939               //cout << " -> no cmt" << endl;
00940 
00941               req = name;
00942               req += CmtSystem::file_separator ();
00943               req += "mgr";
00944               req += CmtSystem::file_separator ();
00945               req += "requirements";
00946 
00947               if (CmtSystem::test_file (req))
00948                 {
00949                   //cout << " -> mgr" << endl;
00950 
00951                   cout << package << " " << version << " " << path << endl;
00952 
00953                   result = true;
00954                 }
00955               else
00956                 {
00957                   //cout << " -> no mgr" << endl;
00958                 }
00959             }
00960         }
00961       else
00962         {
00963           //cout << " -> stop" << endl;
00964         }
00965     }
00966 
00967   return (result);
00968 }
00969 

Generated on Mon May 2 10:25:04 2005 for CMT by doxygen 1.3.5