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