razor.c
author Kristian H?gsberg <krh@redhat.com>
Thu Sep 20 19:28:09 2007 -0400 (2007-09-20)
changeset 39 5fe9c9286cd0
parent 38 88f3ec190a3f
child 41 7eea400e19db
permissions -rw-r--r--
Split the property pool into three pools; requires, provides and packages.

This simplifies the remapping code a lot and reduces memory pressure
during import a bit.
krh@15
     1
#define _GNU_SOURCE
krh@15
     2
krh@0
     3
#include <stdlib.h>
krh@19
     4
#include <stddef.h>
krh@0
     5
#include <stdio.h>
krh@0
     6
#include <string.h>
krh@0
     7
#include <sys/types.h>
krh@0
     8
#include <sys/stat.h>
krh@0
     9
#include <sys/mman.h>
krh@0
    10
#include <unistd.h>
krh@0
    11
#include <fcntl.h>
krh@15
    12
#include <errno.h>
krh@35
    13
#include <ctype.h>
krh@0
    14
krh@27
    15
#include "razor.h"
krh@6
    16
krh@30
    17
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
krh@30
    18
krh@30
    19
struct array {
krh@30
    20
	void *data;
krh@30
    21
	int size, alloc;
krh@30
    22
};
krh@30
    23
krh@30
    24
struct razor_set_section {
krh@30
    25
	unsigned int type;
krh@30
    26
	unsigned int offset;
krh@30
    27
	unsigned int size;
krh@30
    28
};
krh@30
    29
krh@30
    30
struct razor_set_header {
krh@30
    31
	unsigned int magic;
krh@30
    32
	unsigned int version;
krh@30
    33
	struct razor_set_section sections[0];
krh@30
    34
};
krh@30
    35
krh@30
    36
#define RAZOR_MAGIC 0x7a7a7a7a
krh@30
    37
#define RAZOR_VERSION 1
krh@30
    38
krh@30
    39
#define RAZOR_PACKAGES 0
krh@30
    40
#define RAZOR_REQUIRES 1
krh@30
    41
#define RAZOR_PROVIDES 2
krh@30
    42
#define RAZOR_STRING_POOL 3
krh@39
    43
#define RAZOR_PACKAGE_POOL 4
krh@39
    44
#define RAZOR_REQUIRES_POOL 5
krh@39
    45
#define RAZOR_PROVIDES_POOL 6
krh@30
    46
krh@30
    47
struct razor_package {
krh@30
    48
	unsigned long name;
krh@30
    49
	unsigned long version;
krh@30
    50
	unsigned long requires;
krh@30
    51
	unsigned long provides;
krh@30
    52
};
krh@30
    53
krh@30
    54
struct razor_property {
krh@30
    55
	unsigned long name;
krh@30
    56
	unsigned long version;
krh@30
    57
	unsigned long packages;
krh@30
    58
};
krh@30
    59
krh@30
    60
struct razor_set {
krh@30
    61
	struct array string_pool;
krh@30
    62
 	struct array packages;
krh@39
    63
	struct array package_pool;
krh@30
    64
 	struct array requires;
krh@30
    65
 	struct array provides;
krh@39
    66
 	struct array requires_pool;
krh@39
    67
 	struct array provides_pool;
krh@30
    68
	struct razor_set_header *header;
krh@30
    69
};
krh@30
    70
krh@30
    71
struct import_property_context {
krh@30
    72
	struct array *all;
krh@30
    73
	struct array package;
krh@30
    74
};
krh@30
    75
krh@30
    76
struct razor_importer {
krh@30
    77
	struct razor_set *set;
krh@32
    78
	struct array buckets;
krh@30
    79
	struct import_property_context requires;
krh@30
    80
	struct import_property_context provides;
krh@30
    81
	struct razor_package *package;
krh@30
    82
	unsigned long *requires_map;
krh@30
    83
	unsigned long *provides_map;
krh@30
    84
};
krh@30
    85
krh@13
    86
static void
krh@13
    87
array_init(struct array *array)
krh@13
    88
{
krh@13
    89
	memset(array, 0, sizeof *array);
krh@13
    90
}
krh@13
    91
krh@13
    92
static void
krh@13
    93
array_release(struct array *array)
krh@13
    94
{
krh@13
    95
	free(array->data);
krh@13
    96
}
krh@13
    97
krh@6
    98
static void *
krh@6
    99
array_add(struct array *array, int size)
krh@6
   100
{
krh@6
   101
	int alloc;
krh@6
   102
	void *data, *p;
krh@6
   103
krh@6
   104
	if (array->alloc > 0)
krh@6
   105
		alloc = array->alloc;
krh@6
   106
	else
krh@10
   107
		alloc = 16;
krh@6
   108
krh@6
   109
	while (alloc < array->size + size)
krh@6
   110
		alloc *= 2;
krh@6
   111
krh@6
   112
	if (array->alloc < alloc) {
krh@6
   113
		data = realloc(array->data, alloc);
krh@6
   114
		if (data == NULL)
krh@6
   115
			return 0;
krh@6
   116
		array->data = data;
krh@6
   117
		array->alloc = alloc;
krh@6
   118
	}
krh@6
   119
krh@6
   120
	p = array->data + array->size;
krh@6
   121
	array->size += size;
krh@6
   122
krh@6
   123
	return p;
krh@6
   124
}
krh@6
   125
krh@0
   126
static int
krh@0
   127
write_to_fd(int fd, void *p, size_t size)
krh@0
   128
{
krh@0
   129
	int rest, len;
krh@0
   130
krh@0
   131
	rest = size;
krh@0
   132
	while (rest > 0) {
krh@0
   133
		len = write(fd, p, rest);
krh@0
   134
		if (len < 0)
krh@0
   135
			return -1;
krh@0
   136
		rest -= len;
krh@0
   137
	}
krh@0
   138
krh@0
   139
	return 0;
krh@0
   140
}
krh@0
   141
krh@0
   142
static void *
krh@0
   143
zalloc(size_t size)
krh@0
   144
{
krh@0
   145
	void *p;
krh@0
   146
krh@0
   147
	p = malloc(size);
krh@0
   148
	memset(p, 0, size);
krh@0
   149
krh@0
   150
	return p;
krh@0
   151
}
krh@0
   152
krh@19
   153
struct razor_set_section razor_sections[] = {
krh@19
   154
	{ RAZOR_PACKAGES,	offsetof(struct razor_set, packages) },
krh@19
   155
	{ RAZOR_REQUIRES,	offsetof(struct razor_set, requires) },
krh@19
   156
	{ RAZOR_PROVIDES,	offsetof(struct razor_set, provides) },
krh@19
   157
	{ RAZOR_STRING_POOL,	offsetof(struct razor_set, string_pool) },
krh@39
   158
	{ RAZOR_PACKAGE_POOL,	offsetof(struct razor_set, package_pool) },
krh@39
   159
	{ RAZOR_REQUIRES_POOL,	offsetof(struct razor_set, requires_pool) },
krh@39
   160
	{ RAZOR_PROVIDES_POOL,	offsetof(struct razor_set, provides_pool) },
krh@19
   161
};
krh@19
   162
krh@4
   163
struct razor_set *
krh@4
   164
razor_set_create(void)
krh@0
   165
{
krh@18
   166
	return zalloc(sizeof(struct razor_set));
krh@0
   167
}
krh@0
   168
krh@4
   169
struct razor_set *
krh@4
   170
