krh@15: #define _GNU_SOURCE krh@15: krh@0: #include krh@19: #include krh@0: #include krh@0: #include krh@0: #include krh@0: #include krh@0: #include krh@0: #include krh@0: #include krh@15: #include krh@35: #include krh@0: krh@27: #include "razor.h" krh@6: krh@30: struct array { krh@30: void *data; krh@30: int size, alloc; krh@30: }; krh@30: krh@30: struct razor_set_section { krh@30: unsigned int type; krh@30: unsigned int offset; krh@30: unsigned int size; krh@30: }; krh@30: krh@30: struct razor_set_header { krh@30: unsigned int magic; krh@30: unsigned int version; krh@30: struct razor_set_section sections[0]; krh@30: }; krh@30: krh@30: #define RAZOR_MAGIC 0x7a7a7a7a krh@30: #define RAZOR_VERSION 1 krh@30: krh@30: #define RAZOR_PACKAGES 0 krh@30: #define RAZOR_REQUIRES 1 krh@30: #define RAZOR_PROVIDES 2 krh@30: #define RAZOR_STRING_POOL 3 krh@39: #define RAZOR_PACKAGE_POOL 4 krh@39: #define RAZOR_REQUIRES_POOL 5 krh@39: #define RAZOR_PROVIDES_POOL 6 krh@48: #define RAZOR_FILE_TREE 7 krh@30: krh@30: struct razor_package { krh@30: unsigned long name; krh@30: unsigned long version; krh@30: unsigned long requires; krh@30: unsigned long provides; krh@30: }; krh@30: krh@30: struct razor_property { krh@30: unsigned long name; krh@30: unsigned long version; krh@30: unsigned long packages; krh@30: }; krh@30: krh@48: struct razor_entry { krh@48: unsigned long name; krh@48: unsigned long count; krh@48: unsigned long start; krh@48: }; krh@48: krh@30: struct razor_set { krh@30: struct array string_pool; krh@30: struct array packages; krh@39: struct array package_pool; krh@30: struct array requires; krh@30: struct array provides; krh@39: struct array requires_pool; krh@39: struct array provides_pool; krh@48: struct array file_tree; krh@30: struct razor_set_header *header; krh@30: }; krh@30: krh@30: struct import_property_context { krh@30: struct array *all; krh@30: struct array package; krh@30: }; krh@30: krh@30: struct razor_importer { krh@30: struct razor_set *set; krh@32: struct array buckets; krh@30: struct import_property_context requires; krh@30: struct import_property_context provides; krh@30: struct razor_package *package; krh@48: struct array files; krh@30: }; krh@30: krh@13: static void krh@13: array_init(struct array *array) krh@13: { krh@13: memset(array, 0, sizeof *array); krh@13: } krh@13: krh@13: static void krh@13: array_release(struct array *array) krh@13: { krh@13: free(array->data); krh@13: } krh@13: krh@6: static void * krh@6: array_add(struct array *array, int size) krh@6: { krh@6: int alloc; krh@6: void *data, *p; krh@6: krh@6: if (array->alloc > 0) krh@6: alloc = array->alloc; krh@6: else krh@10: alloc = 16; krh@6: krh@6: while (alloc < array->size + size) krh@6: alloc *= 2; krh@6: krh@6: if (array->alloc < alloc) { krh@6: data = realloc(array->data, alloc); krh@6: if (data == NULL) krh@6: return 0; krh@6: array->data = data; krh@6: array->alloc = alloc; krh@6: } krh@6: krh@6: p = array->data + array->size; krh@6: array->size += size; krh@6: krh@6: return p; krh@6: } krh@6: krh@0: static int krh@0: write_to_fd(int fd, void *p, size_t size) krh@0: { krh@0: int rest, len; krh@0: krh@0: rest = size; krh@0: while (rest > 0) { krh@0: len = write(fd, p, rest); krh@0: if (len < 0) krh@0: return -1; krh@0: rest -= len; krh@0: } krh@0: krh@0: return 0; krh@0: } krh@0: krh@0: static void * krh@0: zalloc(size_t size) krh@0: { krh@0: void *p; krh@0: krh@0: p = malloc(size); krh@0: memset(p, 0, size); krh@0: krh@0: return p; krh@0: } krh@0: krh@19: struct razor_set_section razor_sections[] = { krh@19: { RAZOR_PACKAGES, offsetof(struct razor_set, packages) }, krh@19: { RAZOR_REQUIRES, offsetof(struct razor_set, requires) }, krh@19: { RAZOR_PROVIDES, offsetof(struct razor_set, provides) }, krh@19: { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) }, krh@39: { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) }, krh@39: { RAZOR_REQUIRES_POOL, offsetof(struct razor_set, requires_pool) }, krh@39: { RAZOR_PROVIDES_POOL, offsetof(struct razor_set, provides_pool) }, krh@48: { RAZOR_FILE_TREE, offsetof(struct razor_set, file_tree) }, krh@19: }; krh@19: krh@4: struct razor_set * krh@4: razor_set_create(void) krh@0: { krh@18: return zalloc(sizeof(struct razor_set)); krh@0: } krh@0: krh@4: struct razor_set * krh@4: razor_set_open(const char *filename) krh@0: { krh@4: struct razor_set *set; krh@19: struct razor_set_section *s; krh@0: struct stat stat; krh@19: struct array *array; krh@19: int fd; krh@0: krh@4: set = zalloc(sizeof *set); krh@0: fd = open(filename, O_RDONLY); krh@0: if (fstat(fd, &stat) < 0) krh@0: return NULL; krh@4: set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0); krh@4: if (set->header == MAP_FAILED) { krh@4: free(set); krh@0: return NULL; krh@0: } krh@0: krh@19: for (s = set->header->sections; ~s->type; s++) { krh@19: if (s->type >= ARRAY_SIZE(razor_sections)) krh@19: continue; krh@19: if (s->type != razor_sections[s->type].type) krh@19: continue; krh@19: array = (void *) set + razor_sections[s->type].offset; krh@19: array->data = (void *) set->header + s->offset; krh@19: array->size = s->size; krh@19: array->alloc = s->size; krh@0: } krh@0: close(fd); krh@0: krh@4: return set; krh@0: } krh@0: krh@0: void krh@4: razor_set_destroy(struct razor_set *set) krh@0: { krh@0: unsigned int size; krh@19: struct array *a; krh@0: int i; krh@0: krh@4: if (set->header) { krh@4: for (i = 0; set->header->sections[i].type; i++) krh@0: ; krh@4: size = set->header->sections[i].type; krh@4: munmap(set->header, size); krh@0: } else { krh@19: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { krh@19: a = (void *) set + razor_sections[i].offset; krh@19: free(a->data); krh@19: } krh@0: } krh@0: krh@4: free(set); krh@0: } krh@0: krh@43: int krh@4: razor_set_write(struct razor_set *set, const char *filename) krh@0: { krh@0: char data[4096]; krh@4: struct razor_set_header *header = (struct razor_set_header *) data; krh@19: struct array *a; krh@17: unsigned long offset; krh@17: int i, fd; krh@0: krh@0: memset(data, 0, sizeof data); krh@4: header->magic = RAZOR_MAGIC; krh@4: header->version = RAZOR_VERSION; krh@17: offset = sizeof data; krh@0: krh@19: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { krh@19: if (razor_sections[i].type != i) krh@19: continue; krh@19: a = (void *) set + razor_sections[i].offset; krh@19: header->sections[i].type = i; krh@17: header->sections[i].offset = offset; krh@19: header->sections[i].size = a->size; krh@19: offset += (a->size + 4095) & ~4095; krh@17: } krh@0: krh@19: header->sections[i].type = ~0; krh@17: header->sections[i].offset = 0; krh@17: header->sections[i].size = 0; krh@10: krh@0: fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); krh@0: if (fd < 0) krh@0: return -1; krh@0: krh@0: write_to_fd(fd, data, sizeof data); krh@19: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { krh@19: if (razor_sections[i].type != i) krh@19: continue; krh@19: a = (void *) set + razor_sections[i].offset; krh@19: write_to_fd(fd, a->data, (a->size + 4095) & ~4095); krh@19: } krh@17: krh@17: close(fd); krh@0: krh@0: return 0; krh@0: } krh@0: krh@0: static unsigned int krh@0: hash_string(const char *key) krh@0: { krh@0: const char *p; krh@0: unsigned int hash = 0; krh@0: krh@0: for (p = key; *p; p++) krh@9: hash = (hash * 617) ^ *p; krh@0: krh@0: return hash; krh@0: } krh@0: krh@32: static unsigned long krh@32: razor_importer_lookup(struct razor_importer *importer, const char *key) krh@0: { krh@6: unsigned int mask, start, i; krh@6: unsigned long *b; krh@6: char *pool; krh@0: krh@32: pool = importer->set->string_pool.data; krh@32: mask = importer->buckets.alloc - 1; krh@6: start = hash_string(key) * sizeof(unsigned long); krh@0: krh@32: for (i = 0; i < importer->buckets.alloc; i += sizeof *b) { krh@32: b = importer->buckets.data + ((start + i) & mask); krh@6: krh@6: if (*b == 0) krh@0: return 0; krh@0: krh@6: if (strcmp(key, &pool[*b]) == 0) krh@6: return *b; krh@6: } krh@0: krh@0: return 0; krh@0: } krh@0: krh@0: static unsigned long krh@4: add_to_string_pool(struct razor_set *set, const char *key) krh@0: { krh@6: int len; krh@6: char *p; krh@0: krh@0: len = strlen(key) + 1; krh@6: p = array_add(&set->string_pool, len); krh@6: memcpy(p, key, len); krh@0: krh@6: return p - (char *) set->string_pool.data; krh@0: } krh@0: krh@10: static unsigned long krh@39: add_to_property_pool(struct array *pool, struct array *properties) krh@10: { krh@10: unsigned long *p; krh@10: krh@10: p = array_add(properties, sizeof *p); krh@18: *p = ~0ul; krh@39: p = array_add(pool, properties->size); krh@10: memcpy(p, properties->data, properties->size); krh@10: krh@39: return p - (unsigned long *) pool->data; krh@10: } krh@10: krh@0: static void krh@32: do_insert(struct razor_importer *importer, unsigned long value) krh@0: { krh@6: unsigned int mask, start, i; krh@6: unsigned long *b; krh@0: const char *key; krh@0: krh@32: key = (char *) importer->set->string_pool.data + value; krh@32: mask = importer->buckets.alloc - 1; krh@6: start = hash_string(key) * sizeof(unsigned long); krh@6: krh@32: for (i = 0; i < importer->buckets.alloc; i += sizeof *b) { krh@32: b = importer->buckets.data + ((start + i) & mask); krh@6: if (*b == 0) { krh@6: *b = value; krh@0: break; krh@0: } krh@6: } krh@0: } krh@0: krh@32: static unsigned long krh@32: razor_importer_insert(struct razor_importer *importer, const char *key) krh@0: { krh@6: unsigned long value, *buckets, *b, *end; krh@6: int alloc; krh@0: krh@32: alloc = importer->buckets.alloc; krh@32: array_add(&importer->buckets, 4 * sizeof *buckets); krh@32: if (alloc != importer->buckets.alloc) { krh@32: end = importer->buckets.data + alloc; krh@32: memset(end, 0, importer->buckets.alloc - alloc); krh@32: for (b = importer->buckets.data; b < end; b++) { krh@6: value = *b; krh@6: if (value != 0) { krh@6: *b = 0; krh@32: do_insert(importer, value); krh@6: } krh@0: } krh@0: } krh@0: krh@32: value = add_to_string_pool(importer->set, key); krh@32: do_insert (importer, value); krh@0: krh@0: return value; krh@0: } krh@0: krh@30: static unsigned long krh@32: razor_importer_tokenize(struct razor_importer *importer, const char *string) krh@0: { krh@0: unsigned long token; krh@0: krh@13: if (string == NULL) krh@32: return razor_importer_tokenize(importer, ""); krh@13: krh@32: token = razor_importer_lookup(importer, string); krh@0: if (token != 0) krh@0: return token; krh@0: krh@32: return razor_importer_insert(importer, string); krh@0: } krh@0: krh@27: void krh@30: razor_importer_begin_package(struct razor_importer *importer, krh@30: const char *name, const char *version) krh@13: { krh@25: struct razor_package *p; krh@13: krh@30: p = array_add(&importer->set->packages, sizeof *p); krh@32: p->name = razor_importer_tokenize(importer, name); krh@32: p->version = razor_importer_tokenize(importer, version); krh@13: krh@30: importer->package = p; krh@30: array_init(&importer->requires.package); krh@30: array_init(&importer->provides.package); krh@13: } krh@13: krh@13: void krh@30: razor_importer_finish_package(struct razor_importer *importer) krh@13: { krh@25: struct razor_package *p; krh@13: krh@30: p = importer->package; krh@39: p->requires = add_to_property_pool(&importer->set->requires_pool, krh@30: &importer->requires.package); krh@39: p->provides = add_to_property_pool(&importer->set->provides_pool, krh@30: &importer->provides.package); krh@13: krh@30: array_release(&importer->requires.package); krh@30: array_release(&importer->provides.package); krh@13: } krh@13: krh@30: static void krh@30: razor_importer_add_property(struct razor_importer *importer, krh@13: struct import_property_context *pctx, krh@13: const char *name, const char *version) krh@13: { krh@25: struct razor_property *p; krh@13: unsigned long *r; krh@13: krh@25: p = array_add(pctx->all, sizeof *p); krh@32: p->name = razor_importer_tokenize(importer, name); krh@32: p->version = razor_importer_tokenize(importer, version); krh@30: p->packages = importer->package - krh@30: (struct razor_package *) importer->set->packages.data; krh@13: krh@13: r = array_add(&pctx->package, sizeof *r); krh@25: *r = p - (struct razor_property *) pctx->all->data; krh@13: } krh@13: krh@27: void krh@30: razor_importer_add_requires(struct razor_importer *importer, krh@30: const char *name, const char *version) krh@9: { krh@30: razor_importer_add_property(importer, krh@30: &importer->requires, name, version); krh@30: } krh@30: krh@30: void krh@30: razor_importer_add_provides(struct razor_importer *importer, krh@30: const char *name, const char *version) krh@30: { krh@30: razor_importer_add_property(importer, krh@30: &importer->provides, name, version); krh@30: } krh@30: krh@46: void krh@46: razor_importer_add_file(struct razor_importer *importer, const char *name) krh@46: { krh@48: char **p; krh@48: krh@48: p = array_add(&importer->files, sizeof *p); krh@48: *p = strdup(name); krh@46: } krh@46: krh@30: struct razor_importer * krh@30: razor_importer_new(void) krh@30: { krh@30: struct razor_importer *importer; krh@30: krh@30: importer = zalloc(sizeof *importer); krh@30: importer->set = razor_set_create(); krh@30: importer->requires.all = &importer->set->requires; krh@30: importer->provides.all = &importer->set->provides; krh@30: krh@30: return importer; krh@9: } krh@9: krh@22: typedef int (*compare_with_data_func_t)(const void *p1, krh@22: const void *p, krh@22: void *data); krh@22: krh@25: struct qsort_context { krh@25: size_t size; krh@25: compare_with_data_func_t compare; krh@25: void *data; krh@25: }; krh@25: krh@22: static void krh@22: qsort_swap(void *p1, void *p2, size_t size) krh@22: { krh@22: char buffer[size]; krh@22: krh@22: memcpy(buffer, p1, size); krh@22: memcpy(p1, p2, size); krh@22: memcpy(p2, buffer, size); krh@22: } krh@22: krh@25: static void krh@25: __qsort_with_data(void *base, size_t nelem, unsigned long *map, krh@25: struct qsort_context *ctx) krh@22: { krh@22: void *p, *start, *end, *pivot; krh@25: unsigned long *mp, *mstart, *mend, tmp; krh@22: int left, right, result; krh@25: size_t size = ctx->size; krh@22: krh@22: p = base; krh@22: start = base; krh@22: end = base + nelem * size; krh@25: mp = map; krh@25: mstart = map; krh@25: mend = map + nelem; krh@22: pivot = base + (random() % nelem) * size; krh@25: krh@22: while (p < end) { krh@25: result = ctx->compare(p, pivot, ctx->data); krh@22: if (result < 0) { krh@22: qsort_swap(p, start, size); krh@25: tmp = *mp; krh@25: *mp = *mstart; krh@25: *mstart = tmp; krh@22: if (start == pivot) krh@22: pivot = p; krh@22: start += size; krh@25: mstart++; krh@22: p += size; krh@29: mp++; krh@22: } else if (result == 0) { krh@22: p += size; krh@25: mp++; krh@22: } else { krh@22: end -= size; krh@25: mend--; krh@22: qsort_swap(p, end, size); krh@25: tmp = *mp; krh@29: *mp = *mend; krh@29: *mend = tmp; krh@22: if (end == pivot) krh@22: pivot = p; krh@22: } krh@22: } krh@22: krh@22: left = (start - base) / size; krh@22: right = (base + nelem * size - end) / size; krh@22: if (left > 1) krh@25: __qsort_with_data(base, left, map, ctx); krh@22: if (right > 1) krh@25: __qsort_with_data(end, right, mend, ctx); krh@25: } krh@25: krh@25: unsigned long * krh@25: qsort_with_data(void *base, size_t nelem, size_t size, krh@25: compare_with_data_func_t compare, void *data) krh@25: { krh@25: struct qsort_context ctx; krh@25: unsigned long *map; krh@25: int i; krh@25: krh@25: ctx.size = size; krh@25: ctx.compare = compare; krh@25: ctx.data = data; krh@25: krh@25: map = malloc(nelem * sizeof (unsigned long)); krh@25: for (i = 0; i < nelem; i++) krh@25: map[i] = i; krh@25: krh@25: __qsort_with_data(base, nelem, map, &ctx); krh@25: krh@25: return map; krh@22: } krh@9: krh@9: static int krh@35: versioncmp(const char *s1, const char *s2) krh@35: { krh@35: const char *p1, *p2; krh@35: long n1, n2; krh@35: int res; krh@35: krh@35: n1 = strtol(s1, (char **) &p1, 0); krh@35: n2 = strtol(s2, (char **) &p2, 0); krh@35: krh@35: /* Epoch; if one but not the other has an epoch set, default krh@35: * the epoch-less version to 0. */ krh@35: res = (*p1 == ':') - (*p2 == ':'); krh@35: if (res < 0) { krh@35: n1 = 0; krh@35: p1 = s1; krh@35: p2++; krh@35: } else if (res > 0) { krh@35: p1++; krh@35: n2 = 0; krh@35: p2 = s2; krh@35: } krh@35: krh@35: if (n1 != n2) krh@35: return n1 - n2; krh@35: while (*p1 && *p2) { krh@35: if (*p1 != *p2) krh@35: return *p1 - *p2; krh@35: p1++; krh@35: p2++; krh@35: if (isdigit(*p1) && isdigit(*p2)) krh@35: return versioncmp(p1, p2); krh@35: } krh@35: krh@35: return *p1 - *p2; krh@35: } krh@35: krh@35: krh@35: static int krh@22: compare_packages(const void *p1, const void *p2, void *data) krh@9: { krh@25: const struct razor_package *pkg1 = p1, *pkg2 = p2; krh@22: struct razor_set *set = data; krh@22: char *pool = set->string_pool.data; krh@9: krh@23: if (pkg1->name == pkg2->name) krh@35: return versioncmp(&pool[pkg1->version], &pool[pkg2->version]); krh@23: else krh@23: return strcmp(&pool[pkg1->name], &pool[pkg2->name]); krh@9: } krh@9: krh@9: static int krh@22: compare_properties(const void *p1, const void *p2, void *data) krh@9: { krh@25: const struct razor_property *prop1 = p1, *prop2 = p2; krh@22: struct razor_set *set = data; krh@22: char *pool = set->string_pool.data; krh@9: krh@23: if (prop1->name == prop2->name) krh@35: return versioncmp(&pool[prop1->version], &pool[prop2->version]); krh@12: else krh@23: return strcmp(&pool[prop1->name], &pool[prop2->name]); krh@9: } krh@9: krh@10: static unsigned long * krh@25: uniqueify_properties(struct razor_set *set, struct array *properties) krh@9: { krh@25: struct razor_property *rp, *up, *rp_end; krh@18: struct array *pkgs, *p; krh@25: unsigned long *map, *rmap, *r; krh@18: int i, count, unique; krh@9: krh@25: count = properties->size / sizeof(struct razor_property); krh@25: map = qsort_with_data(properties->data, krh@25: count, krh@25: sizeof(struct razor_property), krh@25: compare_properties, krh@25: set); krh@9: krh@25: rp_end = properties->data + properties->size; krh@25: rmap = malloc(count * sizeof *map); krh@25: pkgs = zalloc(count * sizeof *pkgs); krh@25: for (rp = properties->data, up = rp, i = 0; rp < rp_end; rp++, i++) { krh@25: if (rp->name != up->name || rp->version != up->version) { krh@25: up++; krh@25: up->name = rp->name; krh@25: up->version = rp->version; krh@10: } krh@25: krh@25: unique = up - (struct razor_property *) properties->data; krh@25: rmap[map[i]] = unique; krh@25: r = array_add(&pkgs[unique], sizeof *r); krh@25: *r = rp->packages; krh@10: } krh@25: free(map); krh@9: krh@25: up++; krh@25: properties->size = (void *) up - properties->data; krh@25: rp_end = up; krh@25: for (rp = properties->data, p = pkgs; rp < rp_end; rp++, p++) { krh@39: rp->packages = add_to_property_pool(&set->package_pool, p); krh@25: array_release(p); krh@18: } krh@18: krh@18: free(pkgs); krh@18: krh@25: return rmap; krh@10: } krh@10: krh@10: static void krh@39: remap_links(struct array *links, unsigned long *map) krh@10: { krh@39: unsigned long *p, *end; krh@10: krh@39: end = links->data + links->size; krh@39: for (p = links->data; p < end; p++) krh@39: if (*p != ~0) krh@39: *p = map[*p]; krh@9: } krh@9: krh@48: static int krh@48: compare_filenames(const void *p1, const void *p2, void *data) krh@48: { krh@48: char *f1 = *(char **) p1; krh@48: char *f2 = *(char **) p2; krh@48: krh@48: return strcmp(f1, f2); krh@48: } krh@48: krh@48: struct directory { krh@48: unsigned long name, count; krh@48: struct array files; krh@48: struct directory *last; krh@48: }; krh@48: krh@48: static void krh@48: count_entries(struct directory *d) krh@48: { krh@48: struct directory *p, *end; krh@48: krh@48: p = d->files.data; krh@48: end = d->files.data + d->files.size; krh@48: d->count = 0; krh@48: while (p < end) { krh@48: count_entries(p); krh@48: d->count += p->count + 1; krh@48: p++; krh@48: } krh@48: } krh@48: krh@48: static void krh@48: serialize_files(struct directory *d, struct array *array) krh@48: { krh@48: struct directory *p, *end; krh@48: struct razor_entry *e; krh@48: unsigned long s; krh@48: krh@48: p = d->files.data; krh@48: end = d->files.data + d->files.size; krh@48: s = array->size / sizeof *e + d->files.size / sizeof *p; krh@48: while (p < end) { krh@48: e = array_add(array, sizeof *e); krh@48: e->name = p->name; krh@48: e->count = p->files.size / sizeof *p; krh@48: e->start = s; krh@48: s += p->count; krh@48: p++; krh@48: } krh@48: krh@48: p = d->files.data; krh@48: end = d->files.data + d->files.size; krh@48: while (p < end) { krh@48: serialize_files(p, array); krh@48: p++; krh@48: } krh@48: } krh@48: krh@48: static void krh@48: build_file_tree(struct razor_importer *importer) krh@48: { krh@48: int count, i, length; krh@48: char **filenames, *f, *end; krh@48: unsigned long name; krh@48: char dirname[256]; krh@48: struct directory *d, root; krh@48: struct razor_entry *e; krh@48: krh@48: count = importer->files.size / sizeof (char *); krh@48: qsort_with_data(importer->files.data, krh@48: count, krh@48: sizeof (char *), krh@48: compare_filenames, krh@48: NULL); krh@48: krh@48: root.name = razor_importer_tokenize(importer, ""); krh@48: array_init(&root.files); krh@48: root.last = NULL; krh@48: krh@48: filenames = importer->files.data; krh@48: for (i = 0; i < count; i++) { krh@48: f = filenames[i]; krh@48: if (*f != '/') krh@48: continue; krh@48: krh@48: d = &root; krh@48: while (*f) { krh@48: end = strchr(f + 1, '/'); krh@48: if (end == NULL) krh@48: end = f + strlen(f); krh@48: length = end - (f + 1); krh@48: memcpy(dirname, f + 1, length); krh@48: dirname[length] ='\0'; krh@48: name = razor_importer_tokenize(importer, dirname); krh@48: if (d->last == NULL || d->last->name != name) { krh@48: d->last = array_add(&d->files, sizeof *d); krh@48: d->last->name = name; krh@48: d->last->last = NULL; krh@48: array_init(&d->last->files); krh@48: } krh@48: d = d->last; krh@48: f = end; krh@48: } krh@48: krh@48: free(filenames[i]); krh@48: } krh@48: krh@48: count_entries(&root); krh@48: array_init(&importer->set->file_tree); krh@48: krh@48: e = array_add(&importer->set->file_tree, sizeof *e); krh@48: e->name = root.name; krh@48: e->count = root.files.size / sizeof *d; krh@48: e->start = 1; krh@48: krh@48: serialize_files(&root, &importer->set->file_tree); krh@48: krh@48: array_release(&importer->files); krh@48: } krh@48: krh@48: static void krh@48: list_dir(struct razor_set *set, struct razor_entry *e, int indent) krh@48: { krh@48: struct razor_entry *c; krh@48: char *pool = set->string_pool.data; krh@48: int i; krh@48: krh@48: for (i = 0; i < indent; i++) krh@48: putchar(' '); krh@48: printf("%s\n", pool + e->name); krh@48: for (i = 0; i < e->count; i++) { krh@48: c = (struct razor_entry *) set->file_tree.data + e->start + i; krh@48: list_dir(set, c, indent + 2); krh@48: } krh@48: } krh@48: krh@48: void krh@48: razor_set_list_files(struct razor_set *set) krh@48: { krh@48: list_dir(set, set->file_tree.data, 2); krh@48: } krh@48: krh@27: struct razor_set * krh@30: razor_importer_finish(struct razor_importer *importer) krh@9: { krh@30: struct razor_set *set; krh@39: unsigned long *map, *rmap; krh@39: int i, count; krh@18: krh@39: map = uniqueify_properties(importer->set, &importer->set->requires); krh@39: remap_links(&importer->set->requires_pool, map); krh@39: free(map); krh@39: krh@39: map = uniqueify_properties(importer->set, &importer->set->provides); krh@39: remap_links(&importer->set->provides_pool, map); krh@39: free(map); krh@25: krh@30: count = importer->set->packages.size / sizeof(struct razor_package); krh@30: map = qsort_with_data(importer->set->packages.data, krh@25: count, krh@25: sizeof(struct razor_package), krh@25: compare_packages, krh@30: importer->set); krh@39: krh@39: rmap = malloc(count * sizeof *rmap); krh@39: for (i = 0; i < count; i++) krh@39: rmap[map[i]] = i; krh@39: krh@39: remap_links(&importer->set->package_pool, rmap); krh@25: free(map); krh@39: free(rmap); krh@13: krh@48: build_file_tree(importer); krh@48: krh@30: set = importer->set; krh@32: array_release(&importer->buckets); krh@30: free(importer); krh@30: krh@30: return set; krh@9: } krh@9: krh@0: void krh@4: razor_set_list(struct razor_set *set) krh@3: { krh@6: struct razor_package *p, *end; krh@6: char *pool; krh@3: krh@6: pool = set->string_pool.data; krh@6: end = set->packages.data + set->packages.size; krh@14: for (p = set->packages.data; p < end; p++) krh@6: printf("%s %s\n", &pool[p->name], &pool[p->version]); krh@3: } krh@3: krh@16: struct razor_set *bsearch_set; krh@16: krh@16: static int krh@16: compare_package_name(const void *key, const void *data) krh@16: { krh@16: const struct razor_package *p = data; krh@16: char *pool; krh@16: krh@16: pool = bsearch_set->string_pool.data; krh@16: krh@16: return strcmp(key, &pool[p->name]); krh@16: } krh@16: krh@10: struct razor_package * krh@10: razor_set_get_package(struct razor_set *set, const char *package) krh@10: { krh@16: bsearch_set = set; krh@16: return bsearch(package, set->packages.data, krh@16: set->packages.size / sizeof(struct razor_package), krh@16: sizeof(struct razor_package), compare_package_name); krh@10: } krh@10: krh@18: static int krh@18: compare_property_name(const void *key, const void *data) krh@18: { krh@18: const struct razor_property *p = data; krh@18: char *pool; krh@18: krh@18: pool = bsearch_set->string_pool.data; krh@18: krh@18: return strcmp(key, &pool[p->name]); krh@18: } krh@18: krh@18: struct razor_property * krh@18: razor_set_get_property(struct razor_set *set, krh@18: struct array *properties, krh@18: const char *property) krh@18: { krh@18: struct razor_property *p, *start; krh@18: krh@18: bsearch_set = set; krh@18: p = bsearch(property, properties->data, krh@18: properties->size / sizeof(struct razor_property), krh@18: sizeof(struct razor_property), compare_property_name); krh@18: krh@18: start = properties->data; krh@18: while (p > start && (p - 1)->name == p->name) krh@18: p--; krh@18: krh@18: return p; krh@18: } krh@18: krh@10: static void krh@10: razor_set_list_all_properties(struct razor_set *set, struct array *properties) krh@8: { krh@8: struct razor_property *p, *end; krh@8: char *pool; krh@8: krh@8: pool = set->string_pool.data; krh@10: end = properties->data + properties->size; krh@14: for (p = properties->data; p < end; p++) krh@8: printf("%s %s\n", &pool[p->name], &pool[p->version]); krh@8: } krh@8: krh@8: void krh@10: razor_set_list_requires(struct razor_set *set, const char *name) krh@7: { krh@10: struct razor_property *p, *requires; krh@10: struct razor_package *package; krh@10: unsigned long *r; krh@7: char *pool; krh@7: krh@10: if (name) { krh@10: package = razor_set_get_package(set, name); krh@39: r = (unsigned long *) set->requires_pool.data + krh@10: package->requires; krh@10: requires = set->requires.data; krh@10: pool = set->string_pool.data; krh@18: while (~*r) { krh@10: p = &requires[*r++]; krh@10: printf("%s %s\n", &pool[p->name], &pool[p->version]); krh@10: } krh@10: } else krh@10: razor_set_list_all_properties(set, &set->requires); krh@10: } krh@10: krh@10: void krh@10: razor_set_list_provides(struct razor_set *set, const char *name) krh@10: { krh@10: struct razor_property *p, *provides; krh@10: struct razor_package *package; krh@10: unsigned long *r; krh@10: char *pool; krh@10: krh@10: if (name) { krh@10: package = razor_set_get_package(set, name); krh@39: r = (unsigned long *) set->provides_pool.data + krh@10: package->provides; krh@10: provides = set->provides.data; krh@10: pool = set->string_pool.data; krh@18: while (~*r) { krh@10: p = &provides[*r++]; krh@10: printf("%s %s\n", &pool[p->name], &pool[p->version]); krh@10: } krh@10: } else krh@10: razor_set_list_all_properties(set, &set->provides); krh@7: } krh@7: krh@43: static void krh@18: razor_set_list_property_packages(struct razor_set *set, krh@18: struct array *properties, krh@20: const char *name, krh@20: const char *version) krh@18: { krh@18: struct razor_property *property, *end; krh@18: struct razor_package *p, *packages; krh@18: unsigned long *r; krh@18: char *pool; krh@18: krh@18: if (name == NULL) krh@18: return; krh@18: krh@18: property = razor_set_get_property(set, properties, name); krh@18: packages = set->packages.data; krh@18: pool = set->string_pool.data; krh@18: end = properties->data + properties->size; krh@18: while (property < end && strcmp(name, &pool[property->name]) == 0) { krh@35: if (version && versioncmp(version, &pool[property->version]) != 0) krh@20: goto next; krh@18: r = (unsigned long *) krh@39: set->package_pool.data + property->packages; krh@18: while (~*r) { krh@18: p = &packages[*r++]; krh@18: printf("%s %s\n", krh@18: &pool[p->name], &pool[p->version]); krh@18: } krh@20: next: krh@18: property++; krh@18: } krh@18: } krh@18: krh@18: void krh@43: razor_set_list_requires_packages(struct razor_set *set, krh@43: const char *name, krh@43: const char *version) krh@43: { krh@43: razor_set_list_property_packages(set, &set->requires, name, version); krh@43: } krh@43: krh@43: void krh@43: razor_set_list_provides_packages(struct razor_set *set, krh@43: const char *name, krh@43: const char *version) krh@43: { krh@43: razor_set_list_property_packages(set, &set->provides, name, version); krh@43: } krh@43: krh@43: static void krh@21: razor_set_validate(struct razor_set *set, struct array *unsatisfied) krh@21: { krh@21: struct razor_property *r, *p, *rend, *pend; krh@21: unsigned long *u; krh@21: char *pool; krh@21: krh@21: p = set->provides.data; krh@21: rend = set->requires.data + set->requires.size; krh@21: pend = set->provides.data + set->provides.size; krh@21: pool = set->string_pool.data; krh@21: krh@35: for (r = set->requires.data; r < rend; r++) { krh@21: while (p < pend && strcmp(&pool[r->name], &pool[p->name]) > 0) krh@21: p++; krh@37: krh@35: /* If there is more than one version of a provides, krh@35: * seek to the end for the highest version. */ krh@35: while (p + 1 < pend && p->name == (p + 1)->name) krh@35: p++; krh@37: krh@37: /* FIXME: We need to track property flags (<, <=, = krh@37: * etc) to properly determine if a requires is krh@37: * satisfied. The current code doesn't track that the krh@37: * requires a = 1 isn't satisfied by a = 2 provides. */ krh@37: krh@35: if (p == pend || strcmp(&pool[r->name], &pool[p->name]) != 0 || krh@35: versioncmp(&pool[r->version], &pool[p->version]) > 0) { krh@35: /* FIXME: We ignore file requires for now. */ krh@35: if (pool[r->name] == '/') krh@35: continue; krh@21: u = array_add(unsatisfied, sizeof *u); krh@21: *u = r - (struct razor_property *) set->requires.data; krh@21: } krh@21: } krh@21: } krh@21: krh@21: void krh@21: razor_set_list_unsatisfied(struct razor_set *set) krh@21: { krh@21: struct array unsatisfied; krh@21: struct razor_property *requires, *r; krh@21: unsigned long *u, *end; krh@21: char *pool; krh@21: krh@21: array_init(&unsatisfied); krh@21: razor_set_validate(set, &unsatisfied); krh@21: krh@21: end = unsatisfied.data + unsatisfied.size; krh@21: requires = set->requires.data; krh@21: pool = set->string_pool.data; krh@21: krh@21: for (u = unsatisfied.data; u < end; u++) { krh@21: r = requires + *u; krh@21: printf("%s %s not satisfied\n", krh@21: &pool[r->name], &pool[r->version]); krh@21: } krh@21: krh@21: array_release(&unsatisfied); krh@21: } krh@21: krh@41: #define UPSTREAM_SOURCE 0x80000000ul krh@41: #define INDEX_MASK 0x00fffffful krh@41: krh@41: struct source { krh@41: struct razor_set *set; krh@41: unsigned long *requires_map; krh@41: unsigned long *provides_map; krh@41: }; krh@41: krh@41: static void krh@41: prepare_source(struct source *source, struct razor_set *set) krh@41: { krh@41: int count; krh@41: size_t size; krh@41: krh@41: source->set = set; krh@41: krh@41: count = set->requires.size / sizeof (struct razor_property); krh@41: size = count * sizeof *source->requires_map; krh@41: source->requires_map = zalloc(size); krh@41: krh@41: count = set->provides.size / sizeof (struct razor_property); krh@41: size = count * sizeof *source->provides_map; krh@41: source->provides_map = zalloc(size); krh@41: } krh@41: krh@33: static void krh@33: add_package(struct razor_importer *importer, krh@41: struct razor_package *package, struct source *source, krh@41: unsigned long flags) krh@33: { krh@33: char *pool; krh@33: unsigned long *r; krh@41: struct razor_package *p; krh@33: krh@41: pool = source->set->string_pool.data; krh@41: p = array_add(&importer->set->packages, sizeof *p); krh@41: p->name = razor_importer_tokenize(importer, &pool[package->name]); krh@41: p->name |= flags; krh@41: p->version = razor_importer_tokenize(importer, krh@41: &pool[package->version]); krh@41: p->requires = package->requires; krh@41: p->provides = package->provides; krh@33: krh@41: r = (unsigned long *) krh@41: source->set->requires_pool.data + package->requires; krh@41: while (*r != ~0) krh@41: source->requires_map[*r++] = 1; krh@41: krh@41: r = (unsigned long *) krh@41: source->set->provides_pool.data + package->provides; krh@41: while (*r != ~0) krh@41: source->provides_map[*r++] = 1; krh@41: } krh@41: krh@41: krh@41: /* Build the new package list sorted by merging the two package lists. krh@41: * Build new string pool as we go. (for now we just re-use that part of krh@41: * the importer). */ krh@41: static void krh@41: merge_packages(struct razor_importer *importer, krh@41: struct source *source1, struct source *source2, krh@41: struct array *packages) krh@41: { krh@41: struct razor_package *upstream_packages, *p, *s, *send; krh@41: char *spool, *upool; krh@41: unsigned long *u, *uend; krh@41: int cmp; krh@41: krh@41: upstream_packages = source2->set->packages.data; krh@41: krh@41: u = packages->data; krh@41: uend = packages->data + packages->size; krh@41: upool = source2->set->string_pool.data; krh@41: krh@41: s = source1->set->packages.data; krh@41: send = source1->set->packages.data + source1->set->packages.size; krh@41: spool = source1->set->string_pool.data; krh@41: krh@41: while (s < send) { krh@41: p = upstream_packages + *u; krh@41: krh@41: if (u < uend) krh@41: cmp = strcmp(&spool[s->name], &upool[p->name]); krh@41: if (u >= uend || cmp < 0) { krh@41: add_package(importer, s, source1, 0); krh@41: s++; krh@41: } else if (cmp == 0) { krh@41: add_package(importer, p, source2, UPSTREAM_SOURCE); krh@41: s++; krh@41: u++; krh@41: } else { krh@41: add_package(importer, p, source2, UPSTREAM_SOURCE); krh@41: u++; krh@41: } krh@41: } krh@41: } krh@41: krh@41: static unsigned long krh@41: add_property(struct razor_importer *importer, struct array *properties, krh@41: const char *name, const char *version) krh@41: { krh@41: struct razor_property *p; krh@41: krh@41: p = array_add(properties, sizeof *p); krh@41: p->name = razor_importer_tokenize(importer, name); krh@41: p->version = razor_importer_tokenize(importer, version); krh@41: krh@41: return p - (struct razor_property *) properties->data; krh@41: } krh@41: krh@41: static void krh@41: merge_properties(struct array *properties, krh@41: struct razor_importer *importer, krh@41: struct razor_set *set1, krh@41: struct array *properties1, krh@41: unsigned long *map1, krh@41: struct razor_set *set2, krh@41: struct array *properties2, krh@41: unsigned long *map2) krh@41: { krh@41: struct razor_property *p1, *p2; krh@41: int i, j, cmp, count1, count2; krh@41: char *pool1, *pool2; krh@41: krh@41: i = 0; krh@41: j = 0; krh@41: pool1 = set1->string_pool.data; krh@41: pool2 = set2->string_pool.data; krh@41: krh@41: count1 = properties1->size / sizeof *p1; krh@41: count2 = properties2->size / sizeof *p2; krh@41: while (i < count1 || j < count2) { krh@41: if (i < count1 && map1[i] == 0) { krh@41: i++; krh@41: continue; krh@41: } krh@41: if (j < count2 && map2[j] == 0) { krh@41: j++; krh@41: continue; krh@41: } krh@41: p1 = (struct razor_property *) properties1->data + i; krh@41: p2 = (struct razor_property *) properties2->data + j; krh@41: if (i < count1 && j < count2) krh@41: cmp = strcmp(&pool1[p1->name], &pool2[p2->name]); krh@41: else if (i < count1) krh@41: cmp = -1; krh@41: else krh@41: cmp = 1; krh@41: if (cmp == 0) krh@41: cmp = versioncmp(&pool1[p1->version], krh@41: &pool2[p2->version]); krh@41: if (cmp < 0) { krh@41: map1[i++] = add_property(importer, krh@41: properties, krh@41: &pool1[p1->name], krh@41: &pool1[p1->version]); krh@41: } else if (cmp > 0) { krh@41: map2[j++] = add_property(importer, krh@41: properties, krh@41: &pool2[p2->name], krh@41: &pool2[p2->version]); krh@41: } else { krh@41: map1[i++] = map2[j++] = add_property(importer, krh@41: properties, krh@41: &pool1[p1->name], krh@41: &pool1[p1->version]); krh@41: } krh@41: } krh@41: } krh@41: krh@41: static unsigned long krh@41: emit_properties(struct array *source_pool, unsigned long index, krh@41: unsigned long *map, struct array *pool) krh@41: { krh@41: unsigned long r, *p, *q; krh@41: krh@41: r = pool->size / sizeof *q; krh@41: p = (unsigned long *) source_pool->data + index; krh@41: while (*p != ~0) { krh@41: q = array_add(pool, sizeof *q); krh@41: *q = map[*p++]; krh@33: } krh@33: krh@41: q = array_add(pool, sizeof *q); krh@41: *q = ~0; krh@41: krh@41: return r; krh@41: } krh@41: krh@41: /* Rebuild property->packages maps. We can't just remap these, as a krh@41: * property may have lost or gained a number of packages. Allocate an krh@41: * array per property and loop through the packages and add them to krh@41: * the arrays for their properties. */ krh@41: static void krh@41: rebuild_package_lists(struct razor_set *set) krh@41: { krh@41: int requires_count, provides_count; krh@41: struct array *requires_pkgs, *provides_pkgs, *a; krh@41: struct razor_package *pkg, *pkg_end; krh@41: struct razor_property *prop, *prop_end; krh@41: unsigned long *r, *q, *rpool, *ppool; krh@41: krh@41: requires_count = set->requires.size / sizeof (struct razor_property); krh@41: provides_count = set->provides.size / sizeof (struct razor_property); krh@41: requires_pkgs = zalloc(requires_count * sizeof *requires_pkgs); krh@41: provides_pkgs = zalloc(provides_count * sizeof *provides_pkgs); krh@41: pkg_end = set->packages.data + set->packages.size; krh@41: rpool = set->requires_pool.data; krh@41: ppool = set->provides_pool.data; krh@41: krh@41: for (pkg = set->packages.data; pkg < pkg_end; pkg++) { krh@41: for (r = &rpool[pkg->requires]; *r != ~0; r++) { krh@41: q = array_add(&requires_pkgs[*r], sizeof *q); krh@41: *q = pkg - (struct razor_package *) set->packages.data; krh@41: } krh@41: for (r = &ppool[pkg->provides]; *r != ~0; r++) { krh@41: q = array_add(&provides_pkgs[*r], sizeof *q); krh@41: *q = pkg - (struct razor_package *) set->packages.data; krh@41: } krh@33: } krh@33: krh@41: prop_end = set->requires.data + set->requires.size; krh@41: a = requires_pkgs; krh@41: for (prop = set->requires.data; prop < prop_end; prop++, a++) { krh@41: prop->packages = add_to_property_pool(&set->requires_pool, a); krh@41: array_release(a); krh@41: } krh@41: free(requires_pkgs); krh@41: krh@41: prop_end = set->provides.data + set->provides.size; krh@41: a = provides_pkgs; krh@41: for (prop = set->provides.data; prop < prop_end; prop++, a++) { krh@41: prop->packages = add_to_property_pool(&set->provides_pool, a); krh@41: array_release(a); krh@41: } krh@41: free(provides_pkgs); krh@33: } krh@33: krh@33: /* Add packages from 'upstream' to 'set'. The packages to add are krh@33: * specified by the 'packages' array, which is a sorted list of krh@33: * package indexes. Returns a newly allocated package set. Does not krh@41: * enforce validity of the resulting package set. krh@41: * krh@41: * This looks more complicated than it is. An easy way to merge two krh@41: * package sets would be to just use a razor_importer, but that krh@41: * requires resorting, and is thus O(n log n). We can do this in a krh@41: * linear sweep, but it gets a little more complicated. krh@41: */ krh@33: struct razor_set * krh@33: razor_set_add(struct razor_set *set, struct razor_set *upstream, krh@33: struct array *packages) krh@33: { krh@41: struct razor_set *result; krh@33: struct razor_importer *importer; krh@41: struct razor_package *p, *pend; krh@41: struct source source, upstream_source; krh@33: krh@33: importer = razor_importer_new(); krh@33: krh@41: prepare_source(&upstream_source, upstream); krh@41: prepare_source(&source, set); krh@41: krh@41: merge_packages(importer, &source, &upstream_source, packages); krh@41: krh@41: /* As we built the package list, we filled out a bitvector of krh@41: * the properties that are referenced by the packages in the krh@41: * new set. Now we do a parallel loop through the properties krh@41: * and emit those marked in the bit vector to the new set. In krh@41: * the process, we update the bit vector to actually map from krh@41: * indices in the old property list to indices in the new krh@41: * property list for both sets. */ krh@41: krh@41: merge_properties(&importer->set->requires, importer, krh@41: set, &set->requires, source.requires_map, krh@41: upstream, &upstream->requires, krh@41: upstream_source.requires_map); krh@41: merge_properties(&importer->set->provides, importer, krh@41: set, &set->provides, source.provides_map, krh@41: upstream, &upstream->provides, krh@41: upstream_source.provides_map); krh@41: krh@41: /* Now we loop through the packages again and emit the krh@41: * property lists, remapped to point to the new properties. */ krh@41: krh@41: pend = importer->set->packages.data + importer->set->packages.size; krh@41: for (p = importer->set->packages.data; p < pend; p++) { krh@41: struct source *src; krh@41: krh@41: if (p->name & UPSTREAM_SOURCE) krh@41: src = &upstream_source; krh@41: else krh@41: src = &source; krh@41: krh@41: p->requires = emit_properties(&src->set->requires_pool, krh@41: p->requires, krh@41: src->requires_map, krh@41: &importer->set->requires_pool); krh@41: p->provides = emit_properties(&src->set->provides_pool, krh@41: p->provides, krh@41: src->provides_map, krh@41: &importer->set->provides_pool); krh@41: p->name &= INDEX_MASK; krh@33: } krh@33: krh@41: rebuild_package_lists(importer->set); krh@41: krh@41: result = importer->set; krh@41: array_release(&importer->buckets); krh@41: free(importer); krh@41: krh@41: return result; krh@33: } krh@33: krh@37: void krh@37: razor_set_satisfy(struct razor_set *set, struct array *unsatisfied, krh@37: struct razor_set *upstream, struct array *list) krh@37: { krh@37: struct razor_property *requires, *r; krh@37: struct razor_property *p, *pend; krh@39: unsigned long *u, *end, *pkg, *package_pool; krh@37: char *pool, *upool; krh@37: krh@37: end = unsatisfied->data + unsatisfied->size; krh@37: requires = set->requires.data; krh@37: pool = set->string_pool.data; krh@37: krh@37: p = upstream->provides.data; krh@37: pend = upstream->provides.data + upstream->provides.size; krh@37: upool = upstream->string_pool.data; krh@39: package_pool = upstream->package_pool.data; krh@37: krh@37: for (u = unsatisfied->data; u < end; u++) { krh@37: r = requires + *u; krh@37: krh@37: while (p < pend && strcmp(&pool[r->name], &upool[p->name]) > 0) krh@37: p++; krh@37: /* If there is more than one version of a provides, krh@37: * seek to the end for the highest version. */ krh@37: while (p + 1 < pend && p->name == (p + 1)->name) krh@37: p++; krh@37: krh@37: if (p == pend || krh@37: strcmp(&pool[r->name], &upool[p->name]) != 0 || krh@37: versioncmp(&pool[r->version], &upool[p->version]) > 0) { krh@37: /* Do we need to track unsatisfiable requires krh@37: * as we go, or should we just do a krh@37: * razor_set_validate() at the end? */ krh@37: } else { krh@37: pkg = array_add(list, sizeof *pkg); krh@37: /* We just pull in the first package that provides */ krh@39: *pkg = package_pool[p->packages]; krh@37: } krh@37: } krh@37: } krh@37: krh@38: static void krh@38: find_packages(struct razor_set *set, krh@38: int count, const char **packages, struct array *list) krh@38: { krh@38: struct razor_package *p; krh@38: unsigned long *r; krh@38: int i; krh@38: krh@38: /* FIXME: Sort the packages. */ krh@38: for (i = 0; i < count; i++) { krh@38: p = razor_set_get_package(set, packages[i]); krh@38: r = array_add(list, sizeof *r); krh@38: *r = p - (struct razor_package *) set->packages.data; krh@38: } krh@38: } krh@38: krh@38: static void krh@38: find_all_packages(struct razor_set *set, krh@38: struct razor_set *upstream, struct array *list) krh@38: { krh@38: struct razor_package *p, *u, *pend, *uend; krh@38: unsigned long *r; krh@38: char *pool, *upool; krh@38: krh@38: pend = set->packages.data + set->packages.size; krh@38: pool = set->string_pool.data; krh@38: u = upstream->packages.data; krh@38: uend = upstream->packages.data + upstream->packages.size; krh@38: upool = upstream->string_pool.data; krh@38: krh@38: for (p = set->packages.data; p < pend; p++) { krh@38: while (u < uend && strcmp(&pool[p->name], &upool[u->name]) > 0) krh@38: u++; krh@38: if (strcmp(&pool[p->name], &upool[u->name]) == 0) { krh@38: r = array_add(list, sizeof *r); krh@38: *r = u - (struct razor_package *) upstream->packages.data; krh@38: } krh@38: } krh@38: } krh@38: krh@33: struct razor_set * krh@33: razor_set_update(struct razor_set *set, struct razor_set *upstream, krh@33: int count, const char **packages) krh@33: { krh@37: struct razor_set *new; krh@43: struct razor_package *upackages; krh@37: struct array list, unsatisfied; krh@37: char *pool; krh@38: unsigned long *u, *end; krh@38: int total = 0; krh@33: krh@33: array_init(&list); krh@38: if (count > 0) krh@38: find_packages(upstream, count, packages, &list); krh@38: else krh@38: find_all_packages(set, upstream, &list); krh@33: krh@37: end = list.data + list.size; krh@37: upackages = upstream->packages.data; krh@37: pool = upstream->string_pool.data; krh@38: total += list.size / sizeof *u; krh@37: krh@37: while (list.size > 0) { krh@37: new = razor_set_add(set, upstream, &list); krh@37: array_release(&list); krh@37: razor_set_destroy(set); krh@37: set = new; krh@37: krh@37: array_init(&unsatisfied); krh@37: razor_set_validate(new, &unsatisfied); krh@37: array_init(&list); krh@37: razor_set_satisfy(new, &unsatisfied, upstream, &list); krh@37: array_release(&unsatisfied); krh@37: krh@37: end = list.data + list.size; krh@37: upackages = upstream->packages.data; krh@37: pool = upstream->string_pool.data; krh@38: total += list.size / sizeof *u; krh@37: } krh@37: krh@37: array_release(&list); krh@37: krh@37: return set; krh@33: } krh@33: krh@44: /* The diff order matters. We should sort the packages so that a krh@44: * REMOVE of a package comes before the INSTALL, and so that all krh@44: * requires for a package have been installed before the package. krh@44: **/ krh@44: krh@44: void krh@44: razor_set_diff(struct razor_set *set, struct razor_set *upstream, krh@44: razor_package_callback_t callback, void *data) krh@44: { krh@44: struct razor_package *p, *pend, *u, *uend; krh@44: char *ppool, *upool; krh@44: int res = 0; krh@44: krh@44: p = set->packages.data; krh@44: pend = set->packages.data + set->packages.size; krh@44: ppool = set->string_pool.data; krh@44: krh@44: u = upstream->packages.data; krh@44: uend = upstream->packages.data + upstream->packages.size; krh@44: upool = upstream->string_pool.data; krh@44: krh@44: while (p < pend || u < uend) { krh@44: if (p < pend && u < uend) { krh@44: res = strcmp(&ppool[p->name], &upool[u->name]); krh@44: if (res == 0) krh@44: res = versioncmp(&ppool[p->version], krh@44: &upool[u->version]); krh@44: } krh@44: krh@44: if (u == uend || res < 0) { krh@44: callback(&ppool[p->name], &ppool[p->version], krh@44: NULL, data); krh@44: p++; krh@44: continue; krh@44: } else if (p == pend || res > 0) { krh@44: callback(&upool[u->name], NULL, &upool[u->version], krh@44: data); krh@44: u++; krh@44: continue; krh@44: } else { krh@44: p++; krh@44: u++; krh@44: } krh@44: } krh@44: }