#include #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; }