razor_set_open(const char *filename)
krh@0
   171
{
krh@4
   172
	struct razor_set *set;
krh@19
   173
	struct razor_set_section *s;
krh@0
   174
	struct stat stat;
krh@19
   175
	struct array *array;
krh@19
   176
	int fd;
krh@0
   177
krh@4
   178
	set = zalloc(sizeof *set);
krh@0
   179
	fd = open(filename, O_RDONLY);
krh@0
   180
	if (fstat(fd, &stat) < 0)
krh@0
   181
		return NULL;
krh@4
   182
	set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
krh@4
   183
	if (set->header == MAP_FAILED) {
krh@4
   184
		free(set);
krh@0
   185
		return NULL;
krh@0
   186
	}
krh@0
   187
krh@19
   188
	for (s = set->header->sections; ~s->type; s++) {
krh@19
   189
		if (s->type >= ARRAY_SIZE(razor_sections))
krh@19
   190
			continue;
krh@19
   191
		if (s->type != razor_sections[s->type].type)
krh@19
   192
			continue;
krh@19
   193
		array = (void *) set + razor_sections[s->type].offset;
krh@19
   194
		array->data = (void *) set->header + s->offset;
krh@19
   195
		array->size = s->size;
krh@19
   196
		array->alloc = s->size;
krh@0
   197
	}
krh@0
   198
	close(fd);
krh@0
   199
krh@4
   200
	return set;
krh@0
   201
}
krh@0
   202
krh@0
   203
void
krh@4
   204
razor_set_destroy(struct razor_set *set)
krh@0
   205
{
krh@0
   206
	unsigned int size;
krh@19
   207
	struct array *a;
krh@0
   208
	int i;
krh@0
   209
krh@4
   210
	if (set->header) {
krh@4
   211
		for (i = 0; set->header->sections[i].type; i++)
krh@0
   212
			;
krh@4
   213
		size = set->header->sections[i].type;
krh@4
   214
		munmap(set->header, size);
krh@0
   215
	} else {
krh@19
   216
		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@19
   217
			a = (void *) set + razor_sections[i].offset;
krh@19
   218
			free(a->data);
krh@19
   219
		}
krh@0
   220
	}
krh@0
   221
krh@4
   222
	free(set);
krh@0
   223
}
krh@0
   224
krh@0
   225
static int
krh@4
   226
razor_set_write(struct razor_set *set, const char *filename)
krh@0
   227
{
krh@0
   228
	char data[4096];
krh@4
   229
	struct razor_set_header *header = (struct razor_set_header *) data;
krh@19
   230
	struct array *a;
krh@17
   231
	unsigned long offset;
krh@17
   232
	int i, fd;
krh@0
   233
krh@0
   234
	memset(data, 0, sizeof data);
krh@4
   235
	header->magic = RAZOR_MAGIC;
krh@4
   236
	header->version = RAZOR_VERSION;
krh@17
   237
	offset = sizeof data;
krh@0
   238
krh@19
   239
	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@19
   240
		if (razor_sections[i].type != i)
krh@19
   241
			continue;
krh@19
   242
		a = (void *) set + razor_sections[i].offset;
krh@19
   243
		header->sections[i].type = i;
krh@17
   244
		header->sections[i].offset = offset;
krh@19
   245
		header->sections[i].size = a->size;
krh@19
   246
		offset += (a->size + 4095) & ~4095;
krh@17
   247
	}
krh@0
   248
krh@19
   249
	header->sections[i].type = ~0;
krh@17
   250
	header->sections[i].offset = 0;
krh@17
   251
	header->sections[i].size = 0;
krh@10
   252
krh@0
   253
	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
krh@0
   254
	if (fd < 0)
krh@0
   255
		return -1;
krh@0
   256
krh@0
   257
	write_to_fd(fd, data, sizeof data);
krh@19
   258
	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@19
   259
		if (razor_sections[i].type != i)
krh@19
   260
			continue;
krh@19
   261
		a = (void *) set + razor_sections[i].offset;
krh@19
   262
		write_to_fd(fd, a->data, (a->size + 4095) & ~4095);
krh@19
   263
	}
krh@17
   264
krh@17
   265
	close(fd);
krh@0
   266
krh@0
   267
	return 0;
krh@0
   268
}
krh@0
   269
krh@0
   270
static unsigned int
krh@0
   271
hash_string(const char *key)
krh@0
   272
{
krh@0
   273
	const char *p;
krh@0
   274
	unsigned int hash = 0;
krh@0
   275
krh@0
   276
	for (p = key; *p; p++)
krh@9
   277
		hash = (hash * 617) ^ *p;
krh@0
   278
krh@0
   279
	return hash;
krh@0
   280
}
krh@0
   281
krh@32
   282
static unsigned long
krh@32
   283
razor_importer_lookup(struct razor_importer *importer, const char *key)
krh@0
   284
{
krh@6
   285
	unsigned int mask, start, i;
krh@6
   286
	unsigned long *b;
krh@6
   287
	char *pool;
krh@0
   288
krh@32
   289
	pool = importer->set->string_pool.data;
krh@32
   290
	mask = importer->buckets.alloc - 1;
krh@6
   291
	start = hash_string(key) * sizeof(unsigned long);
krh@0
   292
krh@32
   293
	for (i = 0; i < importer->buckets.alloc; i += sizeof *b) {
krh@32
   294
		b = importer->buckets.data + ((start + i) & mask);
krh@6
   295
krh@6
   296
		if (*b == 0)
krh@0
   297
			return 0;
krh@0
   298
krh@6
   299
		if (strcmp(key, &pool[*b]) == 0)
krh@6
   300
			return *b;
krh@6
   301
	}
krh@0
   302
krh@0
   303
	return 0;
krh@0
   304
}
krh@0
   305
krh@0
   306
static unsigned long
krh@4
   307
add_to_string_pool(struct razor_set *set, const char *key)
krh@0
   308
{
krh@6
   309
	int len;
krh@6
   310
	char *p;
krh@0
   311
krh@0
   312
	len = strlen(key) + 1;
krh@6
   313
	p = array_add(&set->string_pool, len);
krh@6
   314
	memcpy(p, key, len);
krh@0
   315
krh@6
   316
	return p - (char *) set->string_pool.data;
krh@0
   317
}
krh@0
   318
krh@10
   319
static unsigned long
krh@39
   320
add_to_property_pool(struct array *pool, struct array *properties)
krh@10
   321
{
krh@10
   322
	unsigned long  *p;
krh@10
   323
krh@10
   324
	p = array_add(properties, sizeof *p);
krh@18
   325
	*p = ~0ul;
krh@39
   326
	p = array_add(pool, properties->size);
krh@10
   327
	memcpy(p, properties->data, properties->size);
krh@10
   328
krh@39
   329
	return p - (unsigned long *) pool->data;
krh@10
   330
}
krh@10
   331
krh@0
   332
static void
krh@32
   333
do_insert(struct razor_importer *importer, unsigned long value)
krh@0
   334
{
krh@6
   335
	unsigned int mask, start, i;
krh@6
   336
	unsigned long *b;
krh@0
   337
	const char *key;
krh@0
   338
krh@32
   339
	key = (char *) importer->set->string_pool.data + value;
krh@32
   340
	mask = importer->buckets.alloc - 1;
krh@6
   341
	start = hash_string(key) * sizeof(unsigned long);
krh@6
   342
krh@32
   343
	for (i = 0; i < importer->buckets.alloc; i += sizeof *b) {
krh@32
   344
		b = importer->buckets.data + ((start + i) & mask);
krh@6
   345
		if (*b == 0) {
krh@6
   346
			*b = value;
krh@0
   347
			break;
krh@0
   348
		}
krh@6
   349
	}
krh@0
   350
}
krh@0
   351
krh@32
   352
static unsigned long
krh@32
   353
