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