Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

cmt_deps_builder.cxx

Go to the documentation of this file.
00001 
00002 #include "cmt_deps_builder.h"
00003 #include "cmt_system.h"
00004 #include "cmt_use.h"
00005 #include "cmt_include.h"
00006 #include "cmt_symbol.h"
00007 
00008 //
00009 //  While parsing a C++ file, these are the possible usefull
00010 // states we can reach.
00011 //  Each state correspond to a specific state action function.
00012 //
00013 enum state_def
00014 {
00015   at_start,                                // beginning of the file
00016   in_line,                                // along a line
00017   in_string,                        // inside a quoted string
00018   in_char,                                // inside a quoted char
00019   in_comment,                        // inside a multi-line comment
00020   in_string_comment,        // inside a quoted string in a comment
00021   in_char_comment,                // inside a quoted char in a comment
00022   in_line_comment                // inside a single-line comment
00023 };
00024 
00025 //--------------------------------------------------
00026 static int build_deps (const cmt_string& name,
00027                        const cmt_string& dir_name,
00028                        int current_path_index,
00029                        const CmtSystem::cmt_string_vector& include_paths,
00030                        const CmtSystem::cmt_string_vector& substitutions,
00031                        CmtSystem::cmt_string_vector& all_deps,
00032                        CmtSystem::cmt_string_vector& deps);
00033 //--------------------------------------------------
00034 
00035 
00036 //--------------------------------------------------
00037 static void header_file_action (const char* header_file,
00038                                 const cmt_string& dir_name,
00039                                 int current_path_index,
00040                                 const CmtSystem::cmt_string_vector& include_paths,
00041                                 const CmtSystem::cmt_string_vector& substitutions,
00042                                 CmtSystem::cmt_string_vector& all_deps,
00043                                 CmtSystem::cmt_string_vector& deps)
00044 {
00045   bool found = false;
00046 
00047   for (int i = 0; i < all_deps.size (); i++)
00048     {
00049       if (all_deps[i] == header_file)
00050         {
00051           found = true;
00052           break;
00053         }
00054     }
00055   
00056   if (!found)
00057     {
00058       all_deps.push_back (header_file);
00059       
00060       int path_index = build_deps (header_file,
00061                                    dir_name,
00062                                    current_path_index,
00063                                    include_paths,
00064                                    substitutions,
00065                                    all_deps,
00066                                    deps);
00067       
00068       if (path_index >= 0)
00069         {
00070           cmt_string full_name;
00071           
00072           if (path_index == 1)
00073             {
00074               full_name = dir_name;
00075               full_name += CmtSystem::file_separator ();
00076               
00077               if (current_path_index >= 2)
00078                 {
00079                   full_name.replace (include_paths[current_path_index - 2],
00080                                      substitutions[current_path_index - 2]);
00081                 }
00082             }
00083           else if (path_index > 1)
00084             {
00085               full_name  = substitutions[path_index - 2];
00086               full_name += CmtSystem::file_separator ();
00087             }
00088           
00089           full_name += header_file;
00090           
00091           deps.push_back (full_name);
00092         }
00093     }
00094 }
00095 
00096 
00097 //--------------------------------------------------
00098 static char* at_start_action (char* ptr,
00099                               state_def& state,
00100                               const cmt_string& dir_name,
00101                               int current_path_index,
00102                               const CmtSystem::cmt_string_vector& include_paths,
00103                               const CmtSystem::cmt_string_vector& substitutions,
00104                               CmtSystem::cmt_string_vector& all_deps,
00105                               CmtSystem::cmt_string_vector& deps)
00106 //--------------------------------------------------
00107 {
00108   char term = 0;
00109 
00110   if (*ptr == '#')
00111     {
00112       ptr++;
00113       while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
00114       if (!strncmp (ptr, "include", 7))
00115         {
00116           ptr += 7;
00117 
00118           while (*ptr == ' ') ptr++;
00119           if (*ptr == '<')
00120             {
00121               term = '>';
00122               ptr++;
00123             }
00124           else if (*ptr == '"')
00125             {
00126               term = '"';
00127               ptr++;
00128             }
00129           else
00130             {
00131               state = in_line;
00132               ptr += strlen (ptr);
00133               return (ptr);
00134             }
00135         }
00136       else
00137         {
00138           state = in_line;
00139           ptr += strlen (ptr);
00140           return (ptr);
00141         }
00142     }
00143   else if (!strncmp (ptr, "      include", 13))
00144     {
00145       ptr += 13;
00146 
00147       while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
00148       if (*ptr == '\'')
00149         {
00150           term = '\'';
00151           ptr++;
00152         }
00153       else
00154         {
00155           state = in_line;
00156           return (ptr);
00157         }
00158     }
00159   else if (!strncmp (ptr, "\tinclude", 8))
00160     {
00161       ptr += 8;
00162 
00163       while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
00164       if (*ptr == '\'')
00165         {
00166           term = '\'';
00167           ptr++;
00168         }
00169       else
00170         {
00171           state = in_line;
00172           return (ptr);
00173         }
00174     }
00175   else
00176     {
00177       state = in_line;
00178       return (ptr);
00179     }
00180 
00181   char* end;
00182 
00183   end = strchr (ptr, term);
00184   if (end != 0)
00185     {
00186       *end = 0;
00187     }
00188   
00189   const char* header_file = ptr;
00190   
00191   header_file_action (header_file,
00192                       dir_name,
00193                       current_path_index,
00194                       include_paths,
00195                       substitutions,
00196                       all_deps,
00197                       deps);
00198   
00199   if (end != 0)
00200     {
00201       *end = term;
00202     }
00203 
00204   state = in_line;
00205   ptr += strlen (ptr);
00206   
00207   return (ptr);
00208 }
00209 
00210 //--------------------------------------------------
00211 static char* in_line_action (char* ptr, state_def& state)
00212 //--------------------------------------------------
00213 {
00214   char* pattern = &ptr[strlen (ptr)];
00215 
00216   char* pos = strchr (ptr, '"');
00217   if (pos != 0)
00218     {
00219       if (pos < pattern)
00220         {
00221           state = in_string;
00222           pattern = pos;
00223         }
00224     }
00225 
00226   pos = strchr (ptr, '\'');
00227   if (pos != 0)
00228     {
00229       if (pos < pattern)
00230         {
00231           state = in_char;
00232           pattern = pos;
00233         }
00234     }
00235 
00236   pos = strstr (ptr, "/*");
00237   if (pos != 0)
00238     {
00239       if (pos < pattern)
00240         {
00241           state = in_comment;
00242           pattern = pos + 1;
00243         }
00244     }
00245 
00246   pos = strstr (ptr, "//");
00247   if (pos != 0)
00248     {
00249       if (pos < pattern)
00250         {
00251           state = in_line_comment;
00252           pattern = pos + 1;
00253         }
00254     }
00255 
00256   if (state != in_line)
00257     {
00258       ptr = pattern + 1;
00259     }
00260   else
00261     {
00262       ptr += strlen (ptr);
00263     }
00264 
00265   return (ptr);
00266 }
00267 
00268 //--------------------------------------------------
00269 static char* in_string_action (char* ptr, state_def& state)
00270 //--------------------------------------------------
00271 {
00272   char* pos = strchr (ptr, '"');
00273   if (pos == 0)
00274     {
00275         // This string is not finished till the end of the line..
00276         // we expect it continues to the nex line...
00277       ptr += strlen (ptr);
00278     }
00279   else
00280     {
00281       pos--;
00282       if (*pos == '\\')
00283         {
00284           ptr = pos + 2;
00285         }
00286       else
00287         {
00288           ptr = pos + 2;
00289           state = in_line;
00290         }
00291     }
00292 
00293   return (ptr);
00294 }
00295 
00296 //--------------------------------------------------
00297 static char* in_char_action (char* ptr, state_def& state)
00298 //--------------------------------------------------
00299 {
00300   char* pos = strchr (ptr, '\'');
00301   if (pos == 0)
00302     {
00303         // This string is not finished till the end of the line..
00304         // we expect it continues to the nex line...
00305       ptr += strlen (ptr);
00306     }
00307   else
00308     {
00309       pos--;
00310       if (*pos == '\\')
00311         {
00312           ptr = pos + 2;
00313         }
00314       else
00315         {
00316           ptr = pos + 2;
00317           state = in_line;
00318         }
00319     }
00320 
00321   return (ptr);
00322 }
00323 
00324 //--------------------------------------------------
00325 static char* in_comment_action (char* ptr, state_def& state)
00326 //--------------------------------------------------
00327 {
00328   char* pattern = &ptr[strlen (ptr)];
00329   char* pos = strchr (ptr, '"');
00330   if (pos != 0)
00331     {
00332       if (pos < pattern)
00333         {
00334           state = in_string_comment;
00335           pattern = pos;
00336         }
00337     }
00338   pos = strchr (ptr, '\'');
00339   if (pos != 0)
00340     {
00341       if (pos < pattern)
00342         {
00343           state = in_char_comment;
00344           pattern = pos;
00345         }
00346     }
00347   pos = strstr (ptr, "*/");
00348   if (pos != 0)
00349     {
00350       if (pos < pattern)
00351         {
00352           state = in_line;
00353           pattern = pos + 1;
00354         }
00355     }
00356 
00357   if (state == in_comment)
00358     {
00359       ptr += strlen (ptr);
00360     }
00361   else
00362     {
00363       ptr = pattern + 1;
00364     }
00365 
00366   return (ptr);
00367 }
00368 
00369 //--------------------------------------------------
00370 static char* in_string_comment_action (char* ptr, state_def& state)
00371 //--------------------------------------------------
00372 {
00373   char* pos = strchr (ptr, '"');
00374   if (pos == 0)
00375     {
00376         // This string is not finished till the end of the line..
00377         // we expect it continues to the nex line...
00378       ptr += strlen (ptr);
00379     }
00380   else
00381     {
00382       pos--;
00383       if (*pos == '\\')
00384         {
00385           ptr = pos + 2;
00386         }
00387       else
00388         {
00389           ptr = pos + 2;
00390           state = in_comment;
00391         }
00392     }
00393 
00394   return (ptr);
00395 }
00396 
00397 //--------------------------------------------------
00398 static char* in_char_comment_action (char* ptr, state_def& state)
00399 //--------------------------------------------------
00400 {
00401   char* pos = strchr (ptr, '\'');
00402   if (pos == 0)
00403     {
00404         // This string is not finished till the end of the line..
00405         // we expect it continues to the nex line...
00406       ptr += strlen (ptr);
00407     }
00408   else
00409     {
00410       pos--;
00411       if (*pos == '\\')
00412         {
00413           ptr = pos + 2;
00414         }
00415       else
00416         {
00417           ptr = pos + 2;
00418           state = in_comment;
00419         }
00420     }
00421 
00422   return (ptr);
00423 }
00424 
00425 //--------------------------------------------------
00426 static char* in_line_comment_action (char* ptr, state_def& state)
00427 //--------------------------------------------------
00428 {
00429   ptr += strlen (ptr);
00430 
00431   return (ptr);
00432 }
00433 
00434 //--------------------------------------------------
00435 static void build_deps_stream (istream& input,
00436                                const cmt_string& dir_name,
00437                                int current_path_index,
00438                                const CmtSystem::cmt_string_vector& include_paths,
00439                                const CmtSystem::cmt_string_vector& substitutions,
00440                                CmtSystem::cmt_string_vector& all_deps,
00441                                CmtSystem::cmt_string_vector& deps)
00442 //--------------------------------------------------
00443 {
00444   if (input)
00445     {
00446       if (Cmt::get_debug ())
00447         {
00448           cout << "CMT> build_deps_stream dir_name=" <<
00449               dir_name << endl;
00450         }
00451 
00452       while (!input.eof ())
00453         {
00454           char line[16384];
00455 
00456           input.getline (line, sizeof (line));
00457           char* ptr = &line[0];
00458           state_def state = at_start;
00459 
00460           if (Cmt::get_debug ())
00461             {
00462               cout << "CMT> build_deps_stream2 line=[" <<
00463                   line << "]" << endl;
00464             }
00465 
00466           while (strlen (ptr) > 0)
00467             {
00468               switch (state)
00469                 {
00470                   case at_start:
00471                     ptr = at_start_action (ptr,
00472                                            state,
00473                                            dir_name,
00474                                            current_path_index,
00475                                            include_paths,
00476                                            substitutions,
00477                                            all_deps,
00478                                            deps);
00479                     break;
00480                   case in_line:
00481                     ptr = in_line_action (ptr, state);
00482                     break;
00483                   case in_string:
00484                     ptr = in_string_action (ptr, state);
00485                     break;
00486                   case in_char:
00487                     ptr = in_char_action (ptr, state);
00488                     break;
00489                   case in_comment:
00490                     ptr = in_comment_action (ptr, state);
00491                     break;
00492                   case in_string_comment:
00493                     ptr = in_string_comment_action (ptr, state);
00494                     break;
00495                   case in_char_comment:
00496                     ptr = in_char_comment_action (ptr, state);
00497                     break;
00498                   case in_line_comment:
00499                     ptr = in_line_action (ptr, state);
00500                     break;
00501                 }
00502             }
00503         }
00504     }
00505 }
00506 
00507 //--------------------------------------------------
00508 static int build_deps (const cmt_string& name,
00509                        const cmt_string& dir_name,
00510                        int current_path_index,
00511                        const CmtSystem::cmt_string_vector& include_paths,
00512                        const CmtSystem::cmt_string_vector& substitutions,
00513                        CmtSystem::cmt_string_vector& all_deps,
00514                        CmtSystem::cmt_string_vector& deps)
00515 //--------------------------------------------------
00516 {
00517   int result = -1;
00518   cmt_string new_dir;
00519 
00520   if (Cmt::get_debug ())
00521     {
00522       cout << "CMT> build_deps name=" << name << " dir_name=" <<
00523           dir_name << endl;
00524     }
00525 
00526     //
00527     // Return 0 when the file is found in the current directory
00528     //
00529   if (CmtSystem::test_file (name))
00530     {
00531       ifstream input (name.c_str ());
00532       if (input)
00533         {
00534           CmtSystem::dirname (name, new_dir);
00535           build_deps_stream (input, new_dir, current_path_index,
00536                              include_paths, substitutions,
00537                              all_deps, deps);
00538           return (0);
00539         }
00540     }
00541 
00542   cmt_string full_name;
00543 
00544   full_name = dir_name;
00545   full_name += CmtSystem::file_separator ();
00546   full_name += name;
00547 
00548     //
00549     // Return 1 when the file is found in the directory of the
00550     // upper level source file
00551     //
00552   if (CmtSystem::test_file (full_name))
00553     {
00554       ifstream input (full_name.c_str ());
00555       if (input)
00556         {
00557           CmtSystem::dirname (full_name, new_dir);
00558           build_deps_stream (input, new_dir, current_path_index,
00559                              include_paths, substitutions,
00560                              all_deps, deps);
00561           return (1);
00562         }
00563     }
00564 
00565   int path_index = -1;
00566 
00567     //
00568     // Return [path_index + 2] when the include file is found at one of
00569     // the include_paths
00570     //
00571   for (path_index = 0; path_index < include_paths.size (); path_index++)
00572     {
00573       full_name  = include_paths[path_index];
00574       full_name += CmtSystem::file_separator ();
00575       full_name += name;
00576 
00577       if (Cmt::get_debug ())
00578         {
00579           cout << "CMT> build_deps2 full_name=" << full_name << endl;
00580         }
00581 
00582       if (CmtSystem::test_file (full_name))
00583         {
00584           ifstream in (full_name.c_str ());
00585           if (in)
00586             {
00587               CmtSystem::dirname (full_name, new_dir);
00588 
00589               if (Cmt::get_debug ())
00590                 {
00591                   cout << "CMT> build_deps3 new_dir=" << new_dir << endl;
00592                 }
00593 
00594               build_deps_stream (in,
00595                                  new_dir,
00596                                  path_index + 2,
00597                                  include_paths,
00598                                  substitutions,
00599                                  all_deps,
00600                                  deps);
00601 
00602               return (path_index + 2);
00603             }
00604         }
00605     }
00606 
00607   if (Cmt::get_debug ())
00608     {
00609       cout << "CMT> build_deps3" << endl;
00610     }
00611 
00612   return (-1);
00613 }
00614 
00615 //--------------------------------------------------------------------------
00616 void DepsBuilder::clear ()
00617 //--------------------------------------------------------------------------
00618 {
00619   m_include_paths.clear ();
00620   m_substitutions.clear ();
00621 }
00622 
00623 //--------------------------------------------------------------------------
00624 void DepsBuilder::add (const cmt_string& path, const cmt_string& substitution)
00625 //--------------------------------------------------------------------------
00626 {
00627   if (path[path.size () - 1] == CmtSystem::file_separator ())
00628     {
00629       cmt_string p = path;
00630       p.erase (path.size () - 1);
00631       m_include_paths.push_back (p);
00632     }
00633   else
00634     {
00635       m_include_paths.push_back (path);
00636     }
00637 
00638   m_substitutions.push_back (substitution);
00639 }
00640 
00641 //--------------------------------------------------------------------------
00642 void DepsBuilder::add_includes (const Use& use)
00643 //--------------------------------------------------------------------------
00644 {
00645   const Include::IncludeVector& includes = use.includes;
00646   int include_number;
00647 
00648   for (include_number = 0;
00649        include_number < includes.size ();
00650        include_number++)
00651     {
00652       const Include& include = includes[include_number];
00653 
00654       cmt_string temp = include.name;
00655       cmt_string pattern;
00656       cmt_string name;
00657       char end_pattern;
00658 
00659       int start = 0;
00660 
00661       for (;;)
00662         {
00663           int begin;
00664 
00665           begin = temp.find (start, "${");
00666           if (begin != cmt_string::npos)
00667             {
00668               end_pattern = '}';
00669             }
00670           else
00671             {
00672               begin = temp.find (start, "$(");
00673               if (begin != cmt_string::npos)
00674                 {
00675                   end_pattern = ')';
00676                 }
00677               else
00678                 {
00679                   break;
00680                 }
00681             }
00682 
00683           start = begin + 2;
00684 
00685           int end;
00686           end = temp.find (start, end_pattern);
00687           if (end == cmt_string::npos) break;
00688           if (end < begin) break;
00689           start = end + 1;
00690 
00691           temp.substr (begin, end - begin + 1, pattern);
00692           temp.substr (begin + 2, end - begin - 2, name);
00693 
00694           Symbol* macro = Symbol::find (name);
00695           if (macro != 0)
00696             {
00697               cmt_string value = macro->resolve_macro_value ();
00698               value += CmtSystem::file_separator ();
00699               temp.replace_all (pattern, value);
00700             }
00701           else
00702             {
00703               cmt_string value = CmtSystem::getenv (name);
00704               value += CmtSystem::file_separator ();
00705               temp.replace_all (pattern, value);
00706             }
00707         }
00708       add (temp, include.name);
00709     }
00710 }
00711 
00712 //--------------------------------------------------------------------------
00713 CmtSystem::cmt_string_vector& DepsBuilder::run (const cmt_string& file_name)
00714 //--------------------------------------------------------------------------
00715 {
00716   m_deps.clear ();
00717   m_all_deps.clear ();
00718 
00719   cmt_string preprocessor;
00720   Symbol* macro = Symbol::find ("preprocessor_command");
00721   if (macro != 0)
00722     {
00723       preprocessor = macro->resolve_macro_value ();
00724     }
00725 
00726   if (preprocessor == "")
00727     {
00728         //
00729         //   Since no preprocessor command is defined,
00730         // we use the internal mechanism provided here.
00731         //
00732       cmt_string new_dir;
00733 
00734       CmtSystem::dirname (file_name, new_dir);
00735 
00736       build_deps (file_name,
00737                   new_dir,
00738                   0,
00739                   m_include_paths,
00740                   m_substitutions,
00741                   m_all_deps,
00742                   m_deps);
00743     }
00744   else
00745     {
00746         //
00747         //  An external preprocessor command is defined. We expect it
00748         // to follow a "standard" syntax for its output, ie:
00749         //   o It starts with:
00750         //       <module>.o: ...
00751         //   o There may be many lines with trailing back-slashes
00752         //   o All entries are space-separated
00753         //   o One of the entries is the source file name itself
00754         //
00755         //  The preprocessor command expects the list of -I options
00756         // (resolved from the "includes" macro) and the list of 
00757         // -D/-U options (resolved from the "*_pp_*flags" macros)
00758         //
00759 
00760         //
00761         // Building the complete command (still the pp_*flags are
00762         // missing)
00763         //
00764       preprocessor += " ";
00765       macro = Symbol::find ("includes");
00766       preprocessor += macro->resolve_macro_value ();
00767       preprocessor += " ";
00768       preprocessor += file_name;
00769       
00770       cmt_string output;
00771       
00772       CmtSystem::execute (preprocessor, output);
00773 
00774         //
00775         // Make the output as one single big line.
00776         //
00777 
00778       output.replace_all ("\n", " ");
00779       output.replace_all ("\\ ", " ");
00780       
00781       CmtSystem::cmt_string_vector files;
00782       
00783       CmtSystem::split (output, " \t", files);
00784 
00785         //
00786         // Analyze each entry
00787         //
00788       
00789       for (int i = 1; i < files.size (); i++)
00790         {
00791           const cmt_string& file = files[i];
00792           if (file == file_name) continue;
00793           
00794           cmt_string dir;
00795           cmt_string name;
00796           cmt_string full_name;
00797           
00798           CmtSystem::dirname (file, dir);
00799 
00800             //
00801             // Only declared include_paths will be taken into account
00802             // Others are considered as system include paths.
00803             //
00804           
00805           for (int j = 0; j < m_include_paths.size (); j++)
00806             {
00807               const cmt_string& p = m_include_paths[j];
00808               if (dir == p)
00809                 {
00810                   CmtSystem::basename (file, name);
00811                   full_name = m_substitutions[j];
00812                   full_name += name;
00813 
00814                     //
00815                     // We add in the "m_deps" list the symbolic form
00816                     // of the path rather that the expanded one.
00817                     //
00818                   
00819                   m_deps.push_back (full_name);
00820                   
00821                   break;
00822                 }
00823             }
00824         }
00825     }
00826 
00827   return (m_deps);
00828 }
00829 

Generated at Thu Apr 11 16:49:40 2002 for CMT by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000