razor_importer_insert(struct razor_importer *importer, const char *key)
krh@0
   354
{
krh@6
   355
	unsigned long value, *buckets, *b, *end;
krh@6
   356
	int alloc;
krh@0
   357
krh@32
   358
	alloc = importer->buckets.alloc;
krh@32
   359
	array_add(&importer->buckets, 4 * sizeof *buckets);
krh@32
   360
	if (alloc != importer->buckets.alloc) {
krh@32
   361
		end = importer->buckets.data + alloc;
krh@32
   362
		memset(end, 0, importer->buckets.alloc - alloc);
krh@32
   363
		for (b = importer->buckets.data; b < end; b++) {
krh@6
   364
			value = *b;
krh@6
   365
			if (value != 0) {
krh@6
   366
				*b = 0;
krh@32
   367
				do_insert(importer, value);
krh@6
   368
			}
krh@0
   369
		}
krh@0
   370
	}
krh@0
   371
krh@32
   372
	value = add_to_string_pool(importer->set, key);
krh@32
   373
	do_insert (importer, value);
krh@0
   374
krh@0
   375
	return value;
krh@0
   376
}
krh@0
   377
krh@30
   378
static unsigned long
krh@32
   379
razor_importer_tokenize(struct razor_importer *importer, const char *string)
krh@0
   380
{
krh@0
   381
	unsigned long token;
krh@0
   382
krh@13
   383
	if (string == NULL)
krh@32
   384
		return razor_importer_tokenize(importer, "");
krh@13
   385
krh@32
   386
	token = razor_importer_lookup(importer, string);
krh@0
   387
	if (token != 0)
krh@0
   388
		return token;
krh@0
   389
krh@32
   390
	return razor_importer_insert(importer, string);
krh@0
   391
}
krh@0
   392
krh@27
   393
void
krh@30
   394
razor_importer_begin_package(struct razor_importer *importer,
krh@30
   395
			     const char *name, const char *version)
krh@13
   396
{
krh@25
   397
	struct razor_package *p;
krh@13
   398
krh@30
   399
	p = array_add(&importer->set->packages, sizeof *p);
krh@32
   400
	p->name = razor_importer_tokenize(importer, name);
krh@32
   401
	p->version = razor_importer_tokenize(importer, version);
krh@13
   402
krh@30
   403
	importer->package = p;
krh@30
   404
	array_init(&importer->requires.package);
krh@30
   405
	array_init(&importer->provides.package);
krh@13
   406
}
krh@13
   407
krh@13
   408
void
krh@30
   409
razor_importer_finish_package(struct razor_importer *importer)
krh@13
   410
{
krh@25
   411
	struct razor_package *p;
krh@13
   412
krh@30
   413
	p = importer->package;
krh@39
   414
	p->requires = add_to_property_pool(&importer->set->requires_pool,
krh@30
   415
					   &importer->requires.package);
krh@39
   416
	p->provides = add_to_property_pool(&importer->set->provides_pool,
krh@30
   417
					   &importer->provides.package);
krh@13
   418
krh@30
   419
	array_release(&importer->requires.package);
krh@30
   420
	array_release(&importer->provides.package);
krh@13
   421
}
krh@13
   422
krh@30
   423
static void
krh@30
   424
razor_importer_add_property(struct razor_importer *importer,
krh@13
   425
			    struct import_property_context *pctx,
krh@13
   426
			    const char *name, const char *version)
krh@13
   427
{
krh@25
   428
	struct razor_property *p;
krh@13
   429
	unsigned long *r;
krh@13
   430
krh@25
   431
	p = array_add(pctx->all, sizeof *p);
krh@32
   432
	p->name = razor_importer_tokenize(importer, name);
krh@32
   433
	p->version = razor_importer_tokenize(importer, version);
krh@30
   434
	p->packages = importer->package -
krh@30
   435
		(struct razor_package *) importer->set->packages.data;
krh@13
   436
krh@13
   437
	r = array_add(&pctx->package, sizeof *r);
krh@25
   438
	*r = p - (struct razor_property *) pctx->all->data;
krh@13
   439
}
krh@13
   440
krh@27
   441
void
krh@30
   442
razor_importer_add_requires(struct razor_importer *importer,
krh@30
   443
			    const char *name, const char *version)
krh@9
   444
{
krh@30
   445
	razor_importer_add_property(importer,
krh@30
   446
				    &importer->requires, name, version);
krh@30
   447
}
krh@30
   448
krh@30
   449
void
krh@30
   450
razor_importer_add_provides(struct razor_importer *importer,
krh@30
   451
			    const char *name, const char *version)
krh@30
   452
{
krh@30
   453
	razor_importer_add_property(importer,
krh@30
   454
				    &importer->provides, name, version);
krh@30
   455
}
krh@30
   456
krh@30
   457
struct razor_importer *
krh@30
   458
razor_importer_new(void)
krh@30
   459
{
krh@30
   460
	struct razor_importer *importer;
krh@30
   461
krh@30
   462
	importer = zalloc(sizeof *importer);
krh@30
   463
	importer->set = razor_set_create();
krh@30
   464
	importer->requires.all = &importer->set->requires;
krh@30
   465
	importer->provides.all = &importer->set->provides;
krh@30
   466
krh@30
   467
	return importer;
krh@9
   468
}
krh@9
   469
krh@22
   470
typedef int (*compare_with_data_func_t)(const void *p1,
krh@22
   471
					const void *p,
krh@22
   472
					void *data);
krh@22
   473
krh@25
   474
struct qsort_context {
krh@25
   475
	size_t size;
krh@25
   476
	compare_with_data_func_t compare;
krh@25
   477
	void *data;
krh@25
   478
};
krh@25
   479
krh@22
   480
static void
krh@22
   481
qsort_swap(void *p1, void *p2, size_t size)
krh@22
   482
{
krh@22
   483
	char buffer[size];
krh@22
   484
krh@22
   485
	memcpy(buffer, p1, size);
krh@22
   486
	memcpy(p1, p2, size);
krh@22
   487
	memcpy(p2, buffer, size);
krh@22
   488
}
krh@22
   489
krh@25
   490
static void
krh@25
   491
__qsort_with_data(void *base, size_t nelem, unsigned long *map,
krh@25
   492
		  struct qsort_context *ctx)
krh@22
   493
{
krh@22
   494
	void *p, *start, *end, *pivot;
krh@25
   495
	unsigned long *mp, *mstart, *mend, tmp;
krh@22
   496
	int left, right, result;
krh@25
   497
	size_t size = ctx->size;
krh@22
   498
krh@22
   499
	p = base;
krh@22
   500
	start = base;
krh@22
   501
	end = base + nelem * size;
krh@25
   502
	mp = map;
krh@25
   503
	mstart = map;
krh@25
   504
	mend = map + nelem;
krh@22
   505
	pivot = base + (random() % nelem) * size;
krh@25
   506
krh@22
   507
	while (p < end) {
krh@25
   508
		result = ctx->compare(p, pivot, ctx->data);
krh@22
   509
		if (result < 0) {
krh@22
   510
			qsort_swap(p, start, size);
krh@25
   511
			tmp = *mp;
krh@25
   512
			*mp = *mstart;
krh@25
   513
			*mstart = tmp;
krh@22
   514
			if (start == pivot)
krh@22
   515
				pivot = p;
krh@22
   516
			start += size;
krh@25
   517
			mstart++;
krh@22
   518
			p += size;
krh@29
   519
			mp++;
krh@22
   520
		} else if (result == 0) {
krh@22
   521
			p += size;
krh@25
   522
			mp++;
krh@22
   523
		} else {
krh@22
   524
 			end -= size;
krh@25
   525
			mend--;
krh@22
   526
			qsort_swap(p, end, size);
krh@25
   527
			tmp = *mp;
krh@29
   528
			*mp = *mend;
krh@29
   529
			*mend = tmp;
krh@22
   530
			if (end == pivot)
krh@22
   531
				pivot = p;
krh@22
   532
		}
krh@22
   533
	}
krh@22
   534
krh@22
   535
	left = (start - base) / size;
krh@22
   536
	right = (base + nelem * size - end) / size;
krh@22
   537
	if (left > 1)
krh@25
   538
		__qsort_with_data(base, left, map, ctx);
krh@22
   539
	if (right > 1)
krh@25
   540
		__qsort_with_data(end, right, mend, ctx);
krh@25
   541
}
krh@25
   542
