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
00010
00011
00012
00013 enum state_def
00014 {
00015 at_start,
00016 in_line,
00017 in_string,
00018 in_char,
00019 in_comment,
00020 in_string_comment,
00021 in_char_comment,
00022 in_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
00276
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
00304
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
00377
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
00405
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
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
00550
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
00569
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
00730
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
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
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
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
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
00802
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
00816
00817
00818
00819 m_deps.push_back (full_name);
00820
00821 break;
00822 }
00823 }
00824 }
00825 }
00826
00827 return (m_deps);
00828 }
00829