| 234 | #endif |
| 235 | |
| 236 | ModuleInfo FsFileAccess::getModuleInfo ( const string & req, const string & from ) const { |
| 237 | if (!failed()) { |
| 238 | return ModuleFileAccess::getModuleInfo(req, from); |
| 239 | } |
| 240 | #if !defined(DAS_NO_FILEIO) |
| 241 | // file-path mode: trigger on .das or .das_project suffix + ./, ../, %/ prefix |
| 242 | if ( endsWithExt(req, ".das") || endsWithExt(req, ".das_project") ) { |
| 243 | bool relCur = (req.size() >= 2 && req[0] == '.' && req[1] == '/'); |
| 244 | bool relPar = (req.size() >= 3 && req[0] == '.' && req[1] == '.' && req[2] == '/'); |
| 245 | bool dasRoot = (req.size() >= 2 && req[0] == '%' && req[1] == '/'); |
| 246 | if ( relCur || relPar || dasRoot ) { |
| 247 | namespace fs = std::filesystem; |
| 248 | fs::path base = dasRoot ? fs::path(getDasRoot().c_str()) : fs::path(from.c_str()).parent_path(); |
| 249 | fs::path rel = dasRoot ? fs::path(req.substr(2).c_str()) : fs::path(req.c_str()); |
| 250 | // refuse absolute paths in the right-hand side: fs::path::operator/ |
| 251 | // discards the LHS when RHS is absolute, which would let `%//etc/x.das` |
| 252 | // (or `%/C:/x.das` on Windows) escape getDasRoot() and the `from` dir. |
| 253 | if ( rel.is_absolute() || rel.has_root_name() || rel.has_root_directory() ) { |
| 254 | return ModuleInfo(); // empty info -> reported as missing prerequisite |
| 255 | } |
| 256 | // for %/ the result must stay under getDasRoot(). After lexically_normal |
| 257 | // any `..` segments left in rel pop above the root (e.g. `%/../etc/x.das`), |
| 258 | // so reject. `./` and `../` are by design and may escape `from`'s dir. |
| 259 | if ( dasRoot ) { |
| 260 | for ( const auto & seg : rel.lexically_normal() ) { |
| 261 | if ( seg == ".." ) return ModuleInfo(); |
| 262 | } |
| 263 | } |
| 264 | fs::path full = (base / rel).lexically_normal(); |
| 265 | ModuleInfo info; |
| 266 | info.fileName = full.generic_string().c_str(); |
| 267 | info.moduleName = full.stem().generic_string().c_str(); |
| 268 | info.importName = info.moduleName; |
| 269 | return info; |
| 270 | } |
| 271 | } |
| 272 | #endif |
| 273 | auto np = req.find_first_of("./"); |
| 274 | if ( np != string::npos ) { |
| 275 | string top = req.substr(0,np); |
| 276 | auto last_np = req.find_last_of("./"); |
| 277 | string path = last_np == np ? "" : req.substr(np + 1,last_np - np - 1); |
| 278 | string mod_name = req.substr(last_np+1); |
| 279 | ModuleInfo info; |
| 280 | if ( top==DASLIB_MODULE_NAME ) { |
| 281 | info.moduleName = mod_name; |
| 282 | info.fileName = getDasRoot() + "/" + DASLIB_MODULE_NAME + "/" + info.moduleName + ".das"; |
| 283 | return info; |
| 284 | } |
| 285 | #define NATIVE_MODULE(category, subdir_name, dir_name, das_name) \ |
| 286 | if ( top==#category && mod_name==#das_name && (path.empty() || path == #subdir_name) ) { \ |
| 287 | info.moduleName = mod_name; \ |
| 288 | info.fileName = getDasRoot() + "/modules/" + #dir_name + "/" + #subdir_name + "/" + #das_name + ".das"; \ |
| 289 | return info; \ |
| 290 | } |
| 291 | #include "modules/external_resolve.inc" |
| 292 | // Try dynamic modules. From modules/<name>/.das_module. |
| 293 | auto resolve_mod = daScriptEnvironment::getBound()->g_dyn_modules_resolve; |
nothing calls this directly
no test coverage detected