krh@25
   543
unsigned long *
krh@25
   544
qsort_with_data(void *base, size_t nelem, size_t size,
krh@25
   545
		compare_with_data_func_t compare, void *data)
krh@25
   546
{
krh@25
   547
	struct qsort_context ctx;
krh@25
   548
	unsigned long *map;
krh@25
   549
	int i;
krh@25
   550
krh@25
   551
	ctx.size = size;
krh@25
   552
	ctx.compare = compare;
krh@25
   553
	ctx.data = data;
krh@25
   554
krh@25
   555
	map = malloc(nelem * sizeof (unsigned long));
krh@25
   556
	for (i = 0; i < nelem; i++)
krh@25
   557
		map[i] = i;
krh@25
   558
krh@25
   559
	__qsort_with_data(base, nelem, map, &ctx);
krh@25
   560
krh@25
   561
	return map;
krh@22
   562
}
krh@9
   563
krh@9
   564
static int
krh@35
   565
versioncmp(const char *s1, const char *s2)
krh@35
   566
{
krh@35
   567
	const char *p1, *p2;
krh@35
   568
	long n1, n2;
krh@35
   569
	int res;
krh@35
   570
krh@35
   571
	n1 = strtol(s1, (char **) &p1, 0);
krh@35
   572
	n2 = strtol(s2, (char **) &p2, 0);
krh@35
   573
krh@35
   574
	/* Epoch; if one but not the other has an epoch set, default
krh@35
   575
	 * the epoch-less version to 0. */
krh@35
   576
	res = (*p1 == ':') - (*p2 == ':');
krh@35
   577
	if (res < 0) {
krh@35
   578
		n1 = 0;
krh@35
   579
		p1 = s1;
krh@35
   580
		p2++;
krh@35
   581
	} else if (res > 0) {
krh@35
   582
		p1++;
krh@35
   583
		n2 = 0;
krh@35
   584
		p2 = s2;
krh@35
   585
	}
krh@35
   586
krh@35
   587
	if (n1 != n2)
krh@35
   588
		return n1 - n2;
krh@35
   589
	while (*p1 && *p2) {
krh@35
   590
		if (*p1 != *p2)
krh@35
   591
			return *p1 - *p2;
krh@35
   592
		p1++;
krh@35
   593
		p2++;
krh@35
   594
		if (isdigit(*p1) && isdigit(*p2))
krh@35
   595
			return versioncmp(p1, p2);
krh@35
   596
	}
krh@35
   597
krh@35
   598
	return *p1 - *p2;
krh@35
   599
}
krh@35
   600
krh@35
   601
krh@35
   602
static int
krh@22
   603
compare_packages(const void *p1, const void *p2, void *data)
krh@9
   604
{
krh@25
   605
	const struct razor_package *pkg1 = p1, *pkg2 = p2;
krh@22
   606
	struct razor_set *set = data;
krh@22
   607
	char *pool = set->string_pool.data;
krh@9
   608
krh@23
   609
	if (pkg1->name == pkg2->name)
krh@35
   610
		return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
krh@23
   611
	else
krh@23
   612
		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
krh@9
   613
}
krh@9
   614
krh@9
   615
static int
krh@22
   616
compare_properties(const void *p1, const void *p2, void *data)
krh@9
   617
{
krh@25
   618
	const struct razor_property *prop1 = p1, *prop2 = p2;
krh@22
   619
	struct razor_set *set = data;
krh@22
   620
	char *pool = set->string_pool.data;
krh@9
   621
krh@23
   622
	if (prop1->name == prop2->name)
krh@35
   623
		return versioncmp(&pool[prop1->version], &pool[prop2->version]);
krh@12
   624
	else
krh@23
   625
		return strcmp(&pool[prop1->name], &pool[prop2->name]);
krh@9
   626
}
krh@9
   627
krh@10
   628
static unsigned long *
krh@25
   629
uniqueify_properties(struct razor_set *set, struct array *properties)
krh@9
   630
{
krh@25
   631
	struct razor_property *rp, *up, *rp_end;
krh@18
   632
	struct array *pkgs, *p;
krh@25
   633
	unsigned long *map, *rmap, *r;
krh@18
   634
	int i, count, unique;
krh@9
   635
krh@25
   636
	count = properties->size / sizeof(struct razor_property);
krh@25
   637
	map = qsort_with_data(properties->data,
krh@25
   638
			      count,
krh@25
   639
			      sizeof(struct razor_property),
krh@25
   640
			      compare_properties,
krh@25
   641
			      set);
krh@9
   642
krh@25
   643
	rp_end = properties->data + properties->size;
krh@25
   644
	rmap = malloc(count * sizeof *map);
krh@25
   645
	pkgs = zalloc(count * sizeof *pkgs);
krh@25
   646
	for (rp = properties->data, up = rp, i = 0; rp < rp_end; rp++, i++) {
krh@25
   647
		if (rp->name != up->name || rp->version != up->version) {
krh@25
   648
			up++;
krh@25
   649
			up->name = rp->name;
krh@25
   650
			up->version = rp->version;
krh@10
   651
		}
krh@25
   652
krh@25
   653
		unique = up - (struct razor_property *) properties->data;
krh@25
   654
		rmap[map[i]] = unique;
krh@25
   655
		r = array_add(&pkgs[unique], sizeof *r);
krh@25
   656
		*r = rp->packages;
krh@10
   657
	}
krh@25
   658
	free(map);
krh@9
   659
krh@25
   660
	up++;
krh@25
   661
	properties->size = (void *) up - properties->data;
krh@25
   662
	rp_end = up;
krh@25
   663
	for (rp = properties->data, p = pkgs; rp < rp_end; rp++, p++) {
krh@39
   664
		rp->packages = add_to_property_pool(&set->package_pool, p);
krh@25
   665
		array_release(p);
krh@18
   666
	}
krh@18
   667
krh@18
   668
	free(pkgs);
krh@18
   669
krh@25
   670
	return rmap;
krh@10
   671
}
krh@10
   672
krh@10
   673
static void
krh@39
   674
remap_links(struct array *links, unsigned long *map)
krh@10
   675
{
krh@39
   676
	unsigned long *p, *end;
krh@10
   677
krh@39
   678
	end = links->data + links->size;
krh@39
   679
	for (p = links->data; p < end; p++)
krh@39
   680
		if (*p != ~0)
krh@39
   681
			*p = map[*p];
krh@9
   682
}
krh@9
   683
krh@27
   684
struct razor_set *
krh@30
   685
