forked from vieter-v/libvieter
refactor: Add original .c package files by Jef.
parent
379a05a7b6
commit
276fa99e4b
|
@ -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