/* * pkg - mkpkg database reader (read-only) * https://rawnix.org * * Copyright (c) 2025 zorz@gmx.com * SPDX-License-Identifier: BSD-2-Clause */ #include "pkgdb.h" #include "paths.h" static void pkgdb_insert(pkgdb_t *db, const char *name, const char *version) { unsigned long hash = hash_djb2(name); size_t idx = hash % db->bucket_count; pkgdb_entry_t *e; e = xmalloc(sizeof(pkgdb_entry_t)); e->key = xstrdup(name); e->pkg = xmalloc(sizeof(installed_pkg_t)); e->pkg->name = xstrdup(name); e->pkg->version = xstrdup(version); e->next = db->buckets[idx]; db->buckets[idx] = e; db->size++; } pkgdb_t *pkgdb_open(const char *root) { pkgdb_t *db; FILE *fp; char line[MAX_LINE]; char *name = NULL, *version = NULL; int state = 0; /* 0=name, 1=version, 2=files */ size_t i; db = xmalloc(sizeof(pkgdb_t)); db->bucket_count = HASH_BUCKETS; db->size = 0; db->buckets = xmalloc(db->bucket_count * sizeof(pkgdb_entry_t *)); for (i = 0; i < db->bucket_count; i++) db->buckets[i] = NULL; db->path = build_root_path(root, PKGDB_PATH); fp = fopen(db->path, "r"); if (!fp) return db; /* empty db is acceptable */ while (fgets(line, sizeof(line), fp)) { line[strcspn(line, "\n")] = '\0'; if (line[0] == '\0') { if (name && version) { pkgdb_insert(db, name, version); free(name); free(version); name = version = NULL; } state = 0; continue; } if (state == 0) { name = xstrdup(line); state = 1; } else if (state == 1) { version = xstrdup(line); state = 2; } /* state 2 = file list, ignored */ } /* handle last entry (file may lack trailing blank line) */ if (name && version) pkgdb_insert(db, name, version); free(name); free(version); fclose(fp); return db; } void pkgdb_close(pkgdb_t *db) { size_t i; pkgdb_entry_t *e, *next; if (!db) return; for (i = 0; i < db->bucket_count; i++) { e = db->buckets[i]; while (e) { next = e->next; free(e->key); free(e->pkg->name); free(e->pkg->version); free(e->pkg); free(e); e = next; } } free(db->buckets); free(db->path); free(db); } installed_pkg_t *pkgdb_find(pkgdb_t *db, const char *name) { unsigned long hash; size_t idx; pkgdb_entry_t *e; if (!db || !name) return NULL; hash = hash_djb2(name); idx = hash % db->bucket_count; for (e = db->buckets[idx]; e; e = e->next) if (strcmp(e->key, name) == 0) return e->pkg; return NULL; } bool pkgdb_installed(pkgdb_t *db, const char *name) { return pkgdb_find(db, name) != NULL; } strarray_t *pkgdb_list(pkgdb_t *db) { strarray_t *arr; size_t i; pkgdb_entry_t *e; arr = xmalloc(sizeof(strarray_t)); strarray_init(arr); if (!db) return arr; for (i = 0; i < db->bucket_count; i++) for (e = db->buckets[i]; e; e = e->next) strarray_add(arr, e->key); return arr; }