razor_importer_finish(struct razor_importer *importer)
krh@9
   686
{
krh@30
   687
	struct razor_set *set;
krh@39
   688
	unsigned long *map, *rmap;
krh@39
   689
	int i, count;
krh@18
   690
krh@39
   691
	map = uniqueify_properties(importer->set, &importer->set->requires);
krh@39
   692
	remap_links(&importer->set->requires_pool, map);
krh@39
   693
	free(map);
krh@39
   694
krh@39
   695
	map = uniqueify_properties(importer->set, &importer->set->provides);
krh@39
   696
	remap_links(&importer->set->provides_pool, map);
krh@39
   697
	free(map);
krh@25
   698
krh@30
   699
	count = importer->set->packages.size / sizeof(struct razor_package);
krh@30
   700
	map = qsort_with_data(importer->set->packages.data,
krh@25
   701
			      count,
krh@25
   702
			      sizeof(struct razor_package),
krh@25
   703
			      compare_packages,
krh@30
   704
			      importer->set);
krh@39
   705
krh@39
   706
	rmap = malloc(count * sizeof *rmap);
krh@39
   707
	for (i = 0; i < count; i++)
krh@39
   708
		rmap[map[i]] = i;
krh@39
   709
krh@39
   710
	remap_links(&importer->set->package_pool, rmap);
krh@25
   711
	free(map);
krh@39
   712
	free(rmap);
krh@13
   713
krh@30
   714
	set = importer->set;
krh@32
   715
	array_release(&importer->buckets);
krh@30
   716
	free(importer);
krh@30
   717
krh@30
   718
	return set;
krh@9
   719
}
krh@9
   720
krh@0
   721
void
krh@4
   722
razor_set_list(struct razor_set *set)
krh@3
   723
{
krh@6
   724
	struct razor_package *p, *end;
krh@6
   725
	char *pool;
krh@3
   726
krh@6
   727
	pool = set->string_pool.data;
krh@6
   728
	end = set->packages.data + set->packages.size;
krh@14
   729
	for (p = set->packages.data; p < end; p++)
krh@6
   730
		printf("%s %s\n", &pool[p->name], &pool[p->version]);
krh@3
   731
}
krh@3
   732
krh@16
   733
struct razor_set *bsearch_set;
krh@16
   734
krh@16
   735
static int
krh@16
   736
compare_package_name(const void *key, const void *data)
krh@16
   737
{
krh@16
   738
	const struct razor_package *p = data;
krh@16
   739
	char *pool;
krh@16
   740
krh@16
   741
	pool = bsearch_set->string_pool.data;
krh@16
   742
krh@16
   743
	return strcmp(key, &pool[p->name]);
krh@16
   744
}
krh@16
   745
krh@10
   746
struct razor_package *
krh@10
   747
razor_set_get_package(struct razor_set *set, const char *package)
krh@10
   748
{
krh@16
   749
	bsearch_set = set;
krh@16
   750
	return bsearch(package, set->packages.data,
krh@16
   751
		       set->packages.size / sizeof(struct razor_package),
krh@16
   752
		       sizeof(struct razor_package), compare_package_name);
krh@10
   753
}
krh@10
   754
krh@18
   755
static int
krh@18
   756
compare_property_name(const void *key, const void *data)
krh@18
   757
{
krh@18
   758
	const struct razor_property *p = data;
krh@18
   759
	char *pool;
krh@18
   760
krh@18
   761
	pool = bsearch_set->string_pool.data;
krh@18
   762
krh@18
   763
	return strcmp(key, &pool[p->name]);
krh@18
   764
}
krh@18
   765
krh@18
   766
struct razor_property *
krh@18
   767
razor_set_get_property(struct razor_set *set,
krh@18
   768
		       struct array *properties,
krh@18
   769
		       const char *property)
krh@18
   770
{
krh@18
   771
	struct razor_property *p, *start;
krh@18
   772
krh@18
   773
	bsearch_set = set;
krh@18
   774
	p = bsearch(property, properties->data,
krh@18
   775
		    properties->size / sizeof(struct razor_property),
krh@18
   776
		    sizeof(struct razor_property), compare_property_name);
krh@18
   777
krh@18
   778
	start = properties->data;
krh@18
   779
	while (p > start && (p - 1)->name == p->name)
krh@18
   780
		p--;
krh@18
   781
krh@18
   782
	return p;
krh@18
   783
}
krh@18
   784
krh@10
   785
static void
krh@10
   786
razor_set_list_all_properties(struct razor_set *set, struct array *properties)
krh@8
   787
{
krh@8
   788
	struct razor_property *p, *end;
krh@8
   789
	char *pool;
krh@8
   790
krh@8
   791
	pool = set->string_pool.data;
krh@10
   792
	end = properties->data + properties->size;
krh@14
   793
	for (p = properties->data; p < end; p++)
krh@8
   794
		printf("%s %s\n", &pool[p->name], &pool[p->version]);
krh@8
   795
}
krh@8
   796
krh@8
   797
void
krh@10
   798
razor_set_list_requires(struct razor_set *set, const char *name)
krh@7
   799
{
krh@10
   800
	struct razor_property *p, *requires;
krh@10
   801
	struct razor_package *package;
krh@10
   802
	unsigned long *r;
krh@7
   803
	char *pool;
krh@7
   804
krh@10
   805
	if (name) {
krh@10
   806
		package = razor_set_get_package(set, name);
krh@39
   807
		r = (unsigned long *) set->requires_pool.data +
krh@10
   808
			package->requires;
krh@10
   809
		requires = set->requires.data;
krh@10
   810
		pool = set->string_pool.data;
krh@18
   811
		while (~*r) {
krh@10
   812
			p = &requires[*r++];
krh@10
   813
			printf("%s %s\n", &pool[p->name], &pool[p->version]);
krh@10
   814
		}
krh@10
   815
	} else
krh@10
   816
		razor_set_list_all_properties(set, &set->requires);
krh@10
   817
}
krh@10
   818
krh@10
   819
void
krh@10
   820
razor_set_list_provides(struct razor_set *set, const char *name)
krh@10
   821
{
krh@10
   822
	struct razor_property *p, *provides;
krh@10
   823
	struct razor_package *package;
krh@10
   824
	unsigned long *r;
krh@10
   825
	char *pool;
krh@10
   826
krh@10
   827
	if (name) {
krh@10
   828
		package = razor_set_get_package(set, name);
krh@39
   829
		r = (unsigned long *) set->provides_pool.data +
krh@10
   830
			package->provides;
krh@10
   831
		provides = set->provides.data;
krh@10
   832
		pool = set->string_pool.data;
krh@18
   833
		while (~*r) {
krh@10
   834
			p = &provides[*r++];
krh@10
   835
			printf("%s %s\n", &pool[p->name], &pool[p->version]);
krh@10
   836
		}
krh@10
   837
	} else 
krh@10
   838
		razor_set_list_all_properties(set, &set->provides);
krh@7
   839
}
krh@7
   840
krh@7
   841
void
krh@18
   842
razor_set_list_property_packages(struct razor_set *set,
krh@18
   843
				 struct array *properties,
krh@20
   844
				 const char *name,
krh@20
   845
				 const char *version)
krh@18
   846
{
krh@18
   847
	struct razor_property *property, *end;
krh@18
   848
	struct razor_package *p, *packages;
krh@18
   849
	unsigned long *r;
krh@18
   850
	char *pool;
krh@18
   851
krh@18
   852
	if (name == NULL)
krh@18
   853
		return;
krh@18
   854
krh@18
   855
	property = razor_set_get_property(set, properties, name);
krh@18
   856
	packages = set->packages.data;
krh@18
   857
	pool = set->string_pool.data;
krh@18
   858
	end = properties->data + properties->size;
krh@18
   859
	while (property < end && strcmp(name, &pool[property->name]) == 0) {
krh@35
   860
		if (version && versioncmp(version, &pool[property->version]) != 0)
krh@20
   861
			goto next;
krh@18
   862
		r = (unsigned long *)
krh@39
   863
			set->package_pool.data + property->packages;
krh@18
   864
		while (~*r) {
krh@18
   865
			p = &packages[*r++];
krh@18
   866
			printf("%s %s\n",
krh@18
   867
			       &pool[p->name], &pool[p->version]);
krh@18
   868
		}
krh@20
   869
	next:
krh@18
   870
		property++;
krh@18
   871
	}
krh@18
   872
}
krh@18
   873
