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.
parent
276fa99e4b
commit
a60c923547
|
@ -33,7 +33,7 @@ typedef struct pkg_info {
|
||||||
} PkgInfo;
|
} PkgInfo;
|
||||||
|
|
||||||
PkgInfo *package_info_init();
|
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);
|
void package_info_free(PkgInfo *pkg_info);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2,6 +2,31 @@
|
||||||
|
|
||||||
#include "package_info.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() {
|
PkgInfo *package_info_init() {
|
||||||
return calloc(1, sizeof(PkgInfo));
|
return calloc(1, sizeof(PkgInfo));
|
||||||
}
|
}
|
||||||
|
@ -29,111 +54,26 @@ void package_info_free(PkgInfo *pkg_info) {
|
||||||
free(pkg_info);
|
free(pkg_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void package_info_parse(PkgInfo *pkg_info, char *pkg_info_str) {
|
||||||
* Advance the pointer until all spaces are skipped.
|
char *value_ptr = pkg_info_str, *tail_ptr;
|
||||||
*/
|
|
||||||
static inline char *trim_spaces_front(char *ptr) {
|
PKG_INFO_STRING("\npkgname = ", name);
|
||||||
while (ptr[0] == ' ') {
|
PKG_INFO_STRING("\npkgbase = ", base);
|
||||||
ptr++;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue