source: CMT/v1r14p20031120/src/cmt_deps_builder.cxx @ 1

Last change on this file since 1 was 1, checked in by arnault, 19 years ago

Import all tags

File size: 21.0 KB
Line 
1
2#include "cmt_deps_builder.h"
3#include "cmt_system.h"
4#include "cmt_use.h"
5#include "cmt_include.h"
6#include "cmt_symbol.h"
7
8//
9//  While parsing a C++ file, these are the possible usefull
10// states we can reach.
11//  Each state correspond to a specific state action function.
12//
13enum state_def
14{
15  at_start,                                // beginning of the file
16  in_line,                                // along a line
17  in_string,                        // inside a quoted string
18  in_char,                                // inside a quoted char
19  in_comment,                        // inside a multi-line comment
20  in_string_comment,        // inside a quoted string in a comment
21  in_char_comment,                // inside a quoted char in a comment
22  in_line_comment                // inside a single-line comment
23};
24
25//--------------------------------------------------
26static int build_deps (const cmt_string& name,
27                       const cmt_string& dir_name,
28                       int current_path_index,
29                       const CmtSystem::cmt_string_vector& include_paths,
30                       const CmtSystem::cmt_string_vector& substitutions,
31                       CmtSystem::cmt_string_vector& all_deps,
32                       CmtSystem::cmt_string_vector& deps);
33
34
35//--------------------------------------------------
36static void header_file_action (const char* header_file,
37                                const cmt_string& dir_name,
38                                int current_path_index,
39                                const CmtSystem::cmt_string_vector& include_paths,
40                                const CmtSystem::cmt_string_vector& substitutions,
41                                CmtSystem::cmt_string_vector& all_deps,
42                                CmtSystem::cmt_string_vector& deps)
43{
44  bool found = false;
45
46  for (int i = 0; i < all_deps.size (); i++)
47    {
48      if (all_deps[i] == header_file)
49        {
50          found = true;
51          break;
52        }
53    }
54 
55  if (!found)
56    {
57      all_deps.push_back (header_file);
58     
59      int path_index = build_deps (header_file,
60                                   dir_name,
61                                   current_path_index,
62                                   include_paths,
63                                   substitutions,
64                                   all_deps,
65                                   deps);
66     
67      if (path_index >= 0)
68        {
69          cmt_string full_name;
70         
71          if (path_index == 1)
72            {
73              full_name = dir_name;
74              full_name += CmtSystem::file_separator ();
75             
76              if (current_path_index >= 2)
77                {
78                  full_name.replace (include_paths[current_path_index - 2],
79                                     substitutions[current_path_index - 2]);
80                }
81            }
82          else if (path_index > 1)
83            {
84              full_name  = substitutions[path_index - 2];
85              full_name += CmtSystem::file_separator ();
86            }
87         
88          full_name += header_file;
89         
90          deps.push_back (full_name);
91        }
92    }
93}
94
95
96//--------------------------------------------------
97static char* at_start_action (char* ptr,
98                              state_def& state,
99                              const cmt_string& dir_name,
100                              int current_path_index,
101                              const CmtSystem::cmt_string_vector& include_paths,
102                              const CmtSystem::cmt_string_vector& substitutions,
103                              CmtSystem::cmt_string_vector& all_deps,
104                              CmtSystem::cmt_string_vector& deps)
105{
106  char term = 0;
107
108  if (*ptr == '#')
109    {
110      ptr++;
111      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
112      if (!strncmp (ptr, "include", 7))
113        {
114          ptr += 7;
115
116          while (*ptr == ' ') ptr++;
117          if (*ptr == '<')
118            {
119              term = '>';
120              ptr++;
121            }
122          else if (*ptr == '"')
123            {
124              term = '"';
125              ptr++;
126            }
127          else
128            {
129              state = in_line;
130              ptr += strlen (ptr);
131              return (ptr);
132            }
133        }
134      else
135        {
136          state = in_line;
137          ptr += strlen (ptr);
138          return (ptr);
139        }
140    }
141  else if (!strncmp (ptr, "      include", 13))
142    {
143      ptr += 13;
144
145      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
146      if (*ptr == '\'')
147        {
148          term = '\'';
149          ptr++;
150        }
151      else
152        {
153          state = in_line;
154          return (ptr);
155        }
156    }
157  else if (!strncmp (ptr, "\tinclude", 8))
158    {
159      ptr += 8;
160
161      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
162      if (*ptr == '\'')
163        {
164          term = '\'';
165          ptr++;
166        }
167      else
168        {
169          state = in_line;
170          return (ptr);
171        }
172    }
173  else
174    {
175      state = in_line;
176      return (ptr);
177    }
178
179  char* end;
180
181  end = strchr (ptr, term);
182  if (end != 0)
183    {
184      *end = 0;
185    }
186 
187  const char* header_file = ptr;
188 
189  header_file_action (header_file,
190                      dir_name,
191                      current_path_index,
192                      include_paths,
193                      substitutions,
194                      all_deps,
195                      deps);
196 
197  if (end != 0)
198    {
199      *end = term;
200    }
201
202  state = in_line;
203  ptr += strlen (ptr);
204 
205  return (ptr);
206}
207
208//--------------------------------------------------
209static char* in_line_action (char* ptr, state_def& state)
210{
211  char* pattern = &ptr[strlen (ptr)];
212
213  char* pos = strchr (ptr, '"');
214  if (pos != 0)
215    {
216      if (pos < pattern)
217        {
218          state = in_string;
219          pattern = pos;
220        }
221    }
222
223  pos = strchr (ptr, '\'');
224  if (pos != 0)
225    {
226      if (pos < pattern)
227        {
228          state = in_char;
229          pattern = pos;
230        }
231    }
232
233  pos = strstr (ptr, "/*");   //*/
234  if (pos != 0)
235    {
236      if (pos < pattern)
237        {
238          state = in_comment;
239          pattern = pos + 1;
240        }
241    }
242
243  pos = strstr (ptr, "//");
244  if (pos != 0)
245    {
246      if (pos < pattern)
247        {
248          state = in_line_comment;
249          pattern = pos + 1;
250        }
251    }
252
253  if (state != in_line)
254    {
255      ptr = pattern + 1;
256    }
257  else
258    {
259      ptr += strlen (ptr);
260    }
261
262  return (ptr);
263}
264
265//--------------------------------------------------
266static char* in_string_action (char* ptr, state_def& state)
267{
268  char* pos = strchr (ptr, '"');
269  if (pos == 0)
270    {
271        // This string is not finished till the end of the line..
272        // we expect it continues to the nex line...
273      ptr += strlen (ptr);
274    }
275  else
276    {
277      pos--;
278      if (*pos == '\\')
279        {
280          ptr = pos + 2;
281        }
282      else
283        {
284          ptr = pos + 2;
285          state = in_line;
286        }
287    }
288
289  return (ptr);
290}
291
292//--------------------------------------------------
293static char* in_char_action (char* ptr, state_def& state)
294{
295  char* pos = strchr (ptr, '\'');
296  if (pos == 0)
297    {
298        // This string is not finished till the end of the line..
299        // we expect it continues to the nex line...
300      ptr += strlen (ptr);
301    }
302  else
303    {
304      pos--;
305      if (*pos == '\\')
306        {
307          ptr = pos + 2;
308        }
309      else
310        {
311          ptr = pos + 2;
312          state = in_line;
313        }
314    }
315
316  return (ptr);
317}
318
319//--------------------------------------------------
320static char* in_comment_action (char* ptr, state_def& state)
321{
322  char* pattern = &ptr[strlen (ptr)];
323  char* pos = strchr (ptr, '"');
324  if (pos != 0)
325    {
326      if (pos < pattern)
327        {
328          state = in_string_comment;
329          pattern = pos;
330        }
331    }
332  pos = strchr (ptr, '\'');
333  if (pos != 0)
334    {
335      if (pos < pattern)
336        {
337          state = in_char_comment;
338          pattern = pos;
339        }
340    }
341  pos = strstr (ptr, "*/");
342  if (pos != 0)
343    {
344      if (pos < pattern)
345        {
346          state = in_line;
347          pattern = pos + 1;
348        }
349    }
350
351  if (state == in_comment)
352    {
353      ptr += strlen (ptr);
354    }
355  else
356    {
357      ptr = pattern + 1;
358    }
359
360  return (ptr);
361}
362
363//--------------------------------------------------
364static char* in_string_comment_action (char* ptr, state_def& state)
365{
366  char* pos = strchr (ptr, '"');
367  if (pos == 0)
368    {
369        // This string is not finished till the end of the line..
370        // we expect it continues to the nex line...
371      ptr += strlen (ptr);
372    }
373  else
374    {
375      pos--;
376      if (*pos == '\\')
377        {
378          ptr = pos + 2;
379        }
380      else
381        {
382          ptr = pos + 2;
383          state = in_comment;
384        }
385    }
386
387  return (ptr);
388}
389
390//--------------------------------------------------
391static char* in_char_comment_action (char* ptr, state_def& state)
392{
393  char* pos = strchr (ptr, '\'');
394  if (pos == 0)
395    {
396        // This string is not finished till the end of the line..
397        // we expect it continues to the nex line...
398      ptr += strlen (ptr);
399    }
400  else
401    {
402      pos--;
403      if (*pos == '\\')
404        {
405          ptr = pos + 2;
406        }
407      else
408        {
409          ptr = pos + 2;
410          state = in_comment;
411        }
412    }
413
414  return (ptr);
415}
416
417//--------------------------------------------------
418static char* in_line_comment_action (char* ptr, state_def& state)
419{
420  ptr += strlen (ptr);
421
422  return (ptr);
423}
424
425//--------------------------------------------------
426static void build_deps_stream (istream& input,
427                               const cmt_string& dir_name,
428                               int current_path_index,
429                               const CmtSystem::cmt_string_vector& include_paths,
430                               const CmtSystem::cmt_string_vector& substitutions,
431                               CmtSystem::cmt_string_vector& all_deps,
432                               CmtSystem::cmt_string_vector& deps)
433{
434  if (input)
435    {
436      if (Cmt::get_debug ())
437        {
438          cout << "CMT> build_deps_stream dir_name=" <<
439              dir_name << endl;
440        }
441
442      while (!input.eof ())
443        {
444          char line[16384];
445
446          input.getline (line, sizeof (line));
447          char* ptr = &line[0];
448          state_def state = at_start;
449
450          if (Cmt::get_debug ())
451            {
452              cout << "CMT> build_deps_stream2 line=[" <<
453                  line << "]" << endl;
454            }
455
456          while (strlen (ptr) > 0)
457            {
458              switch (state)
459                {
460                  case at_start:
461                    ptr = at_start_action (ptr,
462                                           state,
463                                           dir_name,
464                                           current_path_index,
465                                           include_paths,
466                                           substitutions,
467                                           all_deps,
468                                           deps);
469                    break;
470                  case in_line:
471                    ptr = in_line_action (ptr, state);
472                    break;
473                  case in_string:
474                    ptr = in_string_action (ptr, state);
475                    break;
476                  case in_char:
477                    ptr = in_char_action (ptr, state);
478                    break;
479                  case in_comment:
480                    ptr = in_comment_action (ptr, state);
481                    break;
482                  case in_string_comment:
483                    ptr = in_string_comment_action (ptr, state);
484                    break;
485                  case in_char_comment:
486                    ptr = in_char_comment_action (ptr, state);
487                    break;
488                  case in_line_comment:
489                    ptr = in_line_action (ptr, state);
490                    break;
491                }
492            }
493        }
494    }
495}
496
497//--------------------------------------------------
498static int build_deps (const cmt_string& name,
499                       const cmt_string& dir_name,
500                       int current_path_index,
501                       const CmtSystem::cmt_string_vector& include_paths,
502                       const CmtSystem::cmt_string_vector& substitutions,
503                       CmtSystem::cmt_string_vector& all_deps,
504                       CmtSystem::cmt_string_vector& deps)
505{
506  int result = -1;
507  cmt_string new_dir;
508
509  if (Cmt::get_debug ())
510    {
511      cout << "CMT> build_deps name=" << name << " dir_name=" <<
512          dir_name << endl;
513    }
514
515    //
516    // Return 0 when the file is found in the current directory
517    //
518  if (CmtSystem::test_file (name))
519    {
520      ifstream input (name.c_str ());
521      if (input)
522        {
523          CmtSystem::dirname (name, new_dir);
524          build_deps_stream (input, new_dir, current_path_index,
525                             include_paths, substitutions,
526                             all_deps, deps);
527          return (0);
528        }
529    }
530
531  cmt_string full_name;
532
533  full_name = dir_name;
534  full_name += CmtSystem::file_separator ();
535  full_name += name;
536
537    //
538    // Return 1 when the file is found in the directory of the
539    // upper level source file
540    //
541  if (CmtSystem::test_file (full_name))
542    {
543      ifstream input (full_name.c_str ());
544      if (input)
545        {
546          CmtSystem::dirname (full_name, new_dir);
547          build_deps_stream (input, new_dir, current_path_index,
548                             include_paths, substitutions,
549                             all_deps, deps);
550          return (1);
551        }
552    }
553
554  int path_index = -1;
555
556    //
557    // Return [path_index + 2] when the include file is found at one of
558    // the include_paths
559    //
560  for (path_index = 0; path_index < include_paths.size (); path_index++)
561    {
562      full_name  = include_paths[path_index];
563      full_name += CmtSystem::file_separator ();
564      full_name += name;
565
566      if (Cmt::get_debug ())
567        {
568          cout << "CMT> build_deps2 full_name=" << full_name << endl;
569        }
570
571      if (CmtSystem::test_file (full_name))
572        {
573          ifstream in (full_name.c_str ());
574          if (in)
575            {
576              CmtSystem::dirname (full_name, new_dir);
577
578              if (Cmt::get_debug ())
579                {
580                  cout << "CMT> build_deps3 new_dir=" << new_dir << endl;
581                }
582
583              build_deps_stream (in,
584                                 new_dir,
585                                 path_index + 2,
586                                 include_paths,
587                                 substitutions,
588                                 all_deps,
589                                 deps);
590
591              return (path_index + 2);
592            }
593        }
594    }
595
596  if (Cmt::get_debug ())
597    {
598      cout << "CMT> build_deps3" << endl;
599    }
600
601  return (-1);
602}
603
604//--------------------------------------------------------------------------
605void DepsBuilder::clear ()
606{
607  m_include_paths.clear ();
608  m_substitutions.clear ();
609}
610
611//--------------------------------------------------------------------------
612void DepsBuilder::add (const cmt_string& path, const cmt_string& substitution)
613{
614  if (path[path.size () - 1] == CmtSystem::file_separator ())
615    {
616      cmt_string p = path;
617      p.erase (path.size () - 1);
618      m_include_paths.push_back (p);
619    }
620  else
621    {
622      m_include_paths.push_back (path);
623    }
624
625  m_substitutions.push_back (substitution);
626}
627
628//--------------------------------------------------------------------------
629void DepsBuilder::add_includes (const Use& use)
630{
631  const Include::IncludeVector& includes = use.includes;
632  int include_number;
633
634  for (include_number = 0;
635       include_number < includes.size ();
636       include_number++)
637    {
638      const Include& include = includes[include_number];
639
640      cmt_string temp = include.name;
641      cmt_string pattern;
642      cmt_string name;
643      char end_pattern;
644
645      int start = 0;
646
647      for (;;)
648        {
649          int begin;
650
651          begin = temp.find (start, "${");
652          if (begin != cmt_string::npos)
653            {
654              end_pattern = '}';
655            }
656          else
657            {
658              begin = temp.find (start, "$(");
659              if (begin != cmt_string::npos)
660                {
661                  end_pattern = ')';
662                }
663              else
664                {
665                  break;
666                }
667            }
668
669          start = begin + 2;
670
671          int end;
672          end = temp.find (start, end_pattern);
673          if (end == cmt_string::npos) break;
674          if (end < begin) break;
675          start = end + 1;
676
677          temp.substr (begin, end - begin + 1, pattern);
678          temp.substr (begin + 2, end - begin - 2, name);
679
680          Symbol* macro = Symbol::find (name);
681          if (macro != 0)
682            {
683              cmt_string value = macro->resolve_macro_value ();
684              value += CmtSystem::file_separator ();
685              temp.replace_all (pattern, value);
686            }
687          else
688            {
689              cmt_string value = CmtSystem::getenv (name);
690              value += CmtSystem::file_separator ();
691              temp.replace_all (pattern, value);
692            }
693        }
694      add (temp, include.name);
695    }
696}
697
698//--------------------------------------------------------------------------
699CmtSystem::cmt_string_vector& DepsBuilder::run (const cmt_string& file_name)
700{
701  m_deps.clear ();
702  m_all_deps.clear ();
703
704  cmt_string preprocessor;
705  Symbol* macro = Symbol::find ("preprocessor_command");
706  if (macro != 0)
707    {
708      preprocessor = macro->resolve_macro_value ();
709    }
710
711  if (preprocessor == "")
712    {
713        //
714        //   Since no preprocessor command is defined,
715        // we use the internal mechanism provided here.
716        //
717      cmt_string new_dir;
718
719      CmtSystem::dirname (file_name, new_dir);
720
721      build_deps (file_name,
722                  new_dir,
723                  0,
724                  m_include_paths,
725                  m_substitutions,
726                  m_all_deps,
727                  m_deps);
728    }
729  else
730    {
731        //
732        //  An external preprocessor command is defined. We expect it
733        // to follow a "standard" syntax for its output, ie:
734        //   o It starts with:
735        //       <module>.o: ...
736        //   o There may be many lines with trailing back-slashes
737        //   o All entries are space-separated
738        //   o One of the entries is the source file name itself
739        //
740        //  The preprocessor command expects the list of -I options
741        // (resolved from the "includes" macro) and the list of
742        // -D/-U options (resolved from the "*_pp_*flags" macros)
743        //
744
745        //
746        // Building the complete command (still the pp_*flags are
747        // missing)
748        //
749      preprocessor += " ";
750      macro = Symbol::find ("includes");
751      preprocessor += macro->resolve_macro_value ();
752      preprocessor += " ";
753      preprocessor += file_name;
754     
755      cmt_string output;
756     
757      CmtSystem::execute (preprocessor, output);
758
759        //
760        // Make the output as one single big line.
761        //
762
763      output.replace_all ("\n", " ");
764      output.replace_all ("\\ ", " ");
765     
766      CmtSystem::cmt_string_vector files;
767     
768      CmtSystem::split (output, " \t", files);
769
770        //
771        // Analyze each entry
772        //
773     
774      for (int i = 1; i < files.size (); i++)
775        {
776          const cmt_string& file = files[i];
777          if (file == file_name) continue;
778         
779          cmt_string dir;
780          cmt_string name;
781          cmt_string full_name;
782         
783          CmtSystem::dirname (file, dir);
784
785            //
786            // Only declared include_paths will be taken into account
787            // Others are considered as system include paths.
788            //
789         
790          for (int j = 0; j < m_include_paths.size (); j++)
791            {
792              const cmt_string& p = m_include_paths[j];
793              if (dir == p)
794                {
795                  CmtSystem::basename (file, name);
796                  full_name = m_substitutions[j];
797                  full_name += name;
798
799                    //
800                    // We add in the "m_deps" list the symbolic form
801                    // of the path rather that the expanded one.
802                    //
803                 
804                  m_deps.push_back (full_name);
805                 
806                  break;
807                }
808            }
809        }
810    }
811
812  return (m_deps);
813}
814
Note: See TracBrowser for help on using the repository browser.