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