#include "../ui.h"
#include "uipriv.h"
#include "attrstr.h"
struct attr {
uiAttribute *val;
size_t start;
size_t end;
struct attr *prev;
struct attr *next;
};
struct uiprivAttrList {
struct attr *first;
struct attr *last;
};
static void attrInsertBefore(uiprivAttrList *alist, struct attr *a, struct attr *before)
{
if (alist->first == NULL) {
alist->first = a;
alist->last = a;
return;
}
if (before == NULL) {
struct attr *oldlast;
oldlast = alist->last;
alist->last = a;
a->prev = oldlast;
oldlast->next = a;
return;
}
if (before == alist->first) {
struct attr *oldfirst;
oldfirst = alist->first;
alist->first = a;
oldfirst->prev = a;
a->next = oldfirst;
return;
}
a->prev = before->prev;
a->next = before;
before->prev = a;
a->prev->next = a;
}
static int attrHasPos(struct attr *a, size_t pos)
{
if (pos < a->start)
return 0;
return pos < a->end;
}
static int attrRangeIntersect(struct attr *a, size_t *start, size_t *end)
{
if (*start >= a->end)
return 0;
if (*end < a->start)
return 0;
if (*start < a->start)
*start = a->start;
if (*end > a->end)
*end = a->end;
return 1;
}
static struct attr *attrUnlink(uiprivAttrList *alist, struct attr *a)
{
struct attr *p, *n;
p = a->prev;
n = a->next;
a->prev = NULL;
a->next = NULL;
if (p == NULL && n == NULL) {
alist->first = NULL;
alist->last = NULL;
return NULL;
}
if (p == NULL) {
n->prev = NULL;
alist->first = n;
return n;
}
if (n == NULL) {
p->next = NULL;
alist->last = p;
return NULL;
}
p->next = n;
n->prev = p;
return n;
}
static struct attr *attrDelete(uiprivAttrList *alist, struct attr *a)
{
struct attr *next;
next = attrUnlink(alist, a);
uiprivAttributeRelease(a->val);
uiprivFree(a);
return next;
}
static struct attr *attrDropRange(uiprivAttrList *alist, struct attr *a, size_t start, size_t end, struct attr **tail)
{
struct attr *b;
*tail = NULL;
if (!attrRangeIntersect(a, &start, &end))
return a->next;
if (a->start >= start && a->end <= end)
return attrDelete(alist, a);
if (a->start == start) { a->start = end;
*tail = a;
return attrUnlink(alist, a);
}
if (a->end == end) { a->end = start;
return a->next;
}
b = uiprivNew(struct attr);
b->val = uiprivAttributeRetain(a->val);
b->start = end;
b->end = a->end;
*tail = b;
a->end = start;
return a->next;
}
static void attrGrow(uiprivAttrList *alist, struct attr *a, size_t start, size_t end)
{
struct attr *before;
if (a->end < end)
a->end = end;
if (a->start <= start)
return;
a->start = start;
attrUnlink(alist, a);
for (before = alist->first; before != NULL; before = before->next)
if (before->start > a->start)
break;
attrInsertBefore(alist, a, before);
}
static struct attr *attrSplitAt(uiprivAttrList *alist, struct attr *a, size_t at)
{
struct attr *b;
if (at <= a->start)
return NULL;
if (at >= a->end)
return NULL;
b = uiprivNew(struct attr);
b->val = uiprivAttributeRetain(a->val);
b->start = at;
b->end = a->end;
a->end = at;
return b;
}
static struct attr *attrDeleteRange(uiprivAttrList *alist, struct attr *a, size_t start, size_t end)
{
size_t ostart, oend;
size_t count;
ostart = start;
oend = end;
count = oend - ostart;
if (!attrRangeIntersect(a, &start, &end)) {
if (a->start >= ostart)
a->start -= count;
if (a->end >= oend)
a->end -= count;
return a->next;
}
if (a->start >= start && a->end <= end)
return attrDelete(alist, a);
if (a->start == start) { a->start = end - count;
a->end -= count;
return a->next;
}
if (a->end == end) { a->end = start;
return a->next;
}
a->end -= count;
return a->next;
}
uiprivAttrList *uiprivNewAttrList(void)
{
return uiprivNew(uiprivAttrList);
}
void uiprivFreeAttrList(uiprivAttrList *alist)
{
struct attr *a, *next;
a = alist->first;
while (a != NULL) {
next = a->next;
uiprivAttributeRelease(a->val);
uiprivFree(a);
a = next;
}
uiprivFree(alist);
}
void uiprivAttrListInsertAttribute(uiprivAttrList *alist, uiAttribute *val, size_t start, size_t end)
{
struct attr *a;
struct attr *before;
struct attr *tail = NULL;
int split = 0;
uiAttributeType valtype;
before = alist->first;
valtype = uiAttributeGetType(val);
while (before != NULL) {
size_t lstart, lend;
if (before->start > start)
break;
if (split)
goto next;
if (uiAttributeGetType(before->val) != valtype)
goto next;
lstart = start;
lend = end;
if (!attrRangeIntersect(before, &lstart, &lend))
goto next;
if (uiprivAttributeEqual(before->val, val)) {
attrGrow(alist, before, start, end);
return;
}
before = attrDropRange(alist, before, start, end, &tail);
split = 1;
continue;
next:
before = before->next;
}
a = uiprivNew(struct attr);
a->val = uiprivAttributeRetain(val);
a->start = start;
a->end = end;
attrInsertBefore(alist, a, before);
if (tail == NULL)
return;
for (; before != NULL; before = before->next)
if (before->start > tail->start)
break;
attrInsertBefore(alist, tail, before);
}
void uiprivAttrListInsertCharactersUnattributed(uiprivAttrList *alist, size_t start, size_t count)
{
struct attr *a;
struct attr *tails = NULL;
for (a = alist->first; a != NULL; a = a->next) {
struct attr *tail;
if (a->start >= start)
break;
if (!attrHasPos(a, start))
continue;
tail = attrSplitAt(alist, a, start);
tail->start += count;
tail->end += count;
tail->next = tails;
tails = tail;
}
while (tails != NULL) {
struct attr *next;
next = tails->next;
tails->next = NULL;
attrInsertBefore(alist, tails, a);
tails = next;
}
for (; a != NULL; a = a->next) {
a->start += count;
a->end += count;
}
}
void uiprivAttrListInsertCharactersExtendingAttributes(uiprivAttrList *alist, size_t start, size_t count)
{
struct attr *a;
for (a = alist->first; a != NULL; a = a->next) {
if (a->start < start)
a->start += count;
else if (a->start == start && start != 0)
a->start += count;
if (a->end <= start)
a->end += count;
}
}
void uiprivAttrListRemoveAttribute(uiprivAttrList *alist, uiAttributeType type, size_t start, size_t end)
{
struct attr *a;
struct attr *tails = NULL; struct attr *tailsAt = NULL;
a = alist->first;
while (a != NULL) {
size_t lstart, lend;
struct attr *tail;
if (a->start >= end) {
tailsAt = a;
break;
}
if (uiAttributeGetType(a->val) != type)
goto next;
lstart = start;
lend = end;
if (!attrRangeIntersect(a, &lstart, &lend))
goto next;
a = attrDropRange(alist, a, start, end, &tail);
if (tail != NULL) {
tail->next = tails;
tails = tail;
}
continue;
next:
a = a->next;
}
while (tails != NULL) {
struct attr *next;
next = tails->next;
tails->next = NULL;
attrInsertBefore(alist, tails, a);
tails = next;
}
}
void uiprivAttrListRemoveAttributes(uiprivAttrList *alist, size_t start, size_t end)
{
struct attr *a;
struct attr *tails = NULL; struct attr *tailsAt = NULL;
a = alist->first;
while (a != NULL) {
size_t lstart, lend;
struct attr *tail;
if (a->start >= end) {
tailsAt = a;
break;
}
lstart = start;
lend = end;
if (!attrRangeIntersect(a, &lstart, &lend))
goto next;
a = attrDropRange(alist, a, start, end, &tail);
if (tail != NULL) {
tail->next = tails;
tails = tail;
}
continue;
next:
a = a->next;
}
while (tails != NULL) {
struct attr *next;
next = tails->next;
tails->next = NULL;
attrInsertBefore(alist, tails, a);
tails = next;
}
}
void uiprivAttrListRemoveCharacters(uiprivAttrList *alist, size_t start, size_t end)
{
struct attr *a;
a = alist->first;
while (a != NULL)
a = attrDeleteRange(alist, a, start, end);
}
void uiprivAttrListForEach(const uiprivAttrList *alist, const uiAttributedString *s, uiAttributedStringForEachAttributeFunc f, void *data)
{
struct attr *a;
uiForEach ret;
for (a = alist->first; a != NULL; a = a->next) {
ret = (*f)(s, a->val, a->start, a->end, data);
if (ret == uiForEachStop)
break;
}
}