From 4309ad8cc5151dca6a259519bfe68cfc8a5ac6aa Mon Sep 17 00:00:00 2001 From: GreekStapler Date: Wed, 25 Jan 2023 16:22:22 +0100 Subject: [PATCH] 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. --- include/package_info.h | 2 +- src/package/package_info.c | 152 +++++++++++-------------------------- 2 files changed, 47 insertions(+), 107 deletions(-) diff --git a/include/package_info.h b/include/package_info.h index d71386e..b1388a2 100644 --- a/include/package_info.h +++ b/include/package_info.h @@ -33,7 +33,7 @@ typedef struct pkg_info { } PkgInfo; PkgInfo *package_info_init(); -int package_info_parse(PkgInfo *pkg_info, char *pkg_info_str); +void package_info_parse(PkgInfo *pkg_info, char *pkg_info_str); void package_info_free(PkgInfo *pkg_info); #endif diff --git a/src/package/package_info.c b/src/package/package_info.c index 1202485..5e1986d 100644 --- a/src/package/package_info.c +++ b/src/package/package_info.c @@ -2,6 +2,31 @@ #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)); } @@ -29,111 +54,26 @@ void package_info_free(PkgInfo *pkg_info) { free(pkg_info); } -/** - * Advance the pointer until all spaces are skipped. - */ -static inline char *trim_spaces_front(char *ptr) { - while (ptr[0] == ' ') { - ptr++; - } +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); - 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; }