krh@18
   874
void
krh@21
   875
razor_set_validate(struct razor_set *set, struct array *unsatisfied)
krh@21
   876
{
krh@21
   877
	struct razor_property *r, *p, *rend, *pend;
krh@21
   878
	unsigned long *u;
krh@21
   879
	char *pool;
krh@21
   880
krh@21
   881
	p = set->provides.data;
krh@21
   882
	rend = set->requires.data + set->requires.size;
krh@21
   883
	pend = set->provides.data + set->provides.size;
krh@21
   884
	pool = set->string_pool.data;
krh@21
   885
	
krh@35
   886
	for (r = set->requires.data; r < rend; r++) {
krh@21
   887
		while (p < pend && strcmp(&pool[r->name], &pool[p->name]) > 0)
krh@21
   888
			p++;
krh@37
   889
krh@35
   890
		/* If there is more than one version of a provides,
krh@35
   891
		 * seek to the end for the highest version. */
krh@35
   892
		while (p + 1 < pend && p->name == (p + 1)->name)
krh@35
   893
			p++;
krh@37
   894
krh@37
   895
		/* FIXME: We need to track property flags (<, <=, =
krh@37
   896
		 * etc) to properly determine if a requires is
krh@37
   897
		 * satisfied.  The current code doesn't track that the
krh@37
   898
		 * requires a = 1 isn't satisfied by a = 2 provides. */
krh@37
   899
krh@35
   900
		if (p == pend || strcmp(&pool[r->name], &pool[p->name]) != 0 ||
krh@35
   901
		    versioncmp(&pool[r->version], &pool[p->version]) > 0) {
krh@35
   902
			/* FIXME: We ignore file requires for now. */
krh@35
   903
			if (pool[r->name] == '/')
krh@35
   904
				continue;
krh@21
   905
			u = array_add(unsatisfied, sizeof *u);
krh@21
   906
			*u = r - (struct razor_property *) set->requires.data;
krh@21
   907
		}
krh@21
   908
	}
krh@21
   909
}
krh@21
   910
krh@21
   911
void
krh@21
   912
razor_set_list_unsatisfied(struct razor_set *set)
krh@21
   913
{
krh@21
   914
	struct array unsatisfied;
krh@21
   915
	struct razor_property *requires, *r;
krh@21
   916
	unsigned long *u, *end;
krh@21
   917
	char *pool;
krh@21
   918
krh@21
   919
	array_init(&unsatisfied);
krh@21
   920
	razor_set_validate(set, &unsatisfied);
krh@21
   921
krh@21
   922
	end = unsatisfied.data + unsatisfied.size;
krh@21
   923
	requires = set->requires.data;
krh@21
   924
	pool = set->string_pool.data;
krh@21
   925
krh@21
   926
	for (u = unsatisfied.data; u < end; u++) {
krh@21
   927
		r = requires + *u;
krh@21
   928
		printf("%s %s not satisfied\n",
krh@21
   929
		       &pool[r->name], &pool[r->version]);
krh@21
   930
	}
krh@21
   931
krh@21
   932
	array_release(&unsatisfied);
krh@21
   933
}
krh@21
   934
krh@33
   935
static void
krh@33
   936
add_package(struct razor_importer *importer,
krh@33
   937
	    struct razor_package *package, struct razor_set *set)
krh@33
   938
{
krh@33
   939
	char *pool;
krh@33
   940
	unsigned long *r;
krh@33
   941
	struct razor_property *p, *properties;
krh@33
   942
krh@33
   943
	pool = set->string_pool.data;
krh@33
   944
	razor_importer_begin_package(importer,
krh@33
   945
				     &pool[package->name],
krh@33
   946
				     &pool[package->version]);
krh@33
   947
krh@39
   948
	r = (unsigned long *) set->requires_pool.data + package->requires;
krh@33
   949
	properties = set->requires.data;
krh@33
   950
	while (~*r) {
krh@33
   951
		p = &properties[*r++];
krh@33
   952
		razor_importer_add_requires(importer,
krh@33
   953
					    &pool[p->name], &pool[p->version]);
krh@33
   954
	}
krh@33
   955
krh@39
   956
	r = (unsigned long *) set->provides_pool.data + package->provides;
krh@33
   957
	properties = set->provides.data;
krh@33
   958
	while (~*r) {
krh@33
   959
		p = &properties[*r++];
krh@33
   960
		razor_importer_add_provides(importer,
krh@33
   961
					    &pool[p->name], &pool[p->version]);
krh@33
   962
	}
krh@33
   963
krh@33
   964
	razor_importer_finish_package(importer);
krh@33
   965
}
krh@33
   966
krh@33
   967
/* Add packages from 'upstream' to 'set'.  The packages to add are
krh@33
   968
 * specified by the 'packages' array, which is a sorted list of
krh@33
   969
 * package indexes.  Returns a newly allocated package set.  Does not
krh@33
   970
 * enforce validity of the resulting package set. */
krh@33
   971
krh@36
   972
/* FIXME: We can do this in a linear sweep instead of using an
krh@36
   973
 * importer and the sorting that incurs: build the new package list
krh@36
   974
 * sorted, build up a map from package index in old set to package
krh@36
   975
 * index in new set for both sets. ~0 means 'not in new set'.  build
krh@36
   976
 * new string pool as we go, probably just re-use that part of the
krh@36
   977
 * importer.  as we build the package list, fill out a bitvector of
krh@36
   978
 * the properties that are referenced by the pacakges in the new
krh@36
   979
 * set. then do a parallel loop through the properties and emit them
krh@36
   980
 * to the new set and build a map from indices in the old set to
krh@36
   981
 * indices in the new set. then loop through the packages again and
krh@36
   982
 * emit the property lists. */
krh@36
   983
krh@33
   984
struct razor_set *
krh@33
   985
razor_set_add(struct razor_set *set, struct razor_set *upstream,
krh@33
   986
	      struct array *packages)
krh@33
   987
{
krh@33
   988
	struct razor_importer *importer;
krh@33
   989
	struct razor_package *upstream_packages, *p, *s, *send;
krh@33
   990
	char *spool, *upool;
krh@33
   991
	unsigned long *u, *uend;
krh@33
   992
	int cmp;
krh@33
   993
krh@33
   994
	importer = razor_importer_new();
krh@33
   995
	upstream_packages = upstream->packages.data;
krh@33
   996
	u = packages->data;
krh@33
   997
	uend = packages->data + packages->size;
krh@33
   998
	upool = upstream->string_pool.data;
krh@33
   999
	s = set->packages.data;
krh@33
  1000
	send = set->packages.data + set->packages.size;
krh@33
  1001
	spool = set->string_pool.data;
krh@33
  1002
krh@33
  1003
	while (s < send) {
krh@33
  1004
		p = upstream_packages + *u;
krh@37
  1005
		if (u < uend)
krh@37
  1006
			cmp = strcmp(&spool[s->name], &upool[p->name]);
krh@37
  1007
		if (u >= uend || cmp < 0) {
krh@33
  1008
			add_package(importer, s, set);
krh@33
  1009
			s++;
krh@33
  1010
		} else if (cmp == 0) {
krh@33
  1011
			add_package(importer, p, upstream);
krh@33
  1012
			s++;
krh@33
  1013
			u++;
krh@33
  1014
		} else {
krh@33
  1015
			add_package(importer, p, upstream);
krh@33
  1016
			u++;
krh@33
  1017
		}
krh@33
  1018
	}
krh@33
  1019
krh@33
  1020
	return razor_importer_finish(importer);
krh@33
  1021
}
krh@33
  1022
