/* grecs - Gray's Extensible Configuration System Copyright (C) 2007-2016 Sergey Poznyakoff Grecs is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Grecs 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Grecs. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include struct grecs_list * grecs_list_create() { struct grecs_list *lp = grecs_malloc(sizeof(*lp)); memset(lp, 0, sizeof(*lp)); return lp; } size_t grecs_list_size(struct grecs_list *lp) { return lp ? lp->count : 0; } void grecs_list_insert_entry(struct grecs_list *lp, struct grecs_list_entry *anchor, struct grecs_list_entry *ent, int before) { struct grecs_list_entry *p; if (!anchor) { ent->prev = NULL; ent->next = lp->head; if (lp->head) lp->head->prev = ent; else lp->tail = ent; lp->head = ent; lp->count++; return; } if (before) { grecs_list_insert_entry(lp, anchor->prev, ent, 0); return; } ent->prev = anchor; if ((p = anchor->next)) p->prev = ent; else lp->tail = ent; ent->next = p; anchor->next = ent; lp->count++; } void grecs_list_remove_entry(struct grecs_list *lp, struct grecs_list_entry *ent) { struct grecs_list_entry *p; if ((p = ent->prev)) p->next = ent->next; else lp->head = ent->next; if ((p = ent->next)) p->prev = ent->prev; else lp->tail = ent->prev; grecs_free(ent); lp->count--; } void * grecs_list_remove_tail(struct grecs_list *lp) { void *data; struct grecs_list_entry *ep; if (!lp || !lp->tail) return NULL; ep = lp->tail; data = lp->tail->data; grecs_list_remove_entry(lp, ep); return data; } static int _ptrcmp(const void *a, const void *b) { return a != b; } int grecs_list_remove(struct grecs_list *lp, void *data) { struct grecs_list_entry *ep; int (*cmp)(const void *, const void *); if (!lp) return 1; cmp = lp->cmp ? lp->cmp : _ptrcmp; for (ep = lp->head; ep; ep = ep->next) { if (cmp(ep->data, data) == 0) { grecs_list_remove_entry(lp, ep); return 0; } } return 1; } void grecs_list_append(struct grecs_list *lp, void *val) { struct grecs_list_entry *ep = grecs_malloc(sizeof(*ep)); ep->data = val; grecs_list_insert_entry(lp, lp->tail, ep, 0); } void grecs_list_add(struct grecs_list *dst, struct grecs_list *src) { if (!src->head) return; src->head->prev = dst->tail; if (dst->tail) dst->tail->next = src->head; else dst->head = src->head; dst->tail = src->tail; dst->count += src->count; src->head = src->tail = NULL; src->count = 0; } void grecs_list_push(struct grecs_list *lp, void *val) { struct grecs_list_entry *ep = grecs_malloc(sizeof(*ep)); ep->data = val; grecs_list_insert_entry(lp, NULL, ep, 0); } void * grecs_list_pop(struct grecs_list *lp) { void *data; struct grecs_list_entry *ep; if (!lp) return NULL; ep = lp->head; if (ep) { data = ep->data; grecs_list_remove_entry(lp, ep); } else data = NULL; return data; } void grecs_list_clear(struct grecs_list *lp) { struct grecs_list_entry *ep; if (!lp) return; ep = lp->head; while (ep) { struct grecs_list_entry *next = ep->next; if (lp->free_entry) lp->free_entry(ep->data); grecs_free(ep); ep = next; } lp->head = lp->tail = NULL; lp->count = 0; } void grecs_list_free(struct grecs_list *lp) { if (lp) { grecs_list_clear(lp); grecs_free(lp); } } void * grecs_list_locate(struct grecs_list *lp, void *data) { struct grecs_list_entry *ep; int (*cmp)(const void *, const void *); if (!lp) return NULL; cmp = lp->cmp ? lp->cmp : _ptrcmp; for (ep = lp->head; ep; ep = ep->next) { if (cmp(ep->data, data) == 0) return ep->data; } return NULL; } void * grecs_list_index(struct grecs_list *lp, size_t idx) { struct grecs_list_entry *ep; if (!lp) return NULL; for (ep = lp->head; ep && idx; ep = ep->next, idx--) ; return ep ? ep->data : NULL; } int grecs_list_compare(struct grecs_list *a, struct grecs_list *b) { struct grecs_list_entry *ap, *bp; int (*cmp)(const void *, const void *); if (!a) return !!b; else if (!b) return 1; if (grecs_list_size(a) != grecs_list_size(b)) return 1; if (a->cmp != b->cmp) return 1; cmp = a->cmp ? a->cmp : _ptrcmp; for (ap = a->head, bp = b->head; ap; ap = ap->next, bp = bp->next) if (cmp(ap->data, bp->data)) return 1; return 0; }