#include #include #include #include #include #include #include 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; }