initial commit
commit
342f977ac7
|
@ -0,0 +1,3 @@
|
||||||
|
# Cieter
|
||||||
|
|
||||||
|
Cieter is a rewrite of the Vieter project in modern C.
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef VIETER_DYNARRAY
|
||||||
|
#define VIETER_DYNARRAY
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct dyn_array DynArray;
|
||||||
|
|
||||||
|
DynArray *dynarray_init(size_t initial_capacity);
|
||||||
|
void dynarray_add(DynArray *da, const char * s);
|
||||||
|
void dynarray_free(DynArray *da);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a DynArray into an array by freeing all its surrounding components
|
||||||
|
* and returning the underlying array pointer.
|
||||||
|
*/
|
||||||
|
char **dynarray_convert(DynArray *da);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef VIETER_PACKAGE
|
||||||
|
#define VIETER_PACKAGE
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "archive.h"
|
||||||
|
#include "archive_entry.h"
|
||||||
|
|
||||||
|
#include "package_info.h"
|
||||||
|
#include "dynarray.h"
|
||||||
|
|
||||||
|
typedef struct pkg {
|
||||||
|
char *path;
|
||||||
|
PkgInfo *info;
|
||||||
|
DynArray *files;
|
||||||
|
int compression;
|
||||||
|
} Pkg;
|
||||||
|
|
||||||
|
Pkg *package_read_archive(const char *pkg_path);
|
||||||
|
void package_free(Pkg ** ptp);
|
||||||
|
char *package_to_description(Pkg *pkg);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef VIETER_PACKAGE_INFO
|
||||||
|
#define VIETER_PACKAGE_INFO
|
||||||
|
|
||||||
|
#define FREE_STRING(sp) if (sp != NULL) free(sp)
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "dynarray.h"
|
||||||
|
|
||||||
|
typedef struct pkg_info {
|
||||||
|
char *name;
|
||||||
|
char *base;
|
||||||
|
char *version;
|
||||||
|
char *description;
|
||||||
|
int64_t size;
|
||||||
|
int64_t csize;
|
||||||
|
char *url;
|
||||||
|
char *arch;
|
||||||
|
int64_t build_date;
|
||||||
|
char *packager;
|
||||||
|
char *pgpsig;
|
||||||
|
int64_t pgpsigsize;
|
||||||
|
|
||||||
|
DynArray *groups;
|
||||||
|
DynArray *licenses;
|
||||||
|
DynArray *replaces;
|
||||||
|
DynArray *depends;
|
||||||
|
DynArray *conflicts;
|
||||||
|
DynArray *provides;
|
||||||
|
DynArray *optdepends;
|
||||||
|
DynArray *makedepends;
|
||||||
|
DynArray *checkdepends;
|
||||||
|
} PkgInfo;
|
||||||
|
|
||||||
|
PkgInfo *package_info_init();
|
||||||
|
int package_info_parse(PkgInfo *pkg_info, char *pkg_info_str);
|
||||||
|
void package_info_free(PkgInfo *pkg_info);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include "dynarray.h"
|
||||||
|
|
||||||
|
struct dyn_array {
|
||||||
|
char **array;
|
||||||
|
size_t size;
|
||||||
|
size_t capacity;
|
||||||
|
};
|
||||||
|
|
||||||
|
DynArray *dynarray_init(size_t initial_capacity) {
|
||||||
|
DynArray *da = malloc(sizeof(DynArray));
|
||||||
|
da->size = 0;
|
||||||
|
da->capacity = initial_capacity;
|
||||||
|
|
||||||
|
return da;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dynarray_add(DynArray *da, const char *s) {
|
||||||
|
// An empty dynarray does not have an allocated internal array yet
|
||||||
|
if (da->size == 0) {
|
||||||
|
da->array = malloc(sizeof(char*) * da->capacity);
|
||||||
|
}
|
||||||
|
// Double array size if it's full
|
||||||
|
else if (da->size == da->capacity) {
|
||||||
|
da->array = realloc(da->array, da->capacity * 2);
|
||||||
|
da->capacity *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
da->array[da->size] = strdup(s);
|
||||||
|
da->size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dynarray_free(DynArray *da) {
|
||||||
|
if (da == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (da->array != NULL) {
|
||||||
|
for (size_t i = 0; i < da->size; i++) {
|
||||||
|
free(da->array[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(da->array);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(da);
|
||||||
|
}
|
||||||
|
|
||||||
|
char **dynarray_convert(DynArray *da) {
|
||||||
|
char **array = da->array;
|
||||||
|
|
||||||
|
da->array = NULL;
|
||||||
|
dynarray_free(da);
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
#include "package.h"
|
||||||
|
|
||||||
|
static char *ignored_names[5] = {
|
||||||
|
".BUILDINFO",
|
||||||
|
".INSTALL",
|
||||||
|
".MTREE",
|
||||||
|
".PKGINFO",
|
||||||
|
".CHANGELOG"
|
||||||
|
};
|
||||||
|
static int ignored_words_len = sizeof(ignored_names) / sizeof(char *);
|
||||||
|
|
||||||
|
Pkg *package_init() {
|
||||||
|
return calloc(sizeof(PkgInfo), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pkg *package_read_archive(const char *pkg_path) {
|
||||||
|
struct archive *a = archive_read_new();
|
||||||
|
struct archive_entry *entry = archive_entry_new();
|
||||||
|
|
||||||
|
// These three are the most commonly used compression methods
|
||||||
|
archive_read_support_filter_zstd(a);
|
||||||
|
archive_read_support_filter_gzip(a);
|
||||||
|
archive_read_support_filter_xz(a);
|
||||||
|
|
||||||
|
// Contents should always be a tarball
|
||||||
|
archive_read_support_format_tar(a);
|
||||||
|
|
||||||
|
// TODO where does this 10240 come from?
|
||||||
|
int r = archive_read_open_filename(a, pkg_path, 10240);
|
||||||
|
|
||||||
|
// Exit early if we weren't able to successfully open the archive for reading
|
||||||
|
if (r != ARCHIVE_OK) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int compression_code = archive_filter_code(a, 0);
|
||||||
|
const char *path_name;
|
||||||
|
|
||||||
|
PkgInfo *pkg_info;
|
||||||
|
DynArray *files = dynarray_init(16);
|
||||||
|
|
||||||
|
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
|
||||||
|
path_name = archive_entry_pathname(entry);
|
||||||
|
|
||||||
|
bool ignore = false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ignored_words_len; i++) {
|
||||||
|
if (strcmp(path_name, ignored_names[i]) == 0) {
|
||||||
|
ignore = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ignore) {
|
||||||
|
dynarray_add(files, path_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(path_name, ".PKGINFO") == 0) {
|
||||||
|
// Read data of file into memory buffer
|
||||||
|
int size = archive_entry_size(entry);
|
||||||
|
char *buf = malloc(size);
|
||||||
|
archive_read_data(a, buf, size);
|
||||||
|
|
||||||
|
// Parse package info string into a struct
|
||||||
|
pkg_info = package_info_init();
|
||||||
|
package_info_parse(pkg_info, buf);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
} else {
|
||||||
|
archive_read_data_skip(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get size of file
|
||||||
|
struct stat stats;
|
||||||
|
|
||||||
|
if (stat(pkg_path, &stats) != 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg_info->csize = stats.st_size;
|
||||||
|
|
||||||
|
archive_read_free(a);
|
||||||
|
archive_entry_free(entry);
|
||||||
|
|
||||||
|
// Create final return value
|
||||||
|
Pkg *pkg = package_init();
|
||||||
|
pkg->path = strdup(pkg_path);
|
||||||
|
pkg->info = pkg_info;
|
||||||
|
pkg->files = files;
|
||||||
|
pkg->compression = compression_code;
|
||||||
|
|
||||||
|
return pkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *package_to_description(Pkg *pkg) {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "package_info.h"
|
||||||
|
|
||||||
|
PkgInfo *package_info_init() {
|
||||||
|
return calloc(1, sizeof(PkgInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
void package_info_free(PkgInfo *pkg_info) {
|
||||||
|
FREE_STRING(pkg_info->name);
|
||||||
|
FREE_STRING(pkg_info->base);
|
||||||
|
FREE_STRING(pkg_info->version);
|
||||||
|
FREE_STRING(pkg_info->description);
|
||||||
|
FREE_STRING(pkg_info->url);
|
||||||
|
FREE_STRING(pkg_info->arch);
|
||||||
|
FREE_STRING(pkg_info->packager);
|
||||||
|
FREE_STRING(pkg_info->pgpsig);
|
||||||
|
|
||||||
|
dynarray_free(pkg_info->groups);
|
||||||
|
dynarray_free(pkg_info->licenses);
|
||||||
|
dynarray_free(pkg_info->replaces);
|
||||||
|
dynarray_free(pkg_info->depends);
|
||||||
|
dynarray_free(pkg_info->conflicts);
|
||||||
|
dynarray_free(pkg_info->provides);
|
||||||
|
dynarray_free(pkg_info->optdepends);
|
||||||
|
dynarray_free(pkg_info->makedepends);
|
||||||
|
dynarray_free(pkg_info->checkdepends);
|
||||||
|
|
||||||
|
free(pkg_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advance the pointer until all spaces are skipped.
|
||||||
|
*/
|
||||||
|
static inline char *trim_spaces_front(char *ptr) {
|
||||||
|
while (ptr[0] == ' ') {
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a string pointer in the middle of a string, move over all spaces in the
|
||||||
|
* given direction. The final space is replaced with a NULL-byte.
|
||||||
|
*/
|
||||||
|
static inline void trim_spaces_back(char *ptr) {
|
||||||
|
if (ptr[0] != ' ') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ptr[-1] == ' ') {
|
||||||
|
ptr--;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PKG_INFO_STRING(key, field) if (strcmp(key_ptr, key) == 0) { pkg_info->field = strdup(value_ptr); goto advance; }
|
||||||
|
#define PKG_INFO_INT(key, field) if (strcmp(key_ptr, key) == 0) { pkg_info->field = atoi(value_ptr); goto advance; }
|
||||||
|
#define PKG_INFO_ARRAY(key, field) if (strcmp(key_ptr, key) == 0) { \
|
||||||
|
if (pkg_info->field == NULL) { pkg_info->field = dynarray_init(4); } \
|
||||||
|
dynarray_add(pkg_info->field, value_ptr); goto advance; \
|
||||||
|
}
|
||||||
|
|
||||||
|
int package_info_parse(PkgInfo *pkg_info, char *pkg_info_str) {
|
||||||
|
char *offset_ptr, *equals_ptr, *key_ptr, *value_ptr;
|
||||||
|
|
||||||
|
bool end = false;
|
||||||
|
|
||||||
|
// Iterate over all lines in file
|
||||||
|
while (!end) {
|
||||||
|
// This pointer will always point to the final character of the
|
||||||
|
// current line, be it the position of a newline or the NULL byte at
|
||||||
|
// the end of the entire string
|
||||||
|
offset_ptr = strchr(pkg_info_str, '\n');
|
||||||
|
|
||||||
|
// We replace the newline with a NULL byte. Now we know the line runs
|
||||||
|
// until the next NULL byte.
|
||||||
|
if (offset_ptr != NULL) {
|
||||||
|
offset_ptr[0] = '\0';
|
||||||
|
} else {
|
||||||
|
// Advance pointer to the NULL byte of the string
|
||||||
|
offset_ptr = pkg_info_str + 1;
|
||||||
|
|
||||||
|
while (*offset_ptr != '\0') {
|
||||||
|
offset_ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
end = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip comment lines
|
||||||
|
if (pkg_info_str[0] == '#') {
|
||||||
|
goto advance;
|
||||||
|
}
|
||||||
|
|
||||||
|
equals_ptr = strchr(pkg_info_str, '=');
|
||||||
|
|
||||||
|
// If a line doesn't contain an equals sign, the file is invalid
|
||||||
|
if (equals_ptr == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim whitespace from key
|
||||||
|
key_ptr = trim_spaces_front(pkg_info_str);
|
||||||
|
trim_spaces_back(equals_ptr - 1);
|
||||||
|
|
||||||
|
// Trim spaces from value
|
||||||
|
value_ptr = trim_spaces_front(equals_ptr + 1);
|
||||||
|
trim_spaces_back(offset_ptr - 1);
|
||||||
|
|
||||||
|
// Match key
|
||||||
|
PKG_INFO_STRING("pkgname", name);
|
||||||
|
PKG_INFO_STRING("pkgbase", base);
|
||||||
|
PKG_INFO_STRING("pkgver", version);
|
||||||
|
PKG_INFO_STRING("pkgdesc", description);
|
||||||
|
PKG_INFO_INT("size", size);
|
||||||
|
PKG_INFO_STRING("url", url);
|
||||||
|
PKG_INFO_STRING("arch", arch);
|
||||||
|
PKG_INFO_INT("builddate", build_date);
|
||||||
|
PKG_INFO_STRING("packager", packager);
|
||||||
|
PKG_INFO_STRING("pgpsig", pgpsig);
|
||||||
|
PKG_INFO_INT("pgpsigsize", pgpsigsize);
|
||||||
|
PKG_INFO_ARRAY("group", groups);
|
||||||
|
PKG_INFO_ARRAY("license", licenses);
|
||||||
|
PKG_INFO_ARRAY("replaces", replaces);
|
||||||
|
PKG_INFO_ARRAY("depend", depends);
|
||||||
|
PKG_INFO_ARRAY("optdepend", optdepends);
|
||||||
|
PKG_INFO_ARRAY("makedepend", makedepends);
|
||||||
|
PKG_INFO_ARRAY("checkdepend", checkdepends);
|
||||||
|
|
||||||
|
advance:
|
||||||
|
pkg_info_str = offset_ptr + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue