Improve import script to also pull version and release fields.
14 write_to_fd(int fd, void *p, size_t size)
20 len = write(fd, p, rest);
30 write_to_file(const char *filename, void *p, size_t size)
34 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
37 err = write_to_fd(fd, p, size);
43 struct hashtable_header {
46 struct { unsigned int type, offset; } sections[0];
49 #define HASHTABLE_MAGIC 0x7a7a7a7a
50 #define HASHTABLE_VERSION 1
51 #define HASHTABLE_BUCKETS 1
52 #define HASHTABLE_STRINGS 2
55 unsigned long *buckets;
56 int bucket_count, bucket_alloc;
58 int pool_size, pool_alloc;
59 struct hashtable_header *header;
74 hashtable_create(void)
78 ht = zalloc(sizeof *ht);
79 ht->buckets = zalloc(4096 * sizeof *ht->buckets);
81 ht->bucket_alloc = 4096;
83 ht->string_pool = zalloc(4096);
85 ht->pool_alloc = 4096;
91 hashtable_create_from_file(const char *filename)
95 unsigned int size, offset;
98 ht = zalloc(sizeof *ht);
99 fd = open(filename, O_RDONLY);
100 if (fstat(fd, &stat) < 0)
102 ht->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
103 if (ht->header == MAP_FAILED) {
108 for (i = 0; i < ht->header->sections[i].type; i++) {
109 offset = ht->header->sections[i].offset;
110 size = ht->header->sections[i + 1].offset - offset;
112 switch (ht->header->sections[i].type) {
113 case HASHTABLE_BUCKETS:
114 ht->buckets = (void *) ht->header + offset;
115 ht->bucket_count = size / sizeof *ht->buckets;
116 ht->bucket_alloc = ht->bucket_count;
118 case HASHTABLE_STRINGS:
119 ht->string_pool = (void *) ht->header + offset;
120 ht->pool_size = size;
121 ht->pool_alloc = size;
131 hashtable_destroy(struct hashtable *ht)
137 for (i = 0; ht->header->sections[i].type; i++)
139 size = ht->header->sections[i].type;
140 munmap(ht->header, size);
143 free(ht->string_pool);
150 hashtable_write(struct hashtable *ht, const char *filename)
154 struct hashtable_header *header = (struct hashtable_header *) data;
156 memset(data, 0, sizeof data);
157 header->magic = HASHTABLE_MAGIC;
158 header->version = HASHTABLE_VERSION;
160 header->sections[0].type = HASHTABLE_BUCKETS;
161 header->sections[0].offset = sizeof data;
163 header->sections[1].type = HASHTABLE_STRINGS;
164 header->sections[1].offset =
165 sizeof data + ht->bucket_alloc * sizeof *ht->buckets;
167 header->sections[2].type = 0;
168 header->sections[2].offset =
169 header->sections[1].offset + ht->pool_size;
171 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
175 write_to_fd(fd, data, sizeof data);
176 write_to_fd(fd, ht->buckets, ht->bucket_alloc * sizeof *ht->buckets);
177 write_to_fd(fd, ht->string_pool, ht->pool_size);
183 hash_string(const char *key)
186 unsigned int hash = 0;
188 for (p = key; *p; p++)
189 hash = (hash << 2) ^ *p;
195 hashtable_lookup(struct hashtable *ht, const char *key)
202 mask = ht->bucket_alloc - 1;
203 start = hash_string(key) & mask;
206 value = ht->buckets[i];
211 if (strcmp(key, &ht->string_pool[value]) == 0)
215 } while (i != start);
221 add_to_string_pool(struct hashtable *ht, const char *key)
227 len = strlen(key) + 1;
228 alloc = ht->pool_alloc;
229 while (alloc < ht->pool_size + len)
231 if (ht->pool_alloc < alloc) {
232 pool = realloc(ht->string_pool, alloc);
235 ht->string_pool = pool;
236 ht->pool_alloc = alloc;
239 memcpy(ht->string_pool + ht->pool_size, key, len);
240 value = ht->pool_size;
241 ht->pool_size += len;
247 do_insert(struct hashtable *ht, unsigned long value)
253 key = &ht->string_pool[value];
254 mask = ht->bucket_alloc - 1;
255 start = hash_string(key) & mask;
258 if (ht->buckets[i] == 0) {
259 ht->buckets[i] = value;
263 } while (i != start);
267 hashtable_insert(struct hashtable *ht, const char *key)
269 unsigned long value, *buckets, *old_buckets;
270 int i, alloc, old_alloc;
272 alloc = ht->bucket_alloc;
273 while (alloc < 4 * ht->bucket_count)
276 if (alloc != ht->bucket_alloc) {
277 buckets = zalloc(alloc * sizeof *ht->buckets);
280 old_buckets = ht->buckets;
281 ht->buckets = buckets;
282 old_alloc = ht->bucket_alloc;
283 ht->bucket_alloc = alloc;
285 for (i = 0; i < old_alloc; i++) {
286 value = old_buckets[i];
288 do_insert(ht, value);
293 value = add_to_string_pool(ht, key);
294 do_insert (ht, value);
300 struct razor_context {
301 struct hashtable *global_ht;
304 struct razor_context *
305 razor_context_create (void)
307 struct razor_context *ctx;
309 ctx = malloc(sizeof *ctx);
310 ctx->global_ht = hashtable_create();
315 struct razor_context *
316 razor_context_create_from_file (const char *filename)
318 struct razor_context *ctx;
320 ctx = malloc(sizeof *ctx);
321 ctx->global_ht = hashtable_create_from_file(filename);
327 razor_context_tokenize(struct razor_context *ctx, const char *string)
331 token = hashtable_lookup(ctx->global_ht, string);
335 return hashtable_insert(ctx->global_ht, string);
339 struct razor_context *ctx;
342 struct parsing_context {
343 struct razor_context *ctx;
347 start_element(void *data, const char *name, const char **atts)
349 struct parsing_context *ctx = data;
352 for (i = 0; atts[i]; i += 2)
353 razor_context_tokenize(ctx->ctx, atts[i + 1]);
357 end_element (void *data, const char *name)
362 sha1_to_hex(const unsigned char *sha1)
365 static char hexbuffer[4][50];
366 static const char hex[] = "0123456789abcdef";
367 char *buffer = hexbuffer[3 & ++bufno], *buf = buffer;
370 for (i = 0; i < 20; i++) {
371 unsigned int val = *sha1++;
372 *buf++ = hex[val >> 4];
373 *buf++ = hex[val & 0xf];
381 razor_context_read_file(struct razor_context *ctx, const char *filename)
385 struct parsing_context pctx;
390 unsigned char hash[20];
392 fd = open(filename, O_RDONLY);
393 if (fstat(fd, &stat) < 0)
395 p = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
399 parser = XML_ParserCreate(NULL);
401 XML_SetUserData(parser, &pctx);
402 XML_SetElementHandler(parser, start_element, end_element);
403 if (XML_Parse(parser, p, stat.st_size, 1) == XML_STATUS_ERROR) {
405 "%s at line %d, %s\n",
406 XML_ErrorString(XML_GetErrorCode(parser)),
407 XML_GetCurrentLineNumber(parser),
412 XML_ParserFree(parser);
415 SHA1_Update(&sha1, p, stat.st_size);
416 SHA1_Final(hash, &sha1);
420 snprintf(buf, sizeof buf, "set/%s", sha1_to_hex(hash));
421 if (write_to_file(buf, p, stat.st_size) < 0)
423 munmap(p, stat.st_size);
429 razor_context_write(struct razor_context *ctx, const char *filename)
431 return hashtable_write(ctx->global_ht, filename);
435 razor_context_destroy(struct razor_context *ctx)
437 hashtable_destroy(ctx->global_ht);
444 printf("usage: razor [ import FILES | lookup <key> ]\n");
448 static const char repo_filename[] = "system.repo";
451 main(int argc, char *argv[])
454 struct razor_context *ctx;
459 } else if (strcmp(argv[1], "import") == 0) {
460 if (stat("set", &statbuf) && mkdir("set", 0777)) {
461 fprintf(stderr, "could not create directory 'set'\n");
465 ctx = razor_context_create();
467 for (i = 2; i < argc; i++) {
468 if (razor_context_read_file(ctx, argv[i]) < 0) {
469 fprintf(stderr, "failed to import %s\n",
475 printf("number of buckets: %d\n",
476 ctx->global_ht->bucket_count);
477 printf("bucket allocation: %d\n",
478 ctx->global_ht->bucket_alloc);
479 printf("pool size: %d\n", ctx->global_ht->pool_size);
480 printf("pool allocation: %d\n", ctx->global_ht->pool_alloc);
482 razor_context_write(ctx, repo_filename);
484 razor_context_destroy(ctx);
485 } else if (strcmp(argv[1], "lookup") == 0) {
486 ctx = razor_context_create_from_file(repo_filename);
487 printf("%s is %lu\n", argv[2],
488 hashtable_lookup(ctx->global_ht, argv[2]));
489 razor_context_destroy(ctx);