.
This commit is contained in:
parent
c7291ead23
commit
ff748bd3ff
2 changed files with 386 additions and 68 deletions
370
colla.c
370
colla.c
|
|
@ -473,7 +473,7 @@ usize strv_rfind(strview_t ctx, char c, usize from_right) {
|
|||
if (ctx.len == 0) return STR_NONE;
|
||||
if (from_right > ctx.len) from_right = ctx.len;
|
||||
isize end = (isize)(ctx.len - from_right);
|
||||
for (isize i = end; i >= 0; --i) {
|
||||
for (isize i = end - 1; i >= 0; --i) {
|
||||
if (ctx.buf[i] == c) {
|
||||
return (usize)i;
|
||||
}
|
||||
|
|
@ -508,6 +508,11 @@ bool char_is_num(char c) {
|
|||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
bool char_is_hex(char c) {
|
||||
c = char_lower(c);
|
||||
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
|
||||
}
|
||||
|
||||
char char_lower(char c) {
|
||||
return c >= 'A' && c <= 'Z' ? c + 32 : c;
|
||||
}
|
||||
|
|
@ -930,85 +935,318 @@ bool ibstr_get_i64(ibstream_t *ib, i64 *out) {
|
|||
|
||||
// == REGEX ========================================================
|
||||
|
||||
bool rg__match_impl(rg_match_t *ctx, instream_t *r, instream_t *t) {
|
||||
bool match_any = false;
|
||||
// adapted from rob pike regular expression matcher
|
||||
|
||||
usize beg = STR_END;
|
||||
usize end = STR_END;
|
||||
bool rg__match_here(instream_t r, instream_t t);
|
||||
|
||||
while (!istr_is_finished(r) && !istr_is_finished(t)) {
|
||||
char rc = istr_peek(r);
|
||||
char tc = istr_peek(t);
|
||||
|
||||
if (rc == '\\') {
|
||||
if (istr_peek_next(r) != '*' && istr_peek_next(r) != '\\') {
|
||||
warn("expected * or \\ after escape character");
|
||||
return false;
|
||||
}
|
||||
istr_skip(r, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (istr_peek_next(r) == '*' && rc == tc) {
|
||||
match_any = true;
|
||||
istr_skip(r, 2);
|
||||
istr_skip(t, 1);
|
||||
beg = istr_tell(t);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rc == '*') {
|
||||
match_any = true;
|
||||
istr_skip(r, 1);
|
||||
istr_skip(t, 1);
|
||||
beg = istr_tell(t);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rc == tc) {
|
||||
if (match_any && istr_peek_next(r) == istr_peek_next(t)) {
|
||||
end = istr_tell(t);
|
||||
ctx->text[ctx->count++] = strv(t->beg + beg, end - beg);
|
||||
beg = STR_END;
|
||||
match_any = false;
|
||||
}
|
||||
istr_skip(r, 1);
|
||||
istr_skip(t, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (match_any) {
|
||||
istr_skip(t, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (match_any && istr_is_finished(r)) {
|
||||
end = t->len;
|
||||
ctx->text[ctx->count++] = strv(t->beg + beg, end - beg);
|
||||
bool rg__match_star(char c, instream_t r, instream_t t) {
|
||||
do {
|
||||
if (rg__match_here(r, t)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ctx->count > 0 && istr_is_finished(r) && istr_is_finished(t);
|
||||
} while (!istr_is_finished(&t) && (istr_get(&t) == c || c == '.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
rg_match_t rg_match(strview_t rg, strview_t text) {
|
||||
rg_match_t out = {0};
|
||||
bool rg__match_here(instream_t r, instream_t t) {
|
||||
char rc = istr_peek(&r);
|
||||
char rcn = istr_peek_next(&r);
|
||||
if (rc == '\0') {
|
||||
return true;
|
||||
}
|
||||
if (rcn == '*') {
|
||||
istr_skip(&r, 2);
|
||||
return rg__match_star(rc, r, t);
|
||||
}
|
||||
if (rc == '$' && rcn == '\0') {
|
||||
return istr_peek(&t) == '\0';
|
||||
}
|
||||
if (!istr_is_finished(&t) && (rc == '.' || rc == istr_peek(&t))) {
|
||||
istr_skip(&r, 1);
|
||||
istr_skip(&t, 1);
|
||||
return rg__match_here(r, t);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool rg__matches_impl(instream_t r, instream_t t) {
|
||||
do {
|
||||
if (rg__match_here(r, t)) {
|
||||
return true;
|
||||
}
|
||||
} while (istr_get(&t) != '\0');
|
||||
return false;
|
||||
}
|
||||
|
||||
bool rg_matches(strview_t rg, strview_t text) {
|
||||
if (strv_contains(rg, '*')) {
|
||||
instream_t r = istr_init(rg);
|
||||
instream_t t = istr_init(text);
|
||||
out.matches = rg__match_impl(&out, &r, &t);
|
||||
return rg__matches_impl(r, t);
|
||||
}
|
||||
else {
|
||||
out.matches = strv_equals(rg, text);
|
||||
return strv_equals(rg, text);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool rg_match_easy(strview_t rg, strview_t text) {
|
||||
return rg_match(rg, text).matches;
|
||||
///////////////////////////////////////////////////
|
||||
// glob has the following special characters:
|
||||
// - * matches any string
|
||||
// - ? matches any character
|
||||
// - [ start a match group
|
||||
// - cannot be empty, so this matches either
|
||||
// ] or [:
|
||||
// [][]
|
||||
// []]
|
||||
// - if theres a - between two characters, it
|
||||
// matches a range:
|
||||
// [A-Za-z0-9] is equal to
|
||||
// [ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789]
|
||||
// - if there's a !, it negates the match,
|
||||
// so [!abc] matches anything but a, b, or c
|
||||
// - if there's a + after the last square bracket,
|
||||
// it matches 1+ times
|
||||
|
||||
// g: abc*_d?f[0-9]+c
|
||||
// t: abcdef_def901c
|
||||
// ----------------
|
||||
// g[0] == t[0] -> ++g, ++t
|
||||
// g: bc*_d?f[0-9]+c
|
||||
// t: bcdef_def901c
|
||||
// ----------------
|
||||
// g[0] == t[0] -> ++g, ++t
|
||||
// g: c*_d?f[0-9]+c
|
||||
// t: cdef_def901c
|
||||
// ----------------
|
||||
// g[0] == t[0] -> ++g, ++t
|
||||
// g: *_d?f[0-9]+c
|
||||
// t: def_def901c
|
||||
// ----------------
|
||||
// g[0] == * -> ++g, star match
|
||||
// g: _d?f[0-9]+c
|
||||
// t: def_def901c
|
||||
// c = _
|
||||
// ----------------
|
||||
// g[0] != t[0]
|
||||
// star: ++t
|
||||
// g: _d?f[0-9]+c
|
||||
// t: ef_def901c
|
||||
// ----------------
|
||||
// g[0] != t[0]
|
||||
// star: ++t
|
||||
// g: _d?f[0-9]+c
|
||||
// t: f_def901c
|
||||
// ----------------
|
||||
// g[0] != t[0]
|
||||
// star: ++t
|
||||
// g: _d?f[0-9]+c
|
||||
// t: _def901c
|
||||
// ----------------
|
||||
// g[0] == t[0]
|
||||
// ++g, ++t
|
||||
// g: d?f[0-9]+c
|
||||
// t: def901c
|
||||
// return true from star
|
||||
// ----------------
|
||||
// g[0] == t[0] -> ++g, ++t
|
||||
// g: ?f[0-9]+c
|
||||
// t: ef901c
|
||||
// ----------------
|
||||
// g[0] == ? -> ++g, ++t
|
||||
// g: f[0-9]+c
|
||||
// t: f901c
|
||||
// ----------------
|
||||
// g[0] == t[0] -> ++g, ++t
|
||||
// g: [0-9]+c
|
||||
// t: 901c
|
||||
// ----------------
|
||||
// g[0] == [
|
||||
// begin square:
|
||||
// -- grab pattern
|
||||
// s = strv_empty
|
||||
// while (s == strv_empty)
|
||||
// s += g.getUntil(])
|
||||
// matches_multi = g.peek() == '+'
|
||||
// s: 0-9
|
||||
// -- parse pattern
|
||||
// type: match
|
||||
// multi: matches_multi
|
||||
// ranges[MAX_RANGES] = {
|
||||
// { from: 0, to: 9 }
|
||||
// }
|
||||
// ----------------
|
||||
// matched_once = false
|
||||
// do {
|
||||
// if (!s.inRange(t[0])) {
|
||||
// break;
|
||||
// }
|
||||
// matched_once true
|
||||
// ++t
|
||||
// } while (s.multi);
|
||||
// return matched_atleast_once
|
||||
// ----------------
|
||||
// t: 901c
|
||||
// t[0] == 9 -> in range = true
|
||||
// ++t
|
||||
// t: 01c
|
||||
// t[0] == 0 -> in rage
|
||||
// ++t
|
||||
// t: 1c
|
||||
// t[0] == 1 -> in rage
|
||||
// ++t
|
||||
// t: c
|
||||
// t[0] == 1 -> not in rage
|
||||
// return true
|
||||
// ----------------
|
||||
// g: c
|
||||
// t: c
|
||||
// ----------------
|
||||
// g[0] == t[0] -> ++g, ++t
|
||||
// g:
|
||||
// t:
|
||||
// ----------------
|
||||
// g is empty -> return true
|
||||
//
|
||||
|
||||
bool glob__match_here(instream_t *g, instream_t *t);
|
||||
|
||||
bool glob__match_star(instream_t *g, instream_t *t) {
|
||||
char c = istr_get(g);
|
||||
char n = istr_peek(g);
|
||||
do {
|
||||
if (istr_get(t) == c) {
|
||||
return true;
|
||||
}
|
||||
} while (!istr_is_finished(t));
|
||||
return false;
|
||||
}
|
||||
|
||||
#define GLOB_MAX_RANGES 128
|
||||
|
||||
typedef struct {
|
||||
char from;
|
||||
char to;
|
||||
} glob_range_t;
|
||||
|
||||
typedef struct {
|
||||
bool multi;
|
||||
bool exclude;
|
||||
glob_range_t ranges[GLOB_MAX_RANGES];
|
||||
int range_count;
|
||||
} glob_pat_t;
|
||||
|
||||
bool glob__pat_is_in_range(glob_pat_t *pat, char c) {
|
||||
for (int i = 0; i < pat->range_count; ++i) {
|
||||
if (c >= pat->ranges[i].from &&
|
||||
c <= pat->ranges[i].to
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool glob__match_pattern(instream_t *t, strview_t pat, bool multi) {
|
||||
glob_pat_t p = {
|
||||
.multi = multi,
|
||||
.exclude = pat.buf[0] == '!',
|
||||
};
|
||||
for (usize i = 0; i < pat.len; ++i) {
|
||||
char from = '\0', to = '\0';
|
||||
if (i > 0 && pat.buf[i] == '-' && (i + 1) < pat.len) {
|
||||
from = pat.buf[i - 1];
|
||||
to = pat.buf[i + 1];
|
||||
++i;
|
||||
}
|
||||
else if ((i + 1) >= pat.len || pat.buf[i+1] != '-') {
|
||||
from = to = pat.buf[i];
|
||||
}
|
||||
if (from && to) {
|
||||
p.ranges[p.range_count++] = (glob_range_t){ from, to };
|
||||
}
|
||||
}
|
||||
|
||||
bool matched_atleast_once = false;
|
||||
do {
|
||||
char c = istr_peek(t);
|
||||
bool is_in_range = glob__pat_is_in_range(&p, c);
|
||||
if ((!is_in_range && !p.exclude) || (is_in_range && p.exclude)) {
|
||||
break;
|
||||
}
|
||||
matched_atleast_once = true;
|
||||
istr_skip(t, 1);
|
||||
} while (p.multi);
|
||||
|
||||
return matched_atleast_once;
|
||||
}
|
||||
|
||||
bool glob__match_here(instream_t *g, instream_t *t) {
|
||||
char gc = istr_peek(g);
|
||||
if (gc == '*') {
|
||||
istr_skip(g, 1);
|
||||
if (istr_is_finished(g)) {
|
||||
// set t (text) to empty, as the rest of the patter is sure to match
|
||||
*t = istr_init(STRV_EMPTY);
|
||||
return true;
|
||||
}
|
||||
return glob__match_star(g, t);
|
||||
}
|
||||
if (gc == '[') {
|
||||
// skip [
|
||||
istr_skip(g, 1);
|
||||
strview_t pattern = istr_get_view(g, ']');
|
||||
if (pattern.len == 0) {
|
||||
istr_skip(g, 1);
|
||||
pattern = istr_get_view(g, ']');
|
||||
// add first ]
|
||||
pattern.buf--;
|
||||
pattern.len++;
|
||||
}
|
||||
// skip ]
|
||||
istr_skip(g, 1);
|
||||
bool multi = false;
|
||||
if (istr_peek(g) == '+') {
|
||||
istr_skip(g, 1);
|
||||
multi = true;
|
||||
}
|
||||
return glob__match_pattern(t, pattern, multi);
|
||||
}
|
||||
if (!istr_is_finished(t) && (gc == '?' || gc == istr_peek(t))) {
|
||||
istr_skip(g, 1);
|
||||
istr_skip(t, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool glob__impl(instream_t *g, instream_t *t) {
|
||||
while (!istr_is_finished(g) && !istr_is_finished(t)) {
|
||||
if (!glob__match_here(g, t)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return istr_get(g) == '\0' && istr_get(t) == '\0';
|
||||
}
|
||||
|
||||
bool glob_matches(strview_t glob, strview_t text) {
|
||||
u8 tmpbuf[2048] = {0};
|
||||
arena_t scratch = arena_make(ARENA_STATIC, sizeof(tmpbuf), tmpbuf);
|
||||
// HACK: convert to a regex match as that works better for now :(
|
||||
outstream_t rg = ostr_init(&scratch);
|
||||
for (usize i = 0; i < glob.len; ++i) {
|
||||
if (glob.buf[i] == '*') {
|
||||
ostr_putc(&rg, '.');
|
||||
}
|
||||
ostr_putc(&rg, glob.buf[i]);
|
||||
}
|
||||
|
||||
instream_t pattern = istr_init(ostr_as_view(&rg));
|
||||
instream_t t = istr_init(text);
|
||||
return rg__matches_impl(pattern, t);
|
||||
// instream_t g = istr_init(glob);
|
||||
// instream_t t = istr_init(text);
|
||||
// return glob__impl(&g, &t);
|
||||
}
|
||||
|
||||
// == ARENA ========================================================
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if COLLA_CMT_LIB
|
||||
#pragma comment(lib, "Advapi32")
|
||||
#endif
|
||||
|
||||
#ifndef PROCESSOR_ARCHITECTURE_ARM64
|
||||
#define PROCESSOR_ARCHITECTURE_ARM64 12
|
||||
#endif
|
||||
|
|
@ -352,6 +356,80 @@ oshandle_t os_win_conin(void) {
|
|||
return w32_data.hconin;
|
||||
}
|
||||
|
||||
oshandle_t os_win_regopen(arena_t scratch, strview_t name) {
|
||||
HKEY key = NULL;
|
||||
str16_t key_name = strv_to_str16(&scratch, name);
|
||||
LONG result = RegOpenKeyExW(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
key_name.buf,
|
||||
0,
|
||||
KEY_READ,
|
||||
&key
|
||||
);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
err("failed to open registry key %v", name);
|
||||
return os_handle_zero();
|
||||
}
|
||||
return (oshandle_t){ .data = (uptr)key };
|
||||
}
|
||||
|
||||
void os_win_regclose(oshandle_t key) {
|
||||
RegCloseKey((HKEY)key.data);
|
||||
}
|
||||
|
||||
str_t os_win_regread_str(arena_t *arena, oshandle_t key, strview_t value) {
|
||||
u8 buf[KB(5)] = {0};
|
||||
DWORD bufsize = sizeof(buf);
|
||||
|
||||
arena_t scratch = *arena;
|
||||
str16_t value_str = strv_to_str16(&scratch, value);
|
||||
|
||||
DWORD type = 0;
|
||||
|
||||
LONG result = RegQueryValueExW(
|
||||
(HKEY)key.data,
|
||||
value_str.buf,
|
||||
NULL,
|
||||
&type,
|
||||
buf,
|
||||
&bufsize
|
||||
);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
err("failed to read registry key %v", value);
|
||||
return STR_EMPTY;
|
||||
}
|
||||
|
||||
return str_from_str16(arena, str16_init((char16_t*)buf, 0));
|
||||
}
|
||||
|
||||
i64 os_win_regread_int(arena_t scratch, oshandle_t key, strview_t value) {
|
||||
DWORD regvalue = 0;
|
||||
DWORD type = 0;
|
||||
DWORD bufsize = sizeof(regvalue);
|
||||
str16_t value_str = strv_to_str16(&scratch, value);
|
||||
LONG result = RegQueryValueExW(
|
||||
(HKEY)key.data,
|
||||
value_str.buf,
|
||||
NULL,
|
||||
&type,
|
||||
(u8*)®value,
|
||||
&bufsize
|
||||
);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
err("failed to read registry key %v", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (i64)regvalue;
|
||||
}
|
||||
|
||||
str_t os_win_regkey_str(arena_t *arena, strview_t key, strview_t value) {
|
||||
oshandle_t hkey = os_win_regopen(*arena, key);
|
||||
str_t out = os_win_regread_str(arena, hkey, value);
|
||||
os_win_regclose(hkey);
|
||||
return out;
|
||||
}
|
||||
|
||||
// == FILE ======================================
|
||||
|
||||
#define OS_SMALL_SCRATCH() \
|
||||
|
|
@ -690,6 +768,7 @@ oshandle_t os_run_cmd_async(arena_t scratch, os_cmd_t *cmd, os_cmd_options_t *op
|
|||
HANDLE hstdout_write = NULL;
|
||||
HANDLE hstderr_write = NULL;
|
||||
HANDLE hstdin_read = NULL;
|
||||
bool quiet = options ? options->quiet : false;
|
||||
|
||||
SECURITY_ATTRIBUTES sa_attr = {
|
||||
.nLength = sizeof(SECURITY_ATTRIBUTES),
|
||||
|
|
@ -777,7 +856,7 @@ oshandle_t os_run_cmd_async(arena_t scratch, os_cmd_t *cmd, os_cmd_options_t *op
|
|||
options->env->data = NULL;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
if (!success && !quiet) {
|
||||
err("couldn't create process (%v): %v", cmd_str, os_get_error_string(os_get_last_error()));
|
||||
return os_handle_zero();
|
||||
}
|
||||
|
|
@ -1357,3 +1436,4 @@ void sk_destroy_event(oshandle_t handle) {
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue