/* Copyright (C) 2018 Curtis McEnroe * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include static struct Span { size_t at; size_t to; } Span(size_t at, size_t to) { return (struct Span) { at, to }; } static bool spanEqual(struct Span a, struct Span b) { return a.at == b.at && a.to == b.to; } static bool spanIn(struct Span a, struct Span b) { return a.at > b.at && a.to < b.to; } static bool spanHeadIn(struct Span a, struct Span b) { return a.at > b.at && a.at < b.to; } static bool spanTailIn(struct Span a, struct Span b) { return a.to > b.at && a.to < b.to; } static struct Seg { char *ptr; size_t len; } Seg(char *ptr, size_t len) { return (struct Seg) { ptr, len }; } static struct Seg segHead(struct Seg seg, size_t at) { return Seg(seg.ptr, at); } static struct Seg segTail(struct Seg seg, size_t at) { return Seg(seg.ptr + at, seg.len - at); } static struct Table { struct Table *next; struct Table *prev; size_t len; struct Seg seg[]; } *Table(size_t cap) { size_t size = sizeof(struct Table) + cap * sizeof(struct Seg); struct Table *table = malloc(size); if (!table) err(EX_OSERR, "malloc"); memset(table, 0, size); return table; } static struct TableIter { size_t len; struct Seg *seg; struct Span span; } TableIter(struct Table *table) { if (table->len) { return (struct TableIter) { table->len, &table->seg[0], Span(0, table->seg[0].len), }; } else { return (struct TableIter) { 0, NULL, Span(0, 0) }; } } static void tableNext(struct TableIter *it) { it->len--; it->seg++; it->span = Span(it->span.to, it->span.to + it->seg->len); } static struct Seg *tableAt(struct Table *table, size_t at) { for (struct TableIter it = TableIter(table); it.len; tableNext(&it)) { if (it.span.at == at) return it.seg; } return NULL; } static struct Table *tableInsert(struct Table *prev, size_t at, struct Seg seg) { struct Table *next = Table(prev->len + 2); if (!prev->len) { next->seg[next->len++] = seg; return next; } struct Span span = Span(at, at + seg.len); for (struct TableIter it = TableIter(prev); it.len; tableNext(&it)) { if (it.span.at == at) { next->seg[next->len++] = seg; next->seg[next->len++] = *it.seg; } else if (spanHeadIn(span, it.span)) { next->seg[next->len++] = segHead(*it.seg, at - it.span.at); next->seg[next->len++] = seg; next->seg[next->len++] = segTail(*it.seg, at - it.span.at); } else { next->seg[next->len++] = *it.seg; } } return next; } static struct Table *tableDelete(struct Table *prev, struct Span span) { struct Table *next = Table(prev->len + 1); for (struct TableIter it = TableIter(prev); it.len; tableNext(&it)) { if (spanIn(it.span, span) || spanEqual(it.span, span)) { // drop } else if (spanIn(span, it.span)) { next->seg[next->len++] = segHead(*it.seg, span.at - it.span.at); next->seg[next->len++] = segTail(*it.seg, span.to - it.span.at); } else if (spanHeadIn(span, it.span)) { next->seg[next->len++] = segHead(*it.seg, span.at - it.span.at); } else if (spanTailIn(span, it.span)) { next->seg[next->len++] = segTail(*it.seg, span.to - it.span.at); } else { next->seg[next->len++] = *it.seg; } } return next; } static struct CharIter { struct TableIter in; struct Seg seg; struct Span span; wchar_t ch; int len; } CharIter(struct Table *table, size_t at) { struct TableIter in; for (in = TableIter(table); in.len; tableNext(&in)) { if (at >= in.span.at && at < in.span.to) break; } struct CharIter it = { in, segTail(*in.seg, at - in.span.at), Span(at, in.span.to), 0, 0, }; it.len = mbtowc(&it.ch, it.seg.ptr, it.seg.len); if (it.len < 0) err(EX_DATAERR, "mbtowc"); return it; } static void charNext(struct CharIter *it) { it->seg.ptr += it->len; it->seg.len -= it->len; it->span.at += it->len; if (!it->seg.len && it->in.len) { tableNext(&it->in); it->seg = *it->in.seg; it->span = it->in.span; } it->len = mbtowc(&it->ch, it->seg.ptr, it->seg.len); if (it->len < 0) err(EX_DATAERR, "mbtowc"); } int main() { struct Table *table = Table(0); table = tableInsert(table, 0, Seg("Hello, world!\n", 14)); table = tableDelete(table, Span(1, 5)); table = tableInsert(table, 1, Seg("owdy", 5)); table = tableDelete(table, Span(3, 6)); table = tableInsert(table, 3, Seg(" do", 3)); for (struct CharIter it = CharIter(table, 0); it.seg.len; charNext(&it)) { printf("%C", it.ch); } }