forked from Paril/quake2c
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathg_file.cpp
103 lines (91 loc) · 2.4 KB
/
g_file.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
extern "C"
{
#define QCVM_INTERNAL
#include "shared/shared.h"
#include "vm.h"
#include "g_file.h"
#include "vm_string.h"
}
#include <filesystem>
#include <vector>
#include <regex>
namespace fs = std::filesystem;
const char *qcvm_cpp_absolute_path(const qcvm_t *vm, const char *relative)
{
return qcvm_temp_format(vm, "%s", fs::absolute(relative).string().c_str());
}
char **qcvm_get_file_list(const qcvm_t *vm, const char *path, const char *ext, int32_t *num)
{
std::vector<std::string> paths;
// filtered search
if (strchr(path, '*') || strchr(path, '?') || strchr(path, '[') || strchr(path, ']'))
{
// convert to regex;
// keep \ escapes intact
// convert * to [^/\\]*
// convert ? to .
// convert [! to [^
// escape . outside of character classes with \.
std::string raw_regex(path);
bool inside_class = false;
for (size_t i = 0; i < raw_regex.size(); i++)
{
switch (raw_regex[i])
{
case '.':
if (!inside_class)
{
raw_regex.insert(i, "\\");
i++;
}
continue;
case '\\':
i++;
continue;
case '*':
raw_regex.insert(i, "[^/\\\\]");
i += 6;
continue;
case '[':
inside_class = true;
if (raw_regex[i + 1] == '!')
raw_regex[i + 1] = '^';
continue;
case ']':
inside_class = false;
continue;
}
}
std::regex reg(raw_regex);
fs::path base_path = qcvm_temp_format(vm, "%s", vm->path);
for (auto &p : fs::recursive_directory_iterator(base_path))
if (p.is_regular_file())
{
std::string str = p.path().string().substr(strlen(vm->path));
std::replace(str.begin(), str.end(), '\\', '/');
bool matched = std::regex_match(str, reg);
if (matched)
paths.push_back(str);
}
}
// basic search
else
{
fs::path base_path = qcvm_temp_format(vm, "%s%s", vm->path, path);
for (auto &p : fs::directory_iterator(base_path))
if (p.is_regular_file() && p.path().has_extension() && p.path().extension().string().substr(1).compare(ext) == 0)
{
std::string str = p.path().string().substr(strlen(vm->path));
std::replace(str.begin(), str.end(), '\\', '/');
paths.push_back(str);
}
}
char **results = (char **)qcvm_alloc(vm, sizeof(char *) * paths.size());
for (size_t i = 0; i < paths.size(); i++)
{
results[i] = (char *)qcvm_alloc(vm, sizeof(char) * paths[i].size() + 1);
memcpy(results[i], paths[i].data(), paths[i].size());
}
*num = (int32_t)paths.size();
return results;
}