/* * id.c - Registry of unique and alphabetically sorted identifiers * * Written 2010 by Werner Almesberger * Copyright 2010 Werner Almesberger * * This program 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 2 of the License, or * (at your option) any later version. */ #include <string.h> #include <ctype.h> #include "jrb.h" #include "util.h" #include "id.h" static struct id *free_id = NULL; /* ----- ID comparison (regular string compare) ---------------------------- */ static int do_comp_id(const struct id *a, const struct id *b) { int len = a->len < b->len ? a->len : b->len; int cmp; cmp = memcmp(a->s, b->s, len); if (cmp) return cmp; return a->len < b->len ? -1 : a->len > b->len; } int comp_id(const void *a, const void *b) { return do_comp_id(a, b); } /* ----- Version comparison ------------------------------------------------ */ static int epoch(const char **s, const struct id *id) { const char *end = id->s+id->len; int n = 0; while (*s != end && isdigit(**s)) { n = 10*n+**s-'0'; (*s)++; } if (*s == id->s || (*s != end && **s == ':')) return n; *s = id->s; return 0; } int comp_versions(const struct id *va, const struct id *vb) { int epoch_a = 0, epoch_b = 0; const char *a = va->s; const char *b = vb->s; const char *ea = a+va->len; const char *eb = b+vb->len; epoch_a = epoch(&a, va); epoch_b = epoch(&b, vb); if (epoch_a != epoch_b) return epoch_a-epoch_b; while (1) { if (a == ea || b == eb) return (a != ea)-(b != eb); if (isdigit(*a) && isdigit(*b)) { int na = 0, nb = 0; while (a != ea && isdigit(*a)) { na = na*10+*a-'0'; a++; } while (b != eb && isdigit(*b)) { nb = nb*10+*b-'0'; b++; } if (na == nb) continue; return na-nb; } if (*a > *b) return 1; if (*a < *b) return 1; a++; b++; } } /* ----- Tree maintenance -------------------------------------------------- */ struct tree *make_tree(int (*comp)(const void *a, const void *b)) { struct tree *tree; tree = alloc_type(struct tree); tree->comp = comp; tree->root = make_jrb(); return tree; } struct jrb *make_id(struct tree *tree, const char *s, size_t len) { struct id *id; if (!free_id) free_id = alloc_type(struct id); id = free_id; id->s = s; id->len = len; id->jrb = jrb_find_or_insert(tree->root, id, NULL, tree->comp); if (id->jrb->key == id) free_id = NULL; return id->jrb; } const struct jrb *find_id(const struct tree *tree, const char *s, size_t len) { struct id id = { .s = s, .len = len }; return jrb_find(tree->root, &id, tree->comp); }