From 4812cde90582c61922035905a9b8b6aab51ebbdf Mon Sep 17 00:00:00 2001 From: GreekStapler Date: Sun, 29 Jan 2023 11:48:59 +0000 Subject: [PATCH] chore: Package module now follows the naming and structure conventions of libvieter. --- include/dynarray.h | 24 -------- include/package.h | 26 -------- include/package_info.h | 39 ------------ include/vieter_package.h | 30 +++++++++ src/package/README.md | 5 ++ {include => src/package}/sha256.h | 0 src/package/{package.c => vieter_package.c} | 51 ++++++++-------- .../{dynarray.c => vieter_package_dynarray.c} | 14 ++--- src/package/vieter_package_dynarray.h | 36 +++++++++++ .../{package_info.c => vieter_package_info.c} | 54 ++++++++-------- src/package/vieter_package_info.h | 52 ++++++++++++++++ src/package/vieter_package_internal.h | 10 +++ test/package/test_package.c | 61 ++++++++++--------- 13 files changed, 224 insertions(+), 178 deletions(-) delete mode 100644 include/dynarray.h delete mode 100644 include/package.h delete mode 100644 include/package_info.h create mode 100644 include/vieter_package.h create mode 100644 src/package/README.md rename {include => src/package}/sha256.h (100%) rename src/package/{package.c => vieter_package.c} (81%) rename src/package/{dynarray.c => vieter_package_dynarray.c} (67%) create mode 100644 src/package/vieter_package_dynarray.h rename src/package/{package_info.c => vieter_package_info.c} (59%) create mode 100644 src/package/vieter_package_info.h create mode 100644 src/package/vieter_package_internal.h diff --git a/include/dynarray.h b/include/dynarray.h deleted file mode 100644 index 2ab4022..0000000 --- a/include/dynarray.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef VIETER_DYNARRAY -#define VIETER_DYNARRAY - -#include -#include - -typedef struct dyn_array DynArray; -struct dyn_array { - char **array; - size_t capacity; - size_t size; -}; - -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 diff --git a/include/package.h b/include/package.h deleted file mode 100644 index 0360a6a..0000000 --- a/include/package.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef VIETER_PACKAGE -#define VIETER_PACKAGE - -#include -#include -#include -#include - -#include -#include - -#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 diff --git a/include/package_info.h b/include/package_info.h deleted file mode 100644 index b1388a2..0000000 --- a/include/package_info.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef VIETER_PACKAGE_INFO -#define VIETER_PACKAGE_INFO - -#define FREE_STRING(sp) if (sp != NULL) free(sp) - -#include - -#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 diff --git a/include/vieter_package.h b/include/vieter_package.h new file mode 100644 index 0000000..ebe6487 --- /dev/null +++ b/include/vieter_package.h @@ -0,0 +1,30 @@ +#ifndef VIETER_PACKAGE +#define VIETER_PACKAGE + +#include +#include +#include +#include + +#include +#include + +typedef struct pkg Pkg; + +/* + * Parse package file into something usable by libvieter. + * The pointer returned by this function will need to freed at a later point. + */ +Pkg *vieter_package_read_archive(const char *pkg_path); + +/* + * Deallocate a package. + */ +void vieter_package_free(Pkg ** ptp); + +/* + * Create string that will become the package's desc file. + */ +char *vieter_package_to_description(Pkg *pkg); + +#endif diff --git a/src/package/README.md b/src/package/README.md new file mode 100644 index 0000000..b2bcbd7 --- /dev/null +++ b/src/package/README.md @@ -0,0 +1,5 @@ +# package + +This module handles both parsing the published Arch tarballs & the contents of +their `.PKGINFO` files, as well as generating the contents of the database +archives' `desc` & `files` files. diff --git a/include/sha256.h b/src/package/sha256.h similarity index 100% rename from include/sha256.h rename to src/package/sha256.h diff --git a/src/package/package.c b/src/package/vieter_package.c similarity index 81% rename from src/package/package.c rename to src/package/vieter_package.c index 577e3c9..a3d2cd6 100644 --- a/src/package/package.c +++ b/src/package/vieter_package.c @@ -1,25 +1,25 @@ -#include "package.h" +#include "vieter_package_internal.h" #include "sha256.h" #define SMALL_BUFF_SIZE 128 -#define ADD_STRING(section, field) if (pkg_info->field != 0) { \ - snprintf(aux, SMALL_BUFF_SIZE, section, pkg_info->field); \ +#define ADD_STRING(section, field) if (info->field != 0) { \ + snprintf(aux, SMALL_BUFF_SIZE, section, info->field); \ if (buff_size < strlen(description) + SMALL_BUFF_SIZE + 1) { \ description = realloc(description, buff_size * 2); \ buff_size *= 2; \ } \ strcat(description, aux); \ } -#define ADD_ARRAY(section, field) i = 0; if (pkg_info->field != NULL) { \ - snprintf(aux, SMALL_BUFF_SIZE, section, pkg_info->field->array[i]); i++; \ +#define ADD_ARRAY(section, field) i = 0; if (info->field != NULL) { \ + snprintf(aux, SMALL_BUFF_SIZE, section, info->field->array[i]); i++; \ if (buff_size < strlen(description) + SMALL_BUFF_SIZE + 1) { \ description = realloc(description, buff_size * 2); \ buff_size *= 2; \ } \ strcat(description, aux); \ - while (pkg_info->field->array[i] != NULL) { \ - snprintf(aux, SMALL_BUFF_SIZE, "\n%s", pkg_info->field->array[i]); i++; \ + while (info->field->array[i] != NULL) { \ + snprintf(aux, SMALL_BUFF_SIZE, "\n%s", info->field->array[i]); i++; \ if (buff_size < strlen(description) + SMALL_BUFF_SIZE + 1) { \ description = realloc(description, buff_size * 2); \ buff_size *= 2; \ @@ -37,11 +37,11 @@ static char *ignored_names[5] = { }; static size_t ignored_words_len = sizeof(ignored_names) / sizeof(char *); -Pkg *package_init() { - return calloc(sizeof(PkgInfo), 1); +Pkg *vieter_package_init() { + return calloc(sizeof(pkg_info), 1); } -Pkg *package_read_archive(const char *pkg_path) { +Pkg *vieter_package_read_archive(const char *pkg_path) { struct archive *a = archive_read_new(); struct archive_entry *entry = archive_entry_new(); @@ -64,9 +64,9 @@ Pkg *package_read_archive(const char *pkg_path) { int compression_code = archive_filter_code(a, 0); const char *path_name; - PkgInfo *pkg_info; - DynArray *files = dynarray_init(16); - dynarray_add(files, "%FILES%"); + pkg_info *info; + dynarray *files = vieter_package_dynarray_init(16); + vieter_package_dynarray_add(files, "%FILES%"); while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { path_name = archive_entry_pathname(entry); @@ -81,7 +81,7 @@ Pkg *package_read_archive(const char *pkg_path) { } if (!ignore) { - dynarray_add(files, path_name); + vieter_package_dynarray_add(files, path_name); } if (strcmp(path_name, ".PKGINFO") == 0) { @@ -91,8 +91,8 @@ Pkg *package_read_archive(const char *pkg_path) { archive_read_data(a, buf, size); // Parse package info string into a struct - pkg_info = package_info_init(); - package_info_parse(pkg_info, buf); + info = vieter_package_info_init(); + vieter_package_info_parse(info, buf); free(buf); } else { @@ -107,21 +107,21 @@ Pkg *package_read_archive(const char *pkg_path) { return NULL; } - pkg_info->csize = stats.st_size; + info->csize = stats.st_size; archive_read_free(a); // Create final return value - Pkg *pkg = package_init(); + Pkg *pkg = vieter_package_init(); pkg->path = strdup(pkg_path); - pkg->info = pkg_info; + pkg->info = info; pkg->files = files; pkg->compression = compression_code; return pkg; } -void sha256sum(Pkg *pkg, char *res) { +void vieter_package_sha256sum(Pkg *pkg, char *res) { FILE *f = fopen(pkg->path, "r"); fseek(f, 0, SEEK_END); size_t size = ftell(f); @@ -170,18 +170,19 @@ void sha256sum(Pkg *pkg, char *res) { res[j] = '\0'; } -char *package_to_description(Pkg *pkg) { - PkgInfo *pkg_info = pkg->info; +char *vieter_package_to_description(Pkg *pkg) { + pkg_info *info = pkg->info; size_t buff_size = 1024; char aux[SMALL_BUFF_SIZE]; char *description = malloc(sizeof(char) * buff_size); + // Helper variable for ADD_ARRAY macro int i; // special case for FILENAME // assuming .pkg.tar.zst; other formats are valid, this should account for that - snprintf(aux, SMALL_BUFF_SIZE, "%%FILENAME%%\n%s-%s-%s.pkg.tar.zst", pkg_info->name, pkg_info->version, - pkg_info->arch); + snprintf(aux, SMALL_BUFF_SIZE, "%%FILENAME%%\n%s-%s-%s.pkg.tar.zst", info->name, info->version, + info->arch); strcpy(description, aux); ADD_STRING("\n\n%%NAME%%\n%s", name); @@ -193,7 +194,7 @@ char *package_to_description(Pkg *pkg) { ADD_STRING("\n\n%%ISIZE%%\n%ld", size); char checksum[65]; - sha256sum(pkg, checksum); + vieter_package_sha256sum(pkg, checksum); snprintf(aux, SMALL_BUFF_SIZE, "\n\n%%SHA256SUM%%\n%s", checksum); if (buff_size < strlen(description) + SMALL_BUFF_SIZE + 1) { diff --git a/src/package/dynarray.c b/src/package/vieter_package_dynarray.c similarity index 67% rename from src/package/dynarray.c rename to src/package/vieter_package_dynarray.c index a78e7ff..4f23cbb 100644 --- a/src/package/dynarray.c +++ b/src/package/vieter_package_dynarray.c @@ -1,14 +1,14 @@ -#include "dynarray.h" +#include "vieter_package_dynarray.h" -DynArray *dynarray_init(size_t initial_capacity) { - DynArray *da = malloc(sizeof(DynArray)); +dynarray *vieter_package_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) { +void vieter_package_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); @@ -24,7 +24,7 @@ void dynarray_add(DynArray *da, const char *s) { da->size++; } -void dynarray_free(DynArray *da) { +void vieter_package_dynarray_free(dynarray *da) { if (da == NULL) { return; } @@ -40,11 +40,11 @@ void dynarray_free(DynArray *da) { free(da); } -char **dynarray_convert(DynArray *da) { +char **vieter_package_dynarray_convert(dynarray *da) { char **array = da->array; da->array = NULL; - dynarray_free(da); + vieter_package_dynarray_free(da); return array; } diff --git a/src/package/vieter_package_dynarray.h b/src/package/vieter_package_dynarray.h new file mode 100644 index 0000000..0a96de0 --- /dev/null +++ b/src/package/vieter_package_dynarray.h @@ -0,0 +1,36 @@ +#ifndef VIETER_DYNARRAY +#define VIETER_DYNARRAY + +#include +#include +#include "vieter_package.h" + +typedef struct dynarray dynarray; +struct dynarray { + char **array; + size_t capacity; + size_t size; +}; + +/* + * Allocate a dynamic array. + */ +dynarray *vieter_package_dynarray_init(size_t initial_capacity); + +/* + * Initialise array (if it's not already initialised) and insert a string. + */ +void vieter_package_dynarray_add(dynarray *da, const char * s); + +/* + * Deallocate dynamic array. + */ +void vieter_package_dynarray_free(dynarray *da); + +/* + * Convert a dynarray into an array by freeing all its surrounding components + * and returning the underlying array pointer. + */ +char **vieter_package_dynarray_convert(dynarray *da); + +#endif diff --git a/src/package/package_info.c b/src/package/vieter_package_info.c similarity index 59% rename from src/package/package_info.c rename to src/package/vieter_package_info.c index 5e1986d..b897685 100644 --- a/src/package/package_info.c +++ b/src/package/vieter_package_info.c @@ -1,19 +1,19 @@ #include -#include "package_info.h" +#include "vieter_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); \ + 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); \ + info->field = atoi(value_ptr); \ tail_ptr[0] = '\n'; \ value_ptr = tail_ptr; @@ -21,40 +21,40 @@ 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); \ + if(info->field == NULL) { info->field = vieter_package_dynarray_init(4); } \ + vieter_package_dynarray_add(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)); +pkg_info *vieter_package_info_init() { + return calloc(1, sizeof(pkg_info)); } -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); +void vieter_package_info_free(pkg_info *info) { + FREE_STRING(info->name); + FREE_STRING(info->base); + FREE_STRING(info->version); + FREE_STRING(info->description); + FREE_STRING(info->url); + FREE_STRING(info->arch); + FREE_STRING(info->packager); + FREE_STRING(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); + vieter_package_dynarray_free(info->groups); + vieter_package_dynarray_free(info->licenses); + vieter_package_dynarray_free(info->replaces); + vieter_package_dynarray_free(info->depends); + vieter_package_dynarray_free(info->conflicts); + vieter_package_dynarray_free(info->provides); + vieter_package_dynarray_free(info->optdepends); + vieter_package_dynarray_free(info->makedepends); + vieter_package_dynarray_free(info->checkdepends); - free(pkg_info); + free(info); } -void package_info_parse(PkgInfo *pkg_info, char *pkg_info_str) { +void vieter_package_info_parse(pkg_info *info, char *pkg_info_str) { char *value_ptr = pkg_info_str, *tail_ptr; PKG_INFO_STRING("\npkgname = ", name); diff --git a/src/package/vieter_package_info.h b/src/package/vieter_package_info.h new file mode 100644 index 0000000..fc9f411 --- /dev/null +++ b/src/package/vieter_package_info.h @@ -0,0 +1,52 @@ +#ifndef VIETER_PACKAGE_INFO +#define VIETER_PACKAGE_INFO + +#define FREE_STRING(sp) if (sp != NULL) free(sp) + +#include + +#include "vieter_package.h" +#include "vieter_package_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; +} pkg_info; + +/* + * Allocate and initialise a pkg_info pointer to hold .PKGINFO. + */ +pkg_info *vieter_package_info_init(); + +/* + * Parse .PKGINFO file into something usable by libvieter. + */ +void vieter_package_info_parse(pkg_info *info, char *pkg_info_str); + +/* + * Deallocate a pkg_info pointer. + */ +void vieter_package_info_free(pkg_info *info); + +#endif diff --git a/src/package/vieter_package_internal.h b/src/package/vieter_package_internal.h new file mode 100644 index 0000000..c13278e --- /dev/null +++ b/src/package/vieter_package_internal.h @@ -0,0 +1,10 @@ +#include "vieter_package.h" +#include "vieter_package_info.h" +#include "vieter_package_dynarray.h" + +struct pkg { + char *path; + pkg_info *info; + dynarray *files; + int compression; +}; diff --git a/test/package/test_package.c b/test/package/test_package.c index c0c7085..a79d5df 100644 --- a/test/package/test_package.c +++ b/test/package/test_package.c @@ -1,7 +1,7 @@ #include "acutest.h" -#include "package.h" +#include "vieter_package_internal.h" -void test_pkg_info_parse() { +void test_info_parse() { FILE *f = fopen("./test/package/.PKGINFO", "r"); TEST_ASSERT_(f != NULL, "could not find test .PKGINFO file in ./test/package "); fseek(f, 0L, SEEK_END); @@ -11,34 +11,35 @@ void test_pkg_info_parse() { char *pkg_info_str = malloc(size); fread(pkg_info_str, 1, size, f); fclose(f); - PkgInfo *pkg_info = package_info_init(); - package_info_parse(pkg_info, pkg_info_str); - TEST_CHECK(!strcmp(pkg_info->name, "xcursor-dmz")); - TEST_CHECK(!strcmp(pkg_info->base, "xcursor-dmz")); - TEST_CHECK(!strcmp(pkg_info->version, "0.4.5-2")); - TEST_CHECK(!strcmp(pkg_info->description, "Style neutral, scalable cursor theme")); - TEST_CHECK(!strcmp(pkg_info->url, "https://packages.debian.org/sid/dmz-cursor-theme")); - TEST_CHECK(pkg_info->build_date == 1673751613); - TEST_CHECK(!strcmp(pkg_info->packager, "Unknown Packager")); - TEST_CHECK(pkg_info->size == 3469584); - TEST_CHECK(!strcmp(pkg_info->arch, "any")); + pkg_info *info = vieter_package_info_init(); + vieter_package_info_parse(info, pkg_info_str); - TEST_CHECK(!strcmp(pkg_info->licenses->array[0], "MIT")); - TEST_CHECK(!strcmp(pkg_info->replaces->array[0], "test1")); - TEST_CHECK(!strcmp(pkg_info->groups->array[0], "x11")); - TEST_CHECK(!strcmp(pkg_info->conflicts->array[0], "test2")); - TEST_CHECK(!strcmp(pkg_info->conflicts->array[1], "test3")); - TEST_CHECK(!strcmp(pkg_info->provides->array[0], "test4")); - TEST_CHECK(!strcmp(pkg_info->depends->array[0], "test5")); - TEST_CHECK(!strcmp(pkg_info->depends->array[1], "test6")); - TEST_CHECK(!strcmp(pkg_info->optdepends->array[0], "test7")); - TEST_CHECK(!strcmp(pkg_info->makedepends->array[0], "xorg-xcursorgen")); - TEST_CHECK(!strcmp(pkg_info->checkdepends->array[0], "test8")); + TEST_CHECK(!strcmp(info->name, "xcursor-dmz")); + TEST_CHECK(!strcmp(info->base, "xcursor-dmz")); + TEST_CHECK(!strcmp(info->version, "0.4.5-2")); + TEST_CHECK(!strcmp(info->description, "Style neutral, scalable cursor theme")); + TEST_CHECK(!strcmp(info->url, "https://packages.debian.org/sid/dmz-cursor-theme")); + TEST_CHECK(info->build_date == 1673751613); + TEST_CHECK(!strcmp(info->packager, "Unknown Packager")); + TEST_CHECK(info->size == 3469584); + TEST_CHECK(!strcmp(info->arch, "any")); + + TEST_CHECK(!strcmp(info->licenses->array[0], "MIT")); + TEST_CHECK(!strcmp(info->replaces->array[0], "test1")); + TEST_CHECK(!strcmp(info->groups->array[0], "x11")); + TEST_CHECK(!strcmp(info->conflicts->array[0], "test2")); + TEST_CHECK(!strcmp(info->conflicts->array[1], "test3")); + TEST_CHECK(!strcmp(info->provides->array[0], "test4")); + TEST_CHECK(!strcmp(info->depends->array[0], "test5")); + TEST_CHECK(!strcmp(info->depends->array[1], "test6")); + TEST_CHECK(!strcmp(info->optdepends->array[0], "test7")); + TEST_CHECK(!strcmp(info->makedepends->array[0], "xorg-xcursorgen")); + TEST_CHECK(!strcmp(info->checkdepends->array[0], "test8")); } void test_pkg_read_archive_files() { - Pkg *pkg = package_read_archive("./test/package/xcursor-dmz-0.4.5-2-any.pkg.tar.zst"); + Pkg *pkg = vieter_package_read_archive("./test/package/xcursor-dmz-0.4.5-2-any.pkg.tar.zst"); TEST_ASSERT_(pkg != NULL, "failure parsing pkg archive"); FILE *f = fopen("./test/package/files", "r"); @@ -59,10 +60,10 @@ void test_pkg_read_archive_files() { } void test_pkg_read_archive_desc() { - Pkg *pkg = package_read_archive("./test/package/xcursor-dmz-0.4.5-2-any.pkg.tar.zst"); + Pkg *pkg = vieter_package_read_archive("./test/package/xcursor-dmz-0.4.5-2-any.pkg.tar.zst"); TEST_ASSERT_(pkg != NULL, "failure parsing pkg archive"); - char *description = package_to_description(pkg); + char *description = vieter_package_to_description(pkg); FILE *f = fopen("./test/package/desc", "r"); TEST_ASSERT_(f != NULL, "could not find test desc file in ./test/package"); @@ -77,8 +78,8 @@ void test_pkg_read_archive_desc() { } TEST_LIST = { - {"pkg_info_valid_parse", test_pkg_info_parse}, - {"pkg_read_archive_files", test_pkg_read_archive_files}, - {"pkg_read_archive_desc", test_pkg_read_archive_desc}, + {".PKGINFO parse", test_info_parse}, + {"files array creation", test_pkg_read_archive_files}, + {"desc file creation", test_pkg_read_archive_desc}, {NULL, NULL} };