| 134 | }; |
| 135 | |
| 136 | static std::vector<ModelEntry> discover_models(const std::string & dir, |
| 137 | const std::string & filter) { |
| 138 | std::vector<ModelEntry> entries; |
| 139 | |
| 140 | #ifdef _WIN32 |
| 141 | std::string pattern = dir + "\\*.ggml"; |
| 142 | WIN32_FIND_DATAA fd; |
| 143 | HANDLE hFind = FindFirstFileA(pattern.c_str(), &fd); |
| 144 | if (hFind == INVALID_HANDLE_VALUE) { |
| 145 | fprintf(stderr, "ERROR: cannot open models directory '%s'\n", dir.c_str()); |
| 146 | return entries; |
| 147 | } |
| 148 | do { |
| 149 | if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; |
| 150 | std::string fname = fd.cFileName; |
| 151 | if (!ends_with(fname, ".ggml")) continue; |
| 152 | if (!filter.empty() && fname.find(filter) == std::string::npos) continue; |
| 153 | |
| 154 | std::string full_path = dir + "\\" + fname; |
| 155 | struct _stat st; |
| 156 | if (_stat(full_path.c_str(), &st) != 0) continue; |
| 157 | |
| 158 | ModelEntry e; |
| 159 | e.path = full_path; |
| 160 | e.name = strip_extension(fname); |
| 161 | e.file_size = st.st_size; |
| 162 | entries.push_back(e); |
| 163 | } while (FindNextFileA(hFind, &fd)); |
| 164 | FindClose(hFind); |
| 165 | #else |
| 166 | DIR * d = opendir(dir.c_str()); |
| 167 | if (!d) { |
| 168 | fprintf(stderr, "ERROR: cannot open models directory '%s'\n", dir.c_str()); |
| 169 | return entries; |
| 170 | } |
| 171 | struct dirent * ent; |
| 172 | while ((ent = readdir(d)) != nullptr) { |
| 173 | std::string fname = ent->d_name; |
| 174 | if (!ends_with(fname, ".ggml")) continue; |
| 175 | if (!filter.empty() && fname.find(filter) == std::string::npos) continue; |
| 176 | |
| 177 | std::string full_path = dir + "/" + fname; |
| 178 | struct stat st; |
| 179 | if (stat(full_path.c_str(), &st) != 0) continue; |
| 180 | |
| 181 | ModelEntry e; |
| 182 | e.path = full_path; |
| 183 | e.name = strip_extension(fname); |
| 184 | e.file_size = st.st_size; |
| 185 | entries.push_back(e); |
| 186 | } |
| 187 | closedir(d); |
| 188 | #endif |
| 189 | |
| 190 | std::sort(entries.begin(), entries.end(), [](const ModelEntry & a, const ModelEntry & b) { |
| 191 | return model_sort_key(a.name) < model_sort_key(b.name); |
| 192 | }); |
| 193 | return entries; |
no test coverage detected