Parsee/src/StrSplit.c
LDA b0cf0961a3 [FIX] Make codebase *slightly* NetBSD-friendly
I need to make it so that NetBSD targets get their own
correctness/build checks in CI. I also had to do some hacks with
Cytoplasm, will make a PR for those soon.
2024-10-22 10:21:54 +02:00

260 lines
4.4 KiB
C

#include <StringSplit.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Str.h>
#include <Cytoplasm/Log.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
char **
StrSplitLines(char *text)
{
char **ret = NULL;
size_t lines = 0;
char *next = text, *ptr = text;
bool done = false;
if (!text)
{
return NULL;
}
while (!done)
{
size_t bytes;
char *line;
next = strchr(ptr, '\n');
if (!next)
{
next = text + strlen(text);
done = true;
}
/* Take the chunk from ptr to [text] */
bytes = next - ptr;
line = Malloc(bytes + 1);
memcpy(line, ptr, bytes);
line[bytes] = '\0';
ret = Realloc(ret, sizeof(char *) * ++lines);
ret[lines - 1] = line;
ptr = *next ? next + 1 : next;
}
ret = Realloc(ret, sizeof(char *) * ++lines);
ret[lines - 1] = NULL;
return ret;
}
void
StrFreeLines(char **split)
{
char *line, **orig;
if (!split)
{
return;
}
orig = split;
while ((line = *split++))
{
Free(line);
}
Free(orig);
}
size_t
StrLines(char **split)
{
size_t i;
if (!split)
{
return 0;
}
for (i = 0; *split++; i++)
{
/* Left blank */
}
return i;
}
static size_t
StrMaxLine(char **split)
{
size_t max = 0;
if (!split)
{
return 0;
}
while (*split)
{
size_t len = strlen(*split++);
if (len > max)
{
max = len;
}
}
return max;
}
StringRect
StrFullRect(char **split)
{
return ((StringRect) {
.start_line = 0, .start_char = 0,
.end_line = StrLines(split),
.end_char = StrMaxLine(split),
.source_lines = split
});
}
char
StrGet(StringRect *rect, int line, int col)
{
size_t actual_line, actual_col;
char *linep;
if (!rect || !rect->source_lines)
{
return '\0';
}
actual_line = rect->start_line + line;
actual_col = rect->start_char + col;
if (actual_line > rect->end_line)
{
return '\0';
}
if (actual_line >= StrLines(rect->source_lines))
{
return '\0';
}
if (!(linep = rect->source_lines[actual_line]))
{
return '\0';
}
if (actual_col > strlen(linep))
{
return '\0';
}
return linep[actual_col];
}
size_t
StrViewChars(StringRect rect, int line)
{
size_t actual_line;
char *linep;
if (!rect.source_lines)
{
return 0;
}
actual_line = rect.start_line + line;
if (actual_line > rect.end_line)
{
return 0;
}
if (!(linep = rect.source_lines[actual_line]))
{
return 0;
}
return rect.end_char - rect.start_char;
}
StringRect
StrGetl(StringRect *rect, int line, bool extend)
{
size_t actual_line;
StringRect ret;
if (!rect->source_lines)
{
return StrFullRect(NULL);
}
ret = *rect;
actual_line = rect->start_line + line;
if (actual_line > rect->end_line)
{
return StrFullRect(NULL);
}
if (actual_line >= StrLines(rect->source_lines))
{
return StrFullRect(NULL);
}
ret.start_line = actual_line;
if (!extend)
{
ret.end_line = actual_line;
}
return ret;
}
StringRect
StrShift(StringRect rect, int n)
{
size_t new = rect.start_char + n;
if (new > rect.end_char)
{
new = rect.end_char;
}
rect.start_char = new;
return rect;
}
size_t
StrViewLines(StringRect view)
{
if (view.start_line > view.end_line)
{
return 0;
}
return view.end_line - view.start_line + 1;
}
char *
StrViewToStr(StringRect rect)
{
size_t i;
char *ret = NULL, *rtmp;
if (!rect.source_lines)
{
return NULL;
}
for (i = 0; i < StrViewLines(rect); i++)
{
char *line = NULL, *tmp;
char cbuf[2] = { 0, '\0' };
size_t chi = 0;
bool last = i == StrViewLines(rect) - 1;
while ((*cbuf = StrGet(&rect, i, chi)) != '\0' &&
chi++ <= StrViewChars(rect, i))
{
rtmp = line;
line = StrConcat(2, line, cbuf);
Free(rtmp);
}
tmp = ret;
ret = StrConcat(3, ret, line, last ? "\n" : "\n");
Free(tmp);
Free(line);
}
return ret;
}