@@ -54,57 +54,85 @@ static std::string format(const char *format, const tsl::ordered_map<std::string
54
54
return s;
55
55
}
56
56
57
- static std::vector<std::string> expand_cmake_path (const fs::path &name, const fs::path &toml_dir, bool is_root_project) {
58
- std::vector<std::string> temp;
59
-
60
- auto extract_suffix = [](const fs::path &base, const fs::path &full) {
61
- auto fullpath = full.string ();
62
- auto base_len = base.string ().length ();
63
- auto delet = fullpath.substr (base_len + 1 , fullpath.length () - base_len);
64
- return delet;
57
+ static std::vector<fs::path> expand_cmake_path (const fs::path &source_path, const fs::path &toml_dir, bool is_root_project) {
58
+ auto is_subdir = [](fs::path p, const fs::path &root) {
59
+ while (true ) {
60
+ if (p == root) {
61
+ return true ;
62
+ }
63
+ auto parent = p.parent_path ();
64
+ if (parent == p) {
65
+ break ;
66
+ }
67
+ p = parent;
68
+ }
69
+ return false ;
65
70
};
71
+ if (!is_subdir (fs::absolute (toml_dir / source_path), toml_dir)) {
72
+ throw std::runtime_error (" Path traversal is not allowed: " + source_path.string ());
73
+ }
66
74
67
- auto stem = name.filename ().stem ().string ();
68
- auto ext = name.extension ();
75
+ // Split the path at the first period (since fs::path::stem() and fs::path::extension() split at the last period)
76
+ std::string stem, extension;
77
+ auto filename = source_path.filename ().string ();
78
+ auto dot_position = filename.find (' .' );
79
+ if (dot_position != std::string::npos) {
80
+ stem = filename.substr (0 , dot_position);
81
+ extension = filename.substr (dot_position);
82
+ } else {
83
+ stem = filename;
84
+ }
69
85
70
- if (is_root_project && stem == " **" && name == name. filename ()) {
71
- throw std::runtime_error (" Recursive globbing not allowed in project root: " + name .string ());
86
+ if (is_root_project && stem == " **" && !source_path. has_parent_path ()) {
87
+ throw std::runtime_error (" Recursive globbing not allowed in project root: " + source_path .string ());
72
88
}
73
89
90
+ auto has_extension = [](const fs::path &file_path, const std::string &extension) {
91
+ auto path = file_path.string ();
92
+ return path.rfind (extension) == path.length () - extension.length ();
93
+ };
94
+
95
+ std::vector<fs::path> paths;
74
96
if (stem == " *" ) {
75
- for (const auto &f : fs::directory_iterator (toml_dir / name .parent_path (), fs::directory_options::follow_directory_symlink)) {
76
- if (!f.is_directory () && f.path (). extension () == ext ) {
77
- temp .push_back (extract_suffix (toml_dir, f ));
97
+ for (const auto &f : fs::directory_iterator (toml_dir / source_path .parent_path (), fs::directory_options::follow_directory_symlink)) {
98
+ if (!f.is_directory () && has_extension ( f.path (), extension) ) {
99
+ paths .push_back (fs::relative (f, toml_dir ));
78
100
}
79
101
}
80
102
} else if (stem == " **" ) {
81
- for (const auto &f : fs::recursive_directory_iterator (toml_dir / name.parent_path (), fs::directory_options::follow_directory_symlink)) {
82
- if (!f.is_directory () && f.path ().extension () == ext) {
83
- temp.push_back (extract_suffix (toml_dir, f.path ()));
103
+ for (const auto &f :
104
+ fs::recursive_directory_iterator (toml_dir / source_path.parent_path (), fs::directory_options::follow_directory_symlink)) {
105
+ if (!f.is_directory () && has_extension (f.path (), extension)) {
106
+ paths.push_back (fs::relative (f, toml_dir));
84
107
}
85
108
}
86
109
} else {
87
- temp .push_back (name. string () );
110
+ paths .push_back (source_path );
88
111
}
89
- // Normalize all paths to work with CMake (it needs a / on Windows as well)
90
- for (auto &path : temp) {
91
- std::replace (path.begin (), path.end (), ' \\ ' , ' /' );
92
- }
93
- // Sort paths alphabetically for consistent cross-OS generation
94
- std::sort (temp.begin (), temp.end ());
95
- return temp;
112
+
113
+ return paths;
96
114
}
97
115
98
116
static std::vector<std::string> expand_cmake_paths (const std::vector<std::string> &sources, const fs::path &toml_dir, bool is_root_project) {
99
- // TODO: add duplicate checking
100
- std::vector<std::string> result;
117
+ std::vector<std::string> paths;
101
118
for (const auto &src : sources) {
102
119
auto expanded = expand_cmake_path (src, toml_dir, is_root_project);
103
120
for (const auto &f : expanded) {
104
- result .push_back (f);
121
+ paths .push_back (f. string () );
105
122
}
106
123
}
107
- return result;
124
+
125
+ // Normalize all paths to work with CMake (it needs a / on Windows as well)
126
+ for (auto &path : paths) {
127
+ std::replace (path.begin (), path.end (), ' \\ ' , ' /' );
128
+ }
129
+
130
+ // Sort paths alphabetically for consistent cross-OS generation
131
+ std::sort (paths.begin (), paths.end ());
132
+
133
+ // TODO: remove duplicates
134
+
135
+ return paths;
108
136
}
109
137
110
138
static void create_file (const fs::path &path, const std::string &contents) {
@@ -674,7 +702,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
674
702
675
703
parser::Project project (parent_project, path, false );
676
704
677
- for (auto const &lang : project.project_languages ) {
705
+ for (const auto &lang : project.project_languages ) {
678
706
if (known_languages.find (lang) == known_languages.end ()) {
679
707
if (project.project_allow_unknown_languages ) {
680
708
printf (" [warning] Unknown language '%s' specified\n " , lang.c_str ());
0 commit comments