Initial CST-Agent: portable Linux/Termux/Windows coding agent.
Vendored sashidown, OpenAI-compatible env (OPENAI_*), and bootstrap scripts. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Vendored
+184
@@ -0,0 +1,184 @@
|
||||
#include "line_index.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LINE_IX_DYNAMIC_INIT 256
|
||||
|
||||
static size_t scan_line_end(const char *input, size_t len, size_t pos)
|
||||
{
|
||||
const char *hit = memchr(input + pos, '\n', len - pos);
|
||||
return hit ? (size_t)(hit - input) : len;
|
||||
}
|
||||
|
||||
static size_t scan_skip_line(const char *input, size_t len, size_t pos)
|
||||
{
|
||||
pos = scan_line_end(input, len, pos);
|
||||
if (pos < len)
|
||||
pos++;
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int line_index_ensure(line_index_t *ix, uint32_t need_slots)
|
||||
{
|
||||
if (need_slots <= ix->cap)
|
||||
return 0;
|
||||
if (!ix->owned) {
|
||||
ix->valid = 0;
|
||||
return -1;
|
||||
}
|
||||
uint32_t cap = ix->cap ? ix->cap : LINE_IX_DYNAMIC_INIT;
|
||||
while (cap < need_slots)
|
||||
cap *= 2;
|
||||
uint32_t *p = (uint32_t *)realloc(ix->off, (size_t)cap * sizeof(uint32_t));
|
||||
if (!p) {
|
||||
ix->valid = 0;
|
||||
return -1;
|
||||
}
|
||||
ix->off = p;
|
||||
ix->cap = cap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int line_index_init_dynamic(line_index_t *ix, uint32_t initial_cap)
|
||||
{
|
||||
if (!ix)
|
||||
return -1;
|
||||
if (initial_cap < 2)
|
||||
initial_cap = LINE_IX_DYNAMIC_INIT;
|
||||
uint32_t *off = (uint32_t *)malloc((size_t)initial_cap * sizeof(uint32_t));
|
||||
if (!off)
|
||||
return -1;
|
||||
ix->off = off;
|
||||
ix->cap = initial_cap;
|
||||
ix->n = 1;
|
||||
ix->off[0] = 0;
|
||||
ix->off[1] = 0;
|
||||
ix->cur = 0;
|
||||
ix->valid = 1;
|
||||
ix->owned = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void line_index_free(line_index_t *ix)
|
||||
{
|
||||
if (!ix)
|
||||
return;
|
||||
if (ix->owned) {
|
||||
free(ix->off);
|
||||
ix->off = NULL;
|
||||
ix->owned = 0;
|
||||
ix->cap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void line_index_build(const char *input, size_t len, line_index_t *ix)
|
||||
{
|
||||
ix->n = 1;
|
||||
ix->off[0] = 0;
|
||||
ix->cur = 0;
|
||||
ix->valid = 1;
|
||||
|
||||
const char *start = input;
|
||||
const char *end = input + len;
|
||||
const char *hit;
|
||||
while ((hit = memchr(start, '\n', (size_t)(end - start))) != NULL) {
|
||||
if (ix->n + 1 >= ix->cap) {
|
||||
if (line_index_ensure(ix, ix->n + 2) != 0)
|
||||
return;
|
||||
}
|
||||
ix->off[ix->n++] = (uint32_t)(hit - input) + 1;
|
||||
start = hit + 1;
|
||||
}
|
||||
if (ix->n >= ix->cap) {
|
||||
if (line_index_ensure(ix, ix->n + 1) != 0)
|
||||
return;
|
||||
}
|
||||
ix->off[ix->n] = (uint32_t)len;
|
||||
}
|
||||
|
||||
size_t line_index_extend(line_index_t *ix, const char *input,
|
||||
size_t old_len, size_t new_len)
|
||||
{
|
||||
if (!ix || !ix->valid || new_len <= old_len)
|
||||
return 0;
|
||||
|
||||
size_t last_nl = 0;
|
||||
const char *start = input + old_len;
|
||||
const char *end = input + new_len;
|
||||
const char *hit;
|
||||
while ((hit = memchr(start, '\n', (size_t)(end - start))) != NULL) {
|
||||
if (ix->n + 1 >= ix->cap) {
|
||||
if (line_index_ensure(ix, ix->n + 2) != 0)
|
||||
return last_nl;
|
||||
}
|
||||
last_nl = (size_t)(hit - input) + 1;
|
||||
ix->off[ix->n++] = (uint32_t)last_nl;
|
||||
start = hit + 1;
|
||||
}
|
||||
if (ix->n >= ix->cap) {
|
||||
if (line_index_ensure(ix, ix->n + 1) != 0)
|
||||
return last_nl;
|
||||
}
|
||||
ix->off[ix->n] = (uint32_t)new_len;
|
||||
return last_nl;
|
||||
}
|
||||
|
||||
static uint32_t line_no(const line_index_t *ix, size_t pos)
|
||||
{
|
||||
uint32_t lo = 0;
|
||||
uint32_t hi = ix->n;
|
||||
while (lo + 1 < hi) {
|
||||
uint32_t mid = (lo + hi) / 2;
|
||||
if (ix->off[mid] <= pos)
|
||||
lo = mid;
|
||||
else
|
||||
hi = mid;
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
|
||||
void line_index_seek(line_index_t *ix, size_t pos)
|
||||
{
|
||||
if (!ix || !ix->valid)
|
||||
return;
|
||||
ix->cur = line_no(ix, pos);
|
||||
}
|
||||
|
||||
static uint32_t resolve_line(line_index_t *ix, size_t pos)
|
||||
{
|
||||
/* Sequential hot path: render walks lines in order. */
|
||||
if (ix->cur < ix->n && ix->off[ix->cur] == (uint32_t)pos)
|
||||
return ix->cur;
|
||||
if (ix->cur + 1 < ix->n && ix->off[ix->cur + 1] == (uint32_t)pos) {
|
||||
ix->cur++;
|
||||
return ix->cur;
|
||||
}
|
||||
ix->cur = line_no(ix, pos);
|
||||
return ix->cur;
|
||||
}
|
||||
|
||||
size_t line_end_ix(line_index_t *ix, const char *input, size_t len, size_t pos)
|
||||
{
|
||||
if (!ix || !ix->valid)
|
||||
return scan_line_end(input, len, pos);
|
||||
|
||||
uint32_t k = resolve_line(ix, pos);
|
||||
size_t next = (size_t)ix->off[k + 1];
|
||||
if (next > 0 && next <= len && input[next - 1] == '\n')
|
||||
return next - 1;
|
||||
return next <= len ? next : len;
|
||||
}
|
||||
|
||||
size_t skip_line_ix(line_index_t *ix, const char *input, size_t len, size_t pos)
|
||||
{
|
||||
if (!ix || !ix->valid)
|
||||
return scan_skip_line(input, len, pos);
|
||||
|
||||
uint32_t k = resolve_line(ix, pos);
|
||||
size_t next = (size_t)ix->off[k + 1];
|
||||
if (next > len)
|
||||
return len;
|
||||
/* Advance cursor to the next line start (may equal n at EOF). */
|
||||
ix->cur = k + 1;
|
||||
return next;
|
||||
}
|
||||
Reference in New Issue
Block a user