krh@37
  1023
void
krh@37
  1024
razor_set_satisfy(struct razor_set *set, struct array *unsatisfied,
krh@37
  1025
		  struct razor_set *upstream, struct array *list)
krh@37
  1026
{
krh@37
  1027
	struct razor_property *requires, *r;
krh@37
  1028
	struct razor_property *p, *pend;
krh@39
  1029
	unsigned long *u, *end, *pkg, *package_pool;
krh@37
  1030
	char *pool, *upool;
krh@37
  1031
krh@37
  1032
	end = unsatisfied->data + unsatisfied->size;
krh@37
  1033
	requires = set->requires.data;
krh@37
  1034
	pool = set->string_pool.data;
krh@37
  1035
krh@37
  1036
	p = upstream->provides.data;
krh@37
  1037
	pend = upstream->provides.data + upstream->provides.size;
krh@37
  1038
	upool = upstream->string_pool.data;
krh@39
  1039
	package_pool = upstream->package_pool.data;
krh@37
  1040
krh@37
  1041
	for (u = unsatisfied->data; u < end; u++) {
krh@37
  1042
		r = requires + *u;
krh@37
  1043
krh@37
  1044
		while (p < pend && strcmp(&pool[r->name], &upool[p->name]) > 0)
krh@37
  1045
			p++;
krh@37
  1046
		/* If there is more than one version of a provides,
krh@37
  1047
		 * seek to the end for the highest version. */
krh@37
  1048
		while (p + 1 < pend && p->name == (p + 1)->name)
krh@37
  1049
			p++;
krh@37
  1050
krh@37
  1051
		if (p == pend ||
krh@37
  1052
		    strcmp(&pool[r->name], &upool[p->name]) != 0 ||
krh@37
  1053
		    versioncmp(&pool[r->version], &upool[p->version]) > 0) {
krh@37
  1054
			/* Do we need to track unsatisfiable requires
krh@37
  1055
			 * as we go, or should we just do a
krh@37
  1056
			 * razor_set_validate() at the end? */
krh@37
  1057
		} else {
krh@37
  1058
			pkg = array_add(list, sizeof *pkg);
krh@37
  1059
			/* We just pull in the first package that provides */
krh@39
  1060
			*pkg = package_pool[p->packages];
krh@37
  1061
		}
krh@37
  1062
	}	
krh@37
  1063
}
krh@37
  1064
krh@38
  1065
static void
krh@38
  1066
find_packages(struct razor_set *set,
krh@38
  1067
	      int count, const char **packages, struct array *list)
krh@38
  1068
{
krh@38
  1069
	struct razor_package *p;
krh@38
  1070
	unsigned long *r;
krh@38
  1071
	int i;
krh@38
  1072
krh@38
  1073
	/* FIXME: Sort the packages. */
krh@38
  1074
	for (i = 0; i < count; i++) {
krh@38
  1075
		p = razor_set_get_package(set, packages[i]);
krh@38
  1076
		r = array_add(list, sizeof *r);
krh@38
  1077
		*r = p - (struct razor_package *) set->packages.data;
krh@38
  1078
	}
krh@38
  1079
}
krh@38
  1080
krh@38
  1081
static void
krh@38
  1082
find_all_packages(struct razor_set *set,
krh@38
  1083
		  struct razor_set *upstream, struct array *list)
krh@38
  1084
{
krh@38
  1085
	struct razor_package *p, *u, *pend, *uend;
krh@38
  1086
	unsigned long *r;
krh@38
  1087
	char *pool, *upool;
krh@38
  1088
krh@38
  1089
	pend = set->packages.data + set->packages.size;
krh@38
  1090
	pool = set->string_pool.data;
krh@38
  1091
	u = upstream->packages.data;
krh@38
  1092
	uend = upstream->packages.data + upstream->packages.size;
krh@38
  1093
	upool = upstream->string_pool.data;
krh@38
  1094
krh@38
  1095
	for (p = set->packages.data; p < pend; p++) {
krh@38
  1096
		while (u < uend && strcmp(&pool[p->name], &upool[u->name]) > 0)
krh@38
  1097
			u++;
krh@38
  1098
		if (strcmp(&pool[p->name], &upool[u->name]) == 0) {
krh@38
  1099
			r = array_add(list, sizeof *r);
krh@38
  1100
			*r = u - (struct razor_package *) upstream->packages.data;
krh@38
  1101
		}
krh@38
  1102
	}
krh@38
  1103
}
krh@38
  1104
krh@33
  1105
struct razor_set *
krh@33
  1106
razor_set_update(struct razor_set *set, struct razor_set *upstream,
krh@33
  1107
		 int count, const char **packages)
krh@33
  1108
{
krh@37
  1109
	struct razor_set *new;
krh@37
  1110
	struct razor_package *p, *upackages;
krh@37
  1111
	struct array list, unsatisfied;
krh@37
  1112
	char *pool;
krh@38
  1113
	unsigned long *u, *end;
krh@38
  1114
	int total = 0;
krh@33
  1115
krh@33
  1116
	array_init(&list);
krh@38
  1117
	if (count > 0)
krh@38
  1118
		find_packages(upstream, count, packages, &list);
krh@38
  1119
	else
krh@38
  1120
		find_all_packages(set, upstream, &list);
krh@33
  1121
krh@37
  1122
	end = list.data + list.size;
krh@37
  1123
	upackages = upstream->packages.data;
krh@37
  1124
	pool = upstream->string_pool.data;
krh@37
  1125
	for (u = list.data; u < end; u++) {
krh@37
  1126
		p = upackages + *u;
krh@37
  1127
		printf("package %s-%s set to be updated\n",
krh@37
  1128
		       &pool[p->name], &pool[p->version]);
krh@37
  1129
	}
krh@38
  1130
	total += list.size / sizeof *u;
krh@37
  1131
krh@37
  1132
	while (list.size > 0) {
krh@37
  1133
		printf(" -- satisfying new requires\n");
krh@37
  1134
krh@37
  1135
		new = razor_set_add(set, upstream, &list);
krh@37
  1136
		array_release(&list);
krh@37
  1137
		razor_set_destroy(set);
krh@37
  1138
		set = new;
krh@37
  1139
krh@37
  1140
		array_init(&unsatisfied);
krh@37
  1141
		razor_set_validate(new, &unsatisfied);
krh@37
  1142
		array_init(&list);
krh@37
  1143
		razor_set_satisfy(new, &unsatisfied, upstream, &list);
krh@37
  1144
		array_release(&unsatisfied);
krh@37
  1145
krh@37
  1146
		end = list.data + list.size;
krh@37
  1147
		upackages = upstream->packages.data;
krh@37
  1148
		pool = upstream->string_pool.data;
krh@37
  1149
		for (u = list.data; u < end; u++) {
krh@37
  1150
			p = upackages + *u;
krh@37
  1151
			printf("package %s-%s set to be updated\n",
krh@37
  1152
			       &pool[p->name], &pool[p->version]);
krh@37
  1153
		}
krh@38
  1154
		total += list.size / sizeof *u;
krh@37
  1155
	}
krh@37
  1156
krh@37
  1157
	array_release(&list);
krh@37
  1158
krh@38
  1159
	printf("total of %d packages set to be updated\n", total);
krh@38
  1160
krh@37
  1161
	return set;
krh@33
  1162
}
krh@33
  1163
