Compare commits

..

2 Commits

Author SHA1 Message Date
GreekStapler d252c55fb0 refactor: Modified .PKGINFO parser not to rely on gotos and continues. Parser is now optimistic and assumes .PKGINFO file is valid.
After my changes to the macros, they still feel a bit hacky, but I'm content with them. I also changed the parser to assume the .PKGINFO files are always valid because they are automatically generated. The parser also assumes the same fields will always appear in the same fixed order. I made this change after checking how makepkg generated this file.
2023-01-25 16:22:22 +01:00
GreekStapler cc3cacc1f7 refactor: Add original .c package files by Jef. 2023-01-25 13:00:33 +01:00
6 changed files with 316 additions and 0 deletions

19
include/dynarray.h 100644
View File

@ -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

26
include/package.h 100644
View File

@ -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

View File

@ -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();
void package_info_parse(PkgInfo *pkg_info, char *pkg_info_str);
void package_info_free(PkgInfo *pkg_info);
#endif

View File

@ -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;
}

View File

@ -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) {
}

View File

@ -0,0 +1,79 @@
#include <stdbool.h>
#include "package_info.h"
#define PKG_INFO_STRING(key_ptr, field) if ((value_ptr = strstr(value_ptr, key_ptr)) != NULL) { \
value_ptr += strlen(key_ptr);\
tail_ptr = strchr(value_ptr, '\n');\
tail_ptr[0] = '\0'; \
pkg_info->field = strdup(value_ptr); \
tail_ptr[0] = '\n'; \
} value_ptr = tail_ptr;
#define PKG_INFO_INT(key_ptr, field) value_ptr = strstr(value_ptr, key_ptr) + strlen(key_ptr);\
tail_ptr = strchr(value_ptr, '\n');\
tail_ptr[0] = '\0'; \
pkg_info->field = atoi(value_ptr); \
tail_ptr[0] = '\n'; \
value_ptr = tail_ptr;
#define PKG_INFO_ARRAY(key_ptr, field) while((value_ptr = strstr(value_ptr, key_ptr)) != NULL){ \
value_ptr = value_ptr + strlen(key_ptr);\
tail_ptr = strchr(value_ptr, '\n'); \
tail_ptr[0] = '\0'; \
if(pkg_info->field == NULL) { pkg_info->field = dynarray_init(4); } \
dynarray_add(pkg_info->field, value_ptr); \
tail_ptr[0] = '\n'; \
value_ptr = tail_ptr;\
} value_ptr = tail_ptr;
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);
}
void package_info_parse(PkgInfo *pkg_info, char *pkg_info_str) {
char *value_ptr = pkg_info_str, *tail_ptr;
PKG_INFO_STRING("\npkgname = ", name);
PKG_INFO_STRING("\npkgbase = ", base);
PKG_INFO_STRING("\npkgver = ", version);
PKG_INFO_STRING("\npkgdesc = ", description);
PKG_INFO_STRING("\nurl = ", url);
PKG_INFO_INT("\nbuilddate = ", build_date);
PKG_INFO_STRING("\npackager = ", packager);
PKG_INFO_INT("\nsize = ", size);
PKG_INFO_STRING("\narch = ", arch);
PKG_INFO_ARRAY("\nlicense = ", licenses);
PKG_INFO_ARRAY("\nreplaces = ", replaces);
PKG_INFO_ARRAY("\ngroup = ", groups);
PKG_INFO_ARRAY("\nconflict = ", conflicts);
PKG_INFO_ARRAY("\nprovides = ", provides);
PKG_INFO_ARRAY("\ndepend = ", depends);
PKG_INFO_ARRAY("\noptdepend = ", optdepends);
PKG_INFO_ARRAY("\nmakedepend = ", makedepends);
PKG_INFO_ARRAY("\ncheckdepend = ", checkdepends);
}