| 146 | } |
| 147 | |
| 148 | static bool init_modules_for_folder(FileAccessPtr fa, const das::string &path, das::TextWriter &tout, |
| 149 | const das_hash_set<das::string> *skip_set = nullptr) { |
| 150 | // FileAccess do not support iteratinf over directory. |
| 151 | #if DAS_NO_FILEIO |
| 152 | return false; |
| 153 | #else |
| 154 | using namespace das; |
| 155 | string modules_path = path + "/modules/"; |
| 156 | bool all_good = true; |
| 157 | #if defined(_MSC_VER) |
| 158 | _finddata_t c_file; |
| 159 | intptr_t hFile; |
| 160 | string findPath = modules_path + "/*"; |
| 161 | if ((hFile = _findfirst(findPath.c_str(), &c_file)) != -1L) { |
| 162 | do { |
| 163 | if (strcmp(c_file.name, ".") == 0 || strcmp(c_file.name, "..") == 0) { |
| 164 | continue; |
| 165 | } |
| 166 | if (skip_set && skip_set->count(normalize_module_name(das::string(c_file.name)))) { |
| 167 | // stderr, not `tout`: this is a diagnostic, and `tout` is stdout — which for the MCP server / |
| 168 | // dastest JSON / any stdout-parsing pipeline is a structured data channel a stray line corrupts. |
| 169 | fprintf(stderr, "Warning: local '%s' shadows global — using local\n", c_file.name); |
| 170 | continue; |
| 171 | } |
| 172 | all_good &= Result::OK == init_dyn_modules(fa, modules_path + c_file.name, tout, false); |
| 173 | } while (_findnext(hFile, &c_file) == 0); |
| 174 | } |
| 175 | _findclose(hFile); |
| 176 | #else |
| 177 | DIR *dir; |
| 178 | struct dirent *ent; |
| 179 | if ((dir = opendir (modules_path.c_str())) != NULL) { |
| 180 | while ((ent = readdir (dir)) != NULL) { |
| 181 | if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { |
| 182 | continue; |
| 183 | } |
| 184 | if (skip_set && skip_set->count(normalize_module_name(das::string(ent->d_name)))) { |
| 185 | // stderr, not `tout`: this is a diagnostic, and `tout` is stdout — which for the MCP server / |
| 186 | // dastest JSON / any stdout-parsing pipeline is a structured data channel a stray line corrupts. |
| 187 | fprintf(stderr, "Warning: local '%s' shadows global — using local\n", ent->d_name); |
| 188 | continue; |
| 189 | } |
| 190 | all_good &= Result::OK == init_dyn_modules(fa, modules_path + ent->d_name, tout, false); |
| 191 | } |
| 192 | closedir (dir); |
| 193 | } |
| 194 | #endif |
| 195 | return all_good; |
| 196 | #endif // DAS_NO_FILEIO |
| 197 | } |
| 198 | |
| 199 | static das::string path_basename(const das::string &path) { |
| 200 | // Trim trailing separators so "/mods/foo/" yields "foo" (otherwise |
no test coverage detected