krh@21
  1164
void
krh@4
  1165
razor_set_info(struct razor_set *set)
krh@3
  1166
{
krh@3
  1167
	unsigned int offset, size;
krh@3
  1168
	int i;
krh@3
  1169
krh@4
  1170
	for (i = 0; i < set->header->sections[i].type; i++) {
krh@4
  1171
		offset = set->header->sections[i].offset;
krh@18
  1172
		size = set->header->sections[i].size;
krh@3
  1173
krh@4
  1174
		switch (set->header->sections[i].type) {
krh@4
  1175
		case RAZOR_PACKAGES:
krh@3
  1176
			printf("package section:\t%dkb\n", size / 1024);
krh@3
  1177
			break;
krh@8
  1178
		case RAZOR_REQUIRES:
krh@8
  1179
			printf("requires section:\t%dkb\n", size / 1024);
krh@8
  1180
			break;
krh@7
  1181
		case RAZOR_PROVIDES:
krh@7
  1182
			printf("provides section:\t%dkb\n", size / 1024);
krh@7
  1183
			break;
krh@19
  1184
		case RAZOR_STRING_POOL:
krh@19
  1185
			printf("string pool:\t\t%dkb\n", size / 1024);
krh@19
  1186
			break;
krh@3
  1187
		}
krh@3
  1188
	}
krh@0
  1189
}
krh@0
  1190
krh@0
  1191
static int
krh@0
  1192
usage(void)
krh@0
  1193
{
krh@7
  1194
	printf("usage: razor [ import FILES | lookup <key> | "
krh@15
  1195
	       "list | list-requires | list-provides | eat-yum | info ]\n");
krh@0
  1196
	exit(1);
krh@0
  1197
}
krh@0
  1198
krh@15
  1199
static const char *repo_filename = "system.repo";
krh@15
  1200
static const char rawhide_repo_filename[] = "rawhide.repo";
krh@0
  1201
krh@0
  1202
int
krh@27
  1203
main(int argc, const char *argv[])
krh@0
  1204
{
krh@37
  1205
	struct razor_set *set, *upstream;
krh@0
  1206
	struct stat statbuf;
krh@15
  1207
	char *repo;
krh@15
  1208
krh@15
  1209
	repo = getenv("RAZOR_REPO");
krh@15
  1210
	if (repo != NULL)
krh@15
  1211
		repo_filename = repo;
krh@0
  1212
krh@3
  1213
	if (argc < 2) {
krh@0
  1214
		usage();
krh@0
  1215
	} else if (strcmp(argv[1], "import") == 0) {
krh@0
  1216
		if (stat("set", &statbuf) && mkdir("set", 0777)) {
krh@0
  1217
			fprintf(stderr, "could not create directory 'set'\n");
krh@0
  1218
			exit(-1);
krh@0
  1219
		}
krh@0
  1220
			
krh@27
  1221
		set = razor_import_rzr_files(argc - 2, argv + 2);
krh@6
  1222
krh@6
  1223
		printf("pool size: %d\n", set->string_pool.size);
krh@6
  1224
		printf("pool allocation: %d\n", set->string_pool.alloc);
krh@7
  1225
		printf("packages: %d\n",
krh@7
  1226
		       set->packages.size / sizeof(struct razor_package));
krh@8
  1227
		printf("requires: %d\n",
krh@8
  1228
		       set->requires.size / sizeof(struct razor_property));
krh@7
  1229
		printf("provides: %d\n",
krh@8
  1230
		       set->provides.size / sizeof(struct razor_property));
krh@0
  1231
krh@4
  1232
		razor_set_write(set, repo_filename);
krh@0
  1233
krh@4
  1234
		razor_set_destroy(set);
krh@3
  1235
	} else if (strcmp(argv[1], "list") == 0) {
krh@4
  1236
		set = razor_set_open(repo_filename);
krh@4
  1237
		razor_set_list(set);
krh@4
  1238
		razor_set_destroy(set);
krh@8
  1239
	} else if (strcmp(argv[1], "list-requires") == 0) {
krh@8
  1240
		set = razor_set_open(repo_filename);
krh@10
  1241
		razor_set_list_requires(set, argv[2]);
krh@8
  1242
		razor_set_destroy(set);
krh@7
  1243
	} else if (strcmp(argv[1], "list-provides") == 0) {
krh@7
  1244
		set = razor_set_open(repo_filename);
krh@10
  1245
		razor_set_list_provides(set, argv[2]);
krh@7
  1246
		razor_set_destroy(set);
krh@18
  1247
	} else if (strcmp(argv[1], "what-requires") == 0) {
krh@18
  1248
		set = razor_set_open(repo_filename);
krh@20
  1249
		razor_set_list_property_packages(set, &set->requires,
krh@20
  1250
						 argv[2], argv[3]);
krh@18
  1251
		razor_set_destroy(set);
krh@18
  1252
	} else if (strcmp(argv[1], "what-provides") == 0) {
krh@18
  1253
		set = razor_set_open(repo_filename);
krh@20
  1254
		razor_set_list_property_packages(set, &set->provides,
krh@20
  1255
						 argv[2], argv[3]);
krh@18
  1256
		razor_set_destroy(set);
krh@3
  1257
	} else if (strcmp(argv[1], "info") == 0) {
krh@4
  1258
		set = razor_set_open(repo_filename);
krh@4
  1259
		razor_set_info(set);
krh@4
  1260
		razor_set_destroy(set);
krh@15
  1261
	} else if (strcmp(argv[1], "eat-yum") == 0) {
krh@15
  1262
		set = razor_set_create_from_yum_filelist(STDIN_FILENO);
krh@15
  1263
		if (set == NULL)
krh@15
  1264
			return 1;
krh@15
  1265
		razor_set_write(set, rawhide_repo_filename);
krh@15
  1266
		razor_set_destroy(set);
krh@18
  1267
		printf("wrote %s\n", rawhide_repo_filename);
krh@28
  1268
	} else if (strcmp(argv[1], "import-rpmdb") == 0) {
krh@28
  1269
		set = razor_set_create_from_rpmdb();
krh@28
  1270
		if (set == NULL)
krh@28
  1271
			return 1;
krh@28
  1272
		razor_set_write(set, repo_filename);
krh@28
  1273
		razor_set_destroy(set);
krh@28
  1274
		printf("wrote %s\n", repo_filename);
krh@21
  1275
	} else if (strcmp(argv[1], "validate") == 0) {
krh@21
  1276
		set = razor_set_open(repo_filename);
krh@21
  1277
		if (set == NULL)
krh@21
  1278
			return 1;
krh@21
  1279
		razor_set_list_unsatisfied(set);
krh@21
  1280
		razor_set_destroy(set);
krh@33
  1281
	} else if (strcmp(argv[1], "update") == 0) {
krh@33
  1282
		set = razor_set_open(repo_filename);
krh@33
  1283
		upstream = razor_set_open(rawhide_repo_filename);
krh@33
  1284
		if (set == NULL || upstream == NULL)
krh@33
  1285
			return 1;
krh@37
  1286
		set = razor_set_update(set, upstream, argc - 2, argv + 2);
krh@37
  1287
		razor_set_write(set, "system-updated.repo");
krh@33
  1288
		razor_set_destroy(set);
krh@33
  1289
		razor_set_destroy(upstream);
krh@37
  1290
		printf("wrote system-updated.repo\n");
krh@0
  1291
	} else {
krh@0
  1292
		usage();
krh@0
  1293
	}
krh@0
  1294
krh@0
  1295
	return 0;
krh@0
  1296
}