Fix parsing of Conffiles lines in status files.
[oweals/opkg-lede.git] / libopkg / pkg.c
index 93fd20aa9842bca54a88c3bea351c57b5c9d4e8c..9ba44e82eafa71493952f3132bae8ea2f844fe57 100644 (file)
@@ -1,4 +1,4 @@
-/* pkg.c - the itsy package management system
+/* pkg.c - the opkg package management system
 
    Carl D. Worth
 
 
    Carl D. Worth
 
    General Public License for more details.
 */
 
    General Public License for more details.
 */
 
-#include "opkg.h"
+#include "includes.h"
 #include <ctype.h>
 #include <ctype.h>
+#include <alloca.h>
 #include <string.h>
 #include <string.h>
+#include <stdbool.h>
 #include <errno.h>
 
 #include "pkg.h"
 #include <errno.h>
 
 #include "pkg.h"
@@ -27,6 +29,7 @@
 #include "opkg_message.h"
 #include "opkg_utils.h"
 
 #include "opkg_message.h"
 #include "opkg_utils.h"
 
+#include "libbb/libbb.h"
 #include "sprintf_alloc.h"
 #include "file_util.h"
 #include "str_util.h"
 #include "sprintf_alloc.h"
 #include "file_util.h"
 #include "str_util.h"
@@ -76,12 +79,7 @@ pkg_t *pkg_new(void)
 {
      pkg_t *pkg;
 
 {
      pkg_t *pkg;
 
-     pkg = malloc(sizeof(pkg_t));
-     if (pkg == NULL) {
-         fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-         return NULL;
-     }
-
+     pkg = xcalloc(1, sizeof(pkg_t));
      pkg_init(pkg);
 
      return pkg;
      pkg_init(pkg);
 
      return pkg;
@@ -89,12 +87,10 @@ pkg_t *pkg_new(void)
 
 int pkg_init(pkg_t *pkg)
 {
 
 int pkg_init(pkg_t *pkg)
 {
-     memset(pkg, 0, sizeof(pkg_t));
      pkg->name = NULL;
      pkg->epoch = 0;
      pkg->version = NULL;
      pkg->revision = NULL;
      pkg->name = NULL;
      pkg->epoch = 0;
      pkg->version = NULL;
      pkg->revision = NULL;
-     pkg->familiar_revision = NULL;
      pkg->dest = NULL;
      pkg->src = NULL;
      pkg->architecture = NULL;
      pkg->dest = NULL;
      pkg->src = NULL;
      pkg->architecture = NULL;
@@ -112,6 +108,8 @@ int pkg_init(pkg_t *pkg)
      pkg->recommends_str = NULL;
      pkg->suggests_count = 0;
      pkg->recommends_count = 0;
      pkg->recommends_str = NULL;
      pkg->suggests_count = 0;
      pkg->recommends_count = 0;
+     
+     active_list_init(&pkg->list);
 
      /* Abhaya: added init for conflicts fields */
      pkg->conflicts = NULL;
 
      /* Abhaya: added init for conflicts fields */
      pkg->conflicts = NULL;
@@ -129,6 +127,9 @@ int pkg_init(pkg_t *pkg)
      pkg->local_filename = NULL;
      pkg->tmp_unpack_dir = NULL;
      pkg->md5sum = NULL;
      pkg->local_filename = NULL;
      pkg->tmp_unpack_dir = NULL;
      pkg->md5sum = NULL;
+#if defined HAVE_SHA256
+     pkg->sha256sum = NULL;
+#endif
      pkg->size = NULL;
      pkg->installed_size = NULL;
      pkg->priority = NULL;
      pkg->size = NULL;
      pkg->installed_size = NULL;
      pkg->priority = NULL;
@@ -142,90 +143,194 @@ int pkg_init(pkg_t *pkg)
      return 0;
 }
 
      return 0;
 }
 
+void compound_depend_deinit (compound_depend_t *depends)
+{
+    int i;
+    for (i = 0; i < depends->possibility_count; i++)
+    {
+        depend_t *d;
+        d = depends->possibilities[i];
+        free (d->version);
+        free (d);
+    }
+    free (depends->possibilities);
+}
+
 void pkg_deinit(pkg_t *pkg)
 {
 void pkg_deinit(pkg_t *pkg)
 {
-     free(pkg->name);
-     pkg->name = NULL;
-     pkg->epoch = 0;
-     free(pkg->version);
-     pkg->version = NULL;
-     /* revision and familiar_revision share storage with version, so
-       don't free */
-     pkg->revision = NULL;
-     pkg->familiar_revision = NULL;
-     /* owned by opkg_conf_t */
-     pkg->dest = NULL;
-     /* owned by opkg_conf_t */
-     pkg->src = NULL;
-     free(pkg->architecture);
-     pkg->architecture = NULL;
-     free(pkg->maintainer);
-     pkg->maintainer = NULL;
-     free(pkg->section);
-     pkg->section = NULL;
-     free(pkg->description);
-     pkg->description = NULL;
-     pkg->state_want = SW_UNKNOWN;
-     pkg->state_flag = SF_OK;
-     pkg->state_status = SS_NOT_INSTALLED;
-     free(pkg->depends_str);
-     pkg->depends_str = NULL;
-     free(pkg->provides_str);
-     pkg->provides_str = NULL;
-     pkg->depends_count = 0;
-     /* XXX: CLEANUP: MEMORY_LEAK: how to free up pkg->depends ? */
-     pkg->pre_depends_count = 0;
-     free(pkg->pre_depends_str);
-     pkg->pre_depends_str = NULL;
-     pkg->provides_count = 0;
-     /* XXX: CLEANUP: MEMORY_LEAK: how to free up pkg->provides ? */
-     /* XXX: CLEANUP: MEMORY_LEAK: how to free up pkg->suggests ? */
-     free(pkg->filename);
-     pkg->filename = NULL;
-     free(pkg->local_filename);
-     pkg->local_filename = NULL;
+       int i;
+
+       if (pkg->name)
+               free(pkg->name);
+       pkg->name = NULL;
+
+       pkg->epoch = 0;
+
+       if (pkg->version)
+               free(pkg->version);
+       pkg->version = NULL;
+       /* revision shares storage with version, so don't free */
+       pkg->revision = NULL;
+
+       /* owned by opkg_conf_t */
+       pkg->dest = NULL;
+       /* owned by opkg_conf_t */
+       pkg->src = NULL;
+
+       if (pkg->architecture)
+               free(pkg->architecture);
+       pkg->architecture = NULL;
+
+       if (pkg->maintainer)
+               free(pkg->maintainer);
+       pkg->maintainer = NULL;
+
+       if (pkg->section)
+               free(pkg->section);
+       pkg->section = NULL;
+
+       if (pkg->description)
+               free(pkg->description);
+       pkg->description = NULL;
+       
+       pkg->state_want = SW_UNKNOWN;
+       pkg->state_flag = SF_OK;
+       pkg->state_status = SS_NOT_INSTALLED;
+
+       active_list_clear(&pkg->list);
+
+       if (pkg->replaces)
+               free (pkg->replaces);
+       pkg->replaces = NULL;
+
+       for (i = 0; i < pkg->depends_count; i++)
+               free (pkg->depends_str[i]);
+       free(pkg->depends_str);
+       pkg->depends_str = NULL;
+
+       for (i = 0; i < pkg->provides_count-1; i++)
+               free (pkg->provides_str[i]);
+       free(pkg->provides_str);
+       pkg->provides_str = NULL;
+
+       for (i = 0; i < pkg->conflicts_count; i++)
+               free (pkg->conflicts_str[i]);
+       free(pkg->conflicts_str);
+       pkg->conflicts_str = NULL;
+
+       for (i = 0; i < pkg->replaces_count; i++)
+               free (pkg->replaces_str[i]);
+       free(pkg->replaces_str);
+       pkg->replaces_str = NULL;
+
+       for (i = 0; i < pkg->recommends_count; i++)
+               free (pkg->recommends_str[i]);
+       free(pkg->recommends_str);
+       pkg->recommends_str = NULL;
+
+       for (i = 0; i < pkg->suggests_count; i++)
+               free (pkg->suggests_str[i]);
+       free(pkg->suggests_str);
+       pkg->suggests_str = NULL;
+
+       if (pkg->depends) {
+               int count = pkg->pre_depends_count
+                               + pkg->depends_count
+                               + pkg->recommends_count
+                               + pkg->suggests_count;
+
+               for (i=0; i<count; i++)
+                       compound_depend_deinit (&pkg->depends[i]);
+               free (pkg->depends);
+       }
+
+       if (pkg->conflicts) {
+               for (i=0; i<pkg->conflicts_count; i++)
+                       compound_depend_deinit (&pkg->conflicts[i]);
+               free (pkg->conflicts);
+       }
+
+       if (pkg->provides)
+               free (pkg->provides);
+
+       pkg->pre_depends_count = 0;
+       if (pkg->pre_depends_str)
+               free(pkg->pre_depends_str);
+       pkg->pre_depends_str = NULL;
+       
+       pkg->provides_count = 0;
+       
+       if (pkg->filename)
+               free(pkg->filename);
+       pkg->filename = NULL;
+       
+       if (pkg->local_filename)
+               free(pkg->local_filename);
+       pkg->local_filename = NULL;
+
      /* CLEANUP: It'd be nice to pullin the cleanup function from
        opkg_install.c here. See comment in
        opkg_install.c:cleanup_temporary_files */
      /* CLEANUP: It'd be nice to pullin the cleanup function from
        opkg_install.c here. See comment in
        opkg_install.c:cleanup_temporary_files */
-     free(pkg->tmp_unpack_dir);
-     pkg->tmp_unpack_dir = NULL;
-     free(pkg->md5sum);
-     pkg->md5sum = NULL;
-     free(pkg->size);
-     pkg->size = NULL;
-     free(pkg->installed_size);
-     pkg->installed_size = NULL;
-     free(pkg->priority);
-     pkg->priority = NULL;
-     free(pkg->source);
-     pkg->source = NULL;
-     conffile_list_deinit(&pkg->conffiles);
-     /* XXX: QUESTION: Is forcing this to 1 correct? I suppose so,
+       if (pkg->tmp_unpack_dir)
+               free(pkg->tmp_unpack_dir);
+       pkg->tmp_unpack_dir = NULL;
+
+       if (pkg->md5sum)
+               free(pkg->md5sum);
+       pkg->md5sum = NULL;
+
+#if defined HAVE_SHA256
+       if (pkg->sha256sum)
+               free(pkg->sha256sum);
+       pkg->sha256sum = NULL;
+#endif
+
+       if (pkg->size)
+               free(pkg->size);
+       pkg->size = NULL;
+
+       if (pkg->installed_size)
+               free(pkg->installed_size);
+       pkg->installed_size = NULL;
+
+       if (pkg->priority)
+               free(pkg->priority);
+       pkg->priority = NULL;
+
+       if (pkg->source)
+               free(pkg->source);
+       pkg->source = NULL;
+
+       conffile_list_deinit(&pkg->conffiles);
+
+       /* XXX: QUESTION: Is forcing this to 1 correct? I suppose so,
        since if they are calling deinit, they should know. Maybe do an
        assertion here instead? */
        since if they are calling deinit, they should know. Maybe do an
        assertion here instead? */
-     pkg->installed_files_ref_cnt = 1;
-     pkg_free_installed_files(pkg);
-     pkg->essential = 0;
+       pkg->installed_files_ref_cnt = 1;
+       pkg_free_installed_files(pkg);
+       pkg->essential = 0;
+
+       if (pkg->tags)
+               free (pkg->tags);
+       pkg->tags = NULL;
 }
 
 int pkg_init_from_file(pkg_t *pkg, const char *filename)
 {
      int err;
 }
 
 int pkg_init_from_file(pkg_t *pkg, const char *filename)
 {
      int err;
-     char **raw;
      FILE *control_file;
 
      err = pkg_init(pkg);
      if (err) { return err; }
 
      FILE *control_file;
 
      err = pkg_init(pkg);
      if (err) { return err; }
 
-     pkg->local_filename = strdup(filename);
+     pkg->local_filename = xstrdup(filename);
     
      control_file = tmpfile();
      err = pkg_extract_control_file_to_stream(pkg, control_file);
      if (err) { return err; }
 
      rewind(control_file);
     
      control_file = tmpfile();
      err = pkg_extract_control_file_to_stream(pkg, control_file);
      if (err) { return err; }
 
      rewind(control_file);
-     raw = read_raw_pkgs_from_stream(control_file);
-     pkg_parse_raw(pkg, &raw, NULL, NULL);
+     pkg_parse_from_stream(pkg, control_file, PFM_ALL);
 
      fclose(control_file);
 
 
      fclose(control_file);
 
@@ -251,15 +356,15 @@ int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg, int set_status)
      if (!oldpkg->dest)
          oldpkg->dest = newpkg->dest;
      if (!oldpkg->architecture)
      if (!oldpkg->dest)
          oldpkg->dest = newpkg->dest;
      if (!oldpkg->architecture)
-         oldpkg->architecture = str_dup_safe(newpkg->architecture);
+         oldpkg->architecture = xstrdup(newpkg->architecture);
      if (!oldpkg->arch_priority)
          oldpkg->arch_priority = newpkg->arch_priority;
      if (!oldpkg->section)
      if (!oldpkg->arch_priority)
          oldpkg->arch_priority = newpkg->arch_priority;
      if (!oldpkg->section)
-         oldpkg->section = str_dup_safe(newpkg->section);
+         oldpkg->section = xstrdup(newpkg->section);
      if(!oldpkg->maintainer)
      if(!oldpkg->maintainer)
-         oldpkg->maintainer = str_dup_safe(newpkg->maintainer);
+         oldpkg->maintainer = xstrdup(newpkg->maintainer);
      if(!oldpkg->description)
      if(!oldpkg->description)
-         oldpkg->description = str_dup_safe(newpkg->description);
+         oldpkg->description = xstrdup(newpkg->description);
      if (set_status) {
          /* merge the state_flags from the new package */
          oldpkg->state_want = newpkg->state_want;
      if (set_status) {
          /* merge the state_flags from the new package */
          oldpkg->state_want = newpkg->state_want;
@@ -304,8 +409,10 @@ int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg, int set_status)
          oldpkg->provides_count = newpkg->provides_count;
          newpkg->provides_count = 0;
 
          oldpkg->provides_count = newpkg->provides_count;
          newpkg->provides_count = 0;
 
-         oldpkg->provides = newpkg->provides;
-         newpkg->provides = NULL;
+         if (!oldpkg->provides) {
+               oldpkg->provides = newpkg->provides;
+               newpkg->provides = NULL;
+         }
      }
 
      if (!oldpkg->conflicts_str) {
      }
 
      if (!oldpkg->conflicts_str) {
@@ -329,26 +436,27 @@ int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg, int set_status)
      }
 
      if (!oldpkg->filename)
      }
 
      if (!oldpkg->filename)
-         oldpkg->filename = str_dup_safe(newpkg->filename);
-     if (0)
-     fprintf(stdout, "pkg=%s old local_filename=%s new local_filename=%s\n", 
-            oldpkg->name, oldpkg->local_filename, newpkg->local_filename);
+         oldpkg->filename = xstrdup(newpkg->filename);
      if (!oldpkg->local_filename)
      if (!oldpkg->local_filename)
-         oldpkg->local_filename = str_dup_safe(newpkg->local_filename);
+         oldpkg->local_filename = xstrdup(newpkg->local_filename);
      if (!oldpkg->tmp_unpack_dir)
      if (!oldpkg->tmp_unpack_dir)
-         oldpkg->tmp_unpack_dir = str_dup_safe(newpkg->tmp_unpack_dir);
+         oldpkg->tmp_unpack_dir = xstrdup(newpkg->tmp_unpack_dir);
      if (!oldpkg->md5sum)
      if (!oldpkg->md5sum)
-         oldpkg->md5sum = str_dup_safe(newpkg->md5sum);
+         oldpkg->md5sum = xstrdup(newpkg->md5sum);
+#if defined HAVE_SHA256
+     if (!oldpkg->sha256sum)
+         oldpkg->sha256sum = xstrdup(newpkg->sha256sum);
+#endif
      if (!oldpkg->size)
      if (!oldpkg->size)
-         oldpkg->size = str_dup_safe(newpkg->size);
+         oldpkg->size = xstrdup(newpkg->size);
      if (!oldpkg->installed_size)
      if (!oldpkg->installed_size)
-         oldpkg->installed_size = str_dup_safe(newpkg->installed_size);
+         oldpkg->installed_size = xstrdup(newpkg->installed_size);
      if (!oldpkg->priority)
      if (!oldpkg->priority)
-         oldpkg->priority = str_dup_safe(newpkg->priority);
+         oldpkg->priority = xstrdup(newpkg->priority);
      if (!oldpkg->source)
      if (!oldpkg->source)
-         oldpkg->source = str_dup_safe(newpkg->source);
-     if (oldpkg->conffiles.head == NULL){
-         oldpkg->conffiles = newpkg->conffiles;
+         oldpkg->source = xstrdup(newpkg->source);
+     if (nv_pair_list_empty(&oldpkg->conffiles)){
+         list_splice_init(&newpkg->conffiles.head, &oldpkg->conffiles.head);
          conffile_list_init(&newpkg->conffiles);
      }
      if (!oldpkg->installed_files){
          conffile_list_init(&newpkg->conffiles);
      }
      if (!oldpkg->installed_files){
@@ -366,7 +474,7 @@ abstract_pkg_t *abstract_pkg_new(void)
 {
      abstract_pkg_t * ab_pkg;
 
 {
      abstract_pkg_t * ab_pkg;
 
-     ab_pkg = malloc(sizeof(abstract_pkg_t));
+     ab_pkg = xcalloc(1, sizeof(abstract_pkg_t));
 
      if (ab_pkg == NULL) {
          fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
 
      if (ab_pkg == NULL) {
          fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
@@ -381,8 +489,6 @@ abstract_pkg_t *abstract_pkg_new(void)
 
 int abstract_pkg_init(abstract_pkg_t *ab_pkg)
 {
 
 int abstract_pkg_init(abstract_pkg_t *ab_pkg)
 {
-     memset(ab_pkg, 0, sizeof(abstract_pkg_t));
-
      ab_pkg->provided_by = abstract_pkg_vec_alloc();
      if (ab_pkg->provided_by==NULL){
         return -1;
      ab_pkg->provided_by = abstract_pkg_vec_alloc();
      if (ab_pkg->provided_by==NULL){
         return -1;
@@ -394,177 +500,48 @@ int abstract_pkg_init(abstract_pkg_t *ab_pkg)
 }
 
 void set_flags_from_control(opkg_conf_t *conf, pkg_t *pkg){
 }
 
 void set_flags_from_control(opkg_conf_t *conf, pkg_t *pkg){
-     char * temp_str;
-     char **raw =NULL;
-     char **raw_start=NULL; 
-
-     temp_str = (char *) malloc (strlen(pkg->dest->info_dir)+strlen(pkg->name)+12);
-     if (temp_str == NULL ){
-        opkg_message(conf, OPKG_INFO, "Out of memory in  %s\n", __FUNCTION__);
-        return;
-     }
-     sprintf( temp_str,"%s/%s.control",pkg->dest->info_dir,pkg->name);
-   
-     raw = raw_start = read_raw_pkgs_from_file(temp_str);
-     if (raw == NULL ){
-        opkg_message(conf, OPKG_ERROR, "Unable to open the control file in  %s\n", __FUNCTION__);
-        return;
-     }
+     char *file_name;
+     FILE *fp;
 
 
-     while(*raw){
-        if (!pkg_valorize_other_field(pkg, &raw ) == 0) {
-            opkg_message(conf, OPKG_DEBUG, "unable to read control file for %s. May be empty\n", pkg->name);
-        }
-     }
-     raw = raw_start;
-     while (*raw) {
-        if (raw!=NULL)
-          free(*raw++);
-     }
-
-     free(raw_start); 
-     free(temp_str);
-
-     return ;
+     sprintf_alloc(&file_name,"%s/%s.control", pkg->dest->info_dir, pkg->name);
 
 
-}
-
-char * pkg_formatted_info(pkg_t *pkg )
-{
-     char *line;
-     char * buff;
-
-     buff = malloc(8192);
-     if (buff == NULL) {
-         fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-         return NULL;
+     fp = fopen(file_name, "r");
+     if (fp == NULL) {
+            opkg_message(conf, OPKG_ERROR, "fopen(%s): %s\n",
+                            file_name, strerror(errno));
+            return;
      }
 
      }
 
-     buff[0] = '\0';
-
-     line = pkg_formatted_field(pkg, "Package");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Version");
-     strncat(buff ,line, strlen(line));
-     free(line);
+     free(file_name);
 
 
-     line = pkg_formatted_field(pkg, "Depends");
-     strncat(buff ,line, strlen(line));
-     free(line);
-     
-     line = pkg_formatted_field(pkg, "Recommends");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Suggests");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Provides");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Replaces");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Conflicts");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Status");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Section");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Essential"); /* @@@@ should be removed in future release. *//* I do not agree with this Pigi*/
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Architecture");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Maintainer");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "MD5sum");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Size");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Filename");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Conffiles");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Source");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Description");
-     strncat(buff ,line, strlen(line));
-     free(line);
+     if (pkg_parse_from_stream(pkg, fp, PFM_ESSENTIAL)) {
+        opkg_message(conf, OPKG_DEBUG, "unable to read control file for %s. May be empty\n", pkg->name);
+     }
 
 
-     line = pkg_formatted_field(pkg, "Installed-Time");
-     strncat(buff ,line, strlen(line));
-     free(line);
+     fclose(fp);
 
 
-     return buff;
+     return;
 }
 
 }
 
-char * pkg_formatted_field(pkg_t *pkg, const char *field )
+void pkg_formatted_field(FILE *fp, pkg_t *pkg, const char *field)
 {
 {
-     static size_t LINE_LEN = 128;
-     char * temp = (char *)malloc(1);
-     int len = 0;
-     int flag_provide_false = 0;
-
-/*
-  Pigi: After some discussion with Florian we decided to modify the full procedure in 
-        dynamic memory allocation. This should avoid any other segv in this area ( except for bugs )
-*/
+     int i;
 
      if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) {
          goto UNKNOWN_FMT_FIELD;
      }
 
 
      if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) {
          goto UNKNOWN_FMT_FIELD;
      }
 
-     temp[0]='\0'; 
-
      switch (field[0])
      {
      case 'a':
      case 'A':
          if (strcasecmp(field, "Architecture") == 0) {
      switch (field[0])
      {
      case 'a':
      case 'A':
          if (strcasecmp(field, "Architecture") == 0) {
-              /* Architecture */
               if (pkg->architecture) {
               if (pkg->architecture) {
-                   temp = (char *)realloc(temp,strlen(pkg->architecture)+17);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->architecture)+17), "Architecture: %s\n", pkg->architecture);
+                   fprintf(fp, "Architecture: %s\n", pkg->architecture);
               }
          } else if (strcasecmp(field, "Auto-Installed") == 0) {
               }
          } else if (strcasecmp(field, "Auto-Installed") == 0) {
-               /* Auto-Installed flag */
-               if (pkg->auto_installed) {
-                   char * s = "Auto-Installed: yes\n";
-                   temp = (char *)realloc(temp, strlen(s) + 1);
-                   strcpy (temp, s);
-               }
+               if (pkg->auto_installed)
+                   fprintf(fp, "Auto-Installed: yes\n");
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
@@ -572,54 +549,26 @@ char * pkg_formatted_field(pkg_t *pkg, const char *field )
      case 'c':
      case 'C':
          if (strcasecmp(field, "Conffiles") == 0) {
      case 'c':
      case 'C':
          if (strcasecmp(field, "Conffiles") == 0) {
-              /* Conffiles */
               conffile_list_elt_t *iter;
               conffile_list_elt_t *iter;
-               char confstr[LINE_LEN];
 
 
-              if (pkg->conffiles.head == NULL) {
-                   return temp;
-              }
+              if (nv_pair_list_empty(&pkg->conffiles))
+                   return;
 
 
-               len = 14 ;
-              for (iter = pkg->conffiles.head; iter; iter = iter->next) {
-                   if (iter->data->name && iter->data->value) {
-                       len = len + (strlen(iter->data->name)+strlen(iter->data->value)+5);
-                   }
-              }
-               temp = (char *)realloc(temp,len);
-               if ( temp == NULL ){
-                 fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                 return NULL;
-               }
-               temp[0]='\0';
-               strncpy(temp, "Conffiles:\n", 12);
-              for (iter = pkg->conffiles.head; iter; iter = iter->next) {
-                   if (iter->data->name && iter->data->value) {
-                         snprintf(confstr, LINE_LEN, "%s %s\n", iter->data->name, iter->data->value);
-                         strncat(temp, confstr, strlen(confstr));           
+               fprintf(fp, "Conffiles:\n");
+              for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
+                   if (((conffile_t *)iter->data)->name && ((conffile_t *)iter->data)->value) {
+                         fprintf(fp, " %s %s\n", 
+                                 ((conffile_t *)iter->data)->name, 
+                                 ((conffile_t *)iter->data)->value);
                    }
               }
          } else if (strcasecmp(field, "Conflicts") == 0) {
                    }
               }
          } else if (strcasecmp(field, "Conflicts") == 0) {
-              int i;
-
               if (pkg->conflicts_count) {
               if (pkg->conflicts_count) {
-                    char conflictstr[LINE_LEN];
-                    len = 14 ;
+                    fprintf(fp, "Conflicts:");
                    for(i = 0; i < pkg->conflicts_count; i++) {
                    for(i = 0; i < pkg->conflicts_count; i++) {
-                        len = len + (strlen(pkg->conflicts_str[i])+5);
-                    }
-                    temp = (char *)realloc(temp,len);
-                    if ( temp == NULL ){
-                      fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                      return NULL;
+                        fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->conflicts_str[i]);
                     }
                     }
-                    temp[0]='\0';
-                    strncpy(temp, "Conflicts:", 11);
-                   for(i = 0; i < pkg->conflicts_count; i++) {
-                        snprintf(conflictstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->conflicts_str[i]);
-                        strncat(temp, conflictstr, strlen(conflictstr));           
-                    }
-                    strncat(temp, "\n", strlen("\n")); 
+                    fprintf(fp, "\n");
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
@@ -628,361 +577,192 @@ char * pkg_formatted_field(pkg_t *pkg, const char *field )
      case 'd':
      case 'D':
          if (strcasecmp(field, "Depends") == 0) {
      case 'd':
      case 'D':
          if (strcasecmp(field, "Depends") == 0) {
-              /* Depends */
-              int i;
-
               if (pkg->depends_count) {
               if (pkg->depends_count) {
-                    char depstr[LINE_LEN];
-                    len = 14 ;
+                    fprintf(fp, "Depends:");
                    for(i = 0; i < pkg->depends_count; i++) {
                    for(i = 0; i < pkg->depends_count; i++) {
-                        len = len + (strlen(pkg->depends_str[i])+4);
+                        fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->depends_str[i]);
                     }
                     }
-                    temp = (char *)realloc(temp,len);
-                    if ( temp == NULL ){
-                      fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                      return NULL;
-                    }
-                    temp[0]='\0';
-                    strncpy(temp, "Depends:", 10);
-                   for(i = 0; i < pkg->depends_count; i++) {
-                        snprintf(depstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->depends_str[i]);
-                        strncat(temp, depstr, strlen(depstr));           
-                    }
-                    strncat(temp, "\n", strlen("\n")); 
+                   fprintf(fp, "\n");
               }
          } else if (strcasecmp(field, "Description") == 0) {
               }
          } else if (strcasecmp(field, "Description") == 0) {
-              /* Description */
               if (pkg->description) {
               if (pkg->description) {
-                   temp = (char *)realloc(temp,strlen(pkg->description)+16);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->description)+16), "Description: %s\n", pkg->description);
+                   fprintf(fp, "Description: %s\n", pkg->description);
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
-      break;
+          break;
      case 'e':
      case 'e':
-     case 'E': {
-         /* Essential */
+     case 'E':
          if (pkg->essential) {
          if (pkg->essential) {
-              temp = (char *)realloc(temp,16);
-              if ( temp == NULL ){
-                fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                return NULL;
-              }
-              temp[0]='\0';
-              snprintf(temp, (16), "Essential: yes\n");
+              fprintf(fp, "Essential: yes\n");
          }
          }
-     }
          break;
      case 'f':
          break;
      case 'f':
-     case 'F': {
-         /* Filename */
+     case 'F':
          if (pkg->filename) {
          if (pkg->filename) {
-              temp = (char *)realloc(temp,strlen(pkg->filename)+12);
-              if ( temp == NULL ){
-                 fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                 return NULL;
-              }
-              temp[0]='\0';
-              snprintf(temp, (strlen(pkg->filename)+12), "Filename: %s\n", pkg->filename);
+              fprintf(fp, "Filename: %s\n", pkg->filename);
          }
          }
-     }
          break;
      case 'i':
          break;
      case 'i':
-     case 'I': {
+     case 'I':
          if (strcasecmp(field, "Installed-Size") == 0) {
          if (strcasecmp(field, "Installed-Size") == 0) {
-              /* Installed-Size */
-               temp = (char *)realloc(temp,strlen(pkg->installed_size)+17);
-               if ( temp == NULL ){
-                  fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                  return NULL;
-               }
-               temp[0]='\0';
-               snprintf(temp, (strlen(pkg->installed_size)+17), "Installed-Size: %s\n", pkg->installed_size);
+               fprintf(fp, "Installed-Size: %s\n", pkg->installed_size);
          } else if (strcasecmp(field, "Installed-Time") == 0 && pkg->installed_time) {
          } else if (strcasecmp(field, "Installed-Time") == 0 && pkg->installed_time) {
-               temp = (char *)realloc(temp,29);
-               if ( temp == NULL ){
-                 fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                 return NULL;
-               }
-               temp[0]='\0';
-               snprintf(temp, 29, "Installed-Time: %lu\n", pkg->installed_time);
+               fprintf(fp, "Installed-Time: %lu\n", pkg->installed_time);
          }
          }
-     }
          break;
      case 'm':
          break;
      case 'm':
-     case 'M': {
-         /* Maintainer | MD5sum */
+     case 'M':
          if (strcasecmp(field, "Maintainer") == 0) {
          if (strcasecmp(field, "Maintainer") == 0) {
-              /* Maintainer */
               if (pkg->maintainer) {
               if (pkg->maintainer) {
-                   temp = (char *)realloc(temp,strlen(pkg->maintainer)+14);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->maintainer)+14), "maintainer: %s\n", pkg->maintainer);
+                   fprintf(fp, "maintainer: %s\n", pkg->maintainer);
               }
          } else if (strcasecmp(field, "MD5sum") == 0) {
               }
          } else if (strcasecmp(field, "MD5sum") == 0) {
-              /* MD5sum */
               if (pkg->md5sum) {
               if (pkg->md5sum) {
-                   temp = (char *)realloc(temp,strlen(pkg->md5sum)+11);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->md5sum)+11), "MD5Sum: %s\n", pkg->md5sum);
+                   fprintf(fp, "MD5Sum: %s\n", pkg->md5sum);
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
-     }
          break;
      case 'p':
          break;
      case 'p':
-     case 'P': {
+     case 'P':
          if (strcasecmp(field, "Package") == 0) {
          if (strcasecmp(field, "Package") == 0) {
-              /* Package */
-               temp = (char *)realloc(temp,strlen(pkg->name)+11);
-               if ( temp == NULL ){
-                 fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                 return NULL;
-               }
-               temp[0]='\0';
-               snprintf(temp, (strlen(pkg->name)+11), "Package: %s\n", pkg->name);
+               fprintf(fp, "Package: %s\n", pkg->name);
          } else if (strcasecmp(field, "Priority") == 0) {
          } else if (strcasecmp(field, "Priority") == 0) {
-              /* Priority */
-               temp = (char *)realloc(temp,strlen(pkg->priority)+12);
-               if ( temp == NULL ){
-                 fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                 return NULL;
-               }
-               temp[0]='\0';
-               snprintf(temp, (strlen(pkg->priority)+12), "Priority: %s\n", pkg->priority);
+               fprintf(fp, "Priority: %s\n", pkg->priority);
          } else if (strcasecmp(field, "Provides") == 0) {
          } else if (strcasecmp(field, "Provides") == 0) {
-              /* Provides */
-              int i;
-
               if (pkg->provides_count) {
               if (pkg->provides_count) {
-               /* Here we check if the opkg_internal_use_only is used, and we discard it.*/
-                  for ( i=0; i < pkg->provides_count; i++ ){
-                     if (strstr(pkg->provides_str[i],"opkg_internal_use_only")!=NULL) {
-                         memset (pkg->provides_str[i],'\x0',strlen(pkg->provides_str[i])); /* Pigi clear my trick flag, just in case */
-                         flag_provide_false = 1;
-                      }
-                  }
-                  if ( !flag_provide_false ||                                             /* Pigi there is not my trick flag */
-                     ((flag_provide_false) &&  (pkg->provides_count > 1))){             /* Pigi There is, but we also have others Provides */
-                     char provstr[LINE_LEN];
-                     len = 15;
-                    for(i = 0; i < pkg->provides_count; i++) {
-                         len = len + (strlen(pkg->provides_str[i])+5);
-                     }
-                     temp = (char *)realloc(temp,len);
-                     if ( temp == NULL ){
-                       fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                       return NULL;
-                     }
-                     temp[0]='\0';
-                     strncpy(temp, "Provides:", 12);
-                    for(i = 0; i < pkg->provides_count; i++) {
-                         if (strlen(pkg->provides_str[i])>0){;
-                            snprintf(provstr, LINE_LEN, "%s %s", i == 1 ? "" : ",", pkg->provides_str[i]);
-                            strncat(temp, provstr, strlen(provstr));           
-                         }
-                     }
-                     strncat(temp, "\n", strlen("\n")); 
+                  fprintf(fp, "Provides:");
+                 for(i = 0; i < pkg->provides_count-1; i++) {
+                      fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->provides_str[i]);
                   }
                   }
+                  fprintf(fp, "\n");
                }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
                }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
-     }
          break;
      case 'r':
          break;
      case 'r':
-     case 'R': {
-         int i;
-         /* Replaces | Recommends*/
+     case 'R':
          if (strcasecmp (field, "Replaces") == 0) {
               if (pkg->replaces_count) {
          if (strcasecmp (field, "Replaces") == 0) {
               if (pkg->replaces_count) {
-                    char replstr[LINE_LEN];
-                    len = 14;
-                   for (i = 0; i < pkg->replaces_count; i++) {
-                        len = len + (strlen(pkg->replaces_str[i])+5);
-                    }
-                    temp = (char *)realloc(temp,len);
-                    if ( temp == NULL ){
-                      fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                      return NULL;
-                    }
-                    temp[0]='\0';
-                    strncpy(temp, "Replaces:", 12);
+                    fprintf(fp, "Replaces:");
                    for (i = 0; i < pkg->replaces_count; i++) {
                    for (i = 0; i < pkg->replaces_count; i++) {
-                        snprintf(replstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->replaces_str[i]);
-                        strncat(temp, replstr, strlen(replstr));           
+                        fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->replaces_str[i]);
                     }
                     }
-                    strncat(temp, "\n", strlen("\n")); 
+                    fprintf(fp, "\n");
               }
          } else if (strcasecmp (field, "Recommends") == 0) {
               if (pkg->recommends_count) {
               }
          } else if (strcasecmp (field, "Recommends") == 0) {
               if (pkg->recommends_count) {
-                    char recstr[LINE_LEN];
-                    len = 15;
-                   for(i = 0; i < pkg->recommends_count; i++) {
-                         len = len + (strlen( pkg->recommends_str[i])+5);
-                    }
-                    temp = (char *)realloc(temp,len);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                    temp[0]='\0';
-                    strncpy(temp, "Recommends:", 13);
+                    fprintf(fp, "Recommends:");
                    for(i = 0; i < pkg->recommends_count; i++) {
                    for(i = 0; i < pkg->recommends_count; i++) {
-                        snprintf(recstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->recommends_str[i]);
-                        strncat(temp, recstr, strlen(recstr));           
+                        fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->recommends_str[i]);
                     }
                     }
-                    strncat(temp, "\n", strlen("\n")); 
+                    fprintf(fp, "\n");
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
-     }
          break;
      case 's':
          break;
      case 's':
-     case 'S': {
-         /* Section | Size | Source | Status | Suggests */
+     case 'S':
          if (strcasecmp(field, "Section") == 0) {
          if (strcasecmp(field, "Section") == 0) {
-              /* Section */
               if (pkg->section) {
               if (pkg->section) {
-                   temp = (char *)realloc(temp,strlen(pkg->section)+11);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->section)+11), "Section: %s\n", pkg->section);
+                   fprintf(fp, "Section: %s\n", pkg->section);
+              }
+#if defined HAVE_SHA256
+         } else if (strcasecmp(field, "SHA256sum") == 0) {
+              if (pkg->sha256sum) {
+                   fprintf(fp, "SHA256sum: %s\n", pkg->sha256sum);
               }
               }
+#endif
          } else if (strcasecmp(field, "Size") == 0) {
          } else if (strcasecmp(field, "Size") == 0) {
-              /* Size */
               if (pkg->size) {
               if (pkg->size) {
-                   temp = (char *)realloc(temp,strlen(pkg->size)+8);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->size)+8), "Size: %s\n", pkg->size);
+                   fprintf(fp, "Size: %s\n", pkg->size);
               }
          } else if (strcasecmp(field, "Source") == 0) {
               }
          } else if (strcasecmp(field, "Source") == 0) {
-              /* Source */
               if (pkg->source) {
               if (pkg->source) {
-                   temp = (char *)realloc(temp,strlen(pkg->source)+10);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->source)+10), "Source: %s\n", pkg->source);
+                   fprintf(fp, "Source: %s\n", pkg->source);
                }
          } else if (strcasecmp(field, "Status") == 0) {
                }
          } else if (strcasecmp(field, "Status") == 0) {
-              /* Status */
-               /* Benjamin Pineau note: we should avoid direct usage of 
-                * strlen(arg) without keeping "arg" for later free()
-                */
-               char *pflag=pkg_state_flag_to_str(pkg->state_flag);
-               char *pstat=pkg_state_status_to_str(pkg->state_status);
-               char *pwant=pkg_state_want_to_str(pkg->state_want);
-
-               size_t sum_of_sizes = (size_t) ( strlen(pwant)+ strlen(pflag)+ strlen(pstat) + 12 );
-               temp = (char *)realloc(temp,sum_of_sizes);
-               if ( temp == NULL ){
-                   fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                   return NULL;
-                }
-                temp[0]='\0';
-                snprintf(temp, sum_of_sizes , "Status: %s %s %s\n", pwant, pflag, pstat);
-                free(pflag);
-                free(pwant);
-               if(pstat) /* pfstat can be NULL if ENOMEM */
-                   free(pstat);
+               char *pflag = pkg_state_flag_to_str(pkg->state_flag);
+               char *pstat = pkg_state_status_to_str(pkg->state_status);
+               char *pwant = pkg_state_want_to_str(pkg->state_want);
+
+              if (pflag == NULL || pstat == NULL || pwant == NULL)
+                      return;
+
+               fprintf(fp, "Status: %s %s %s\n", pwant, pflag, pstat);
+
+               free(pflag);
+               free(pwant);
+               free(pstat);
          } else if (strcasecmp(field, "Suggests") == 0) {
               if (pkg->suggests_count) {
          } else if (strcasecmp(field, "Suggests") == 0) {
               if (pkg->suggests_count) {
-                   int i;
-                    char sugstr[LINE_LEN];
-                    len = 13;
+                    fprintf(fp, "Suggests:");
                    for(i = 0; i < pkg->suggests_count; i++) {
                    for(i = 0; i < pkg->suggests_count; i++) {
-                        len = len + (strlen(pkg->suggests_str[i])+5);
-                    }
-                    temp = (char *)realloc(temp,len);
-                    if ( temp == NULL ){
-                      fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                      return NULL;
+                        fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->suggests_str[i]);
                     }
                     }
-                    temp[0]='\0';
-                    strncpy(temp, "Suggests:", 10);
-                   for(i = 0; i < pkg->suggests_count; i++) {
-                        snprintf(sugstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->suggests_str[i]);
-                        strncat(temp, sugstr, strlen(sugstr));           
-                    }
-                    strncat(temp, "\n", strlen("\n")); 
+                    fprintf(fp, "\n");
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
-     }
+         break;
+     case 't':
+     case 'T':
+         if (strcasecmp(field, "Tags") == 0) {
+              if (pkg->tags) {
+                   fprintf(fp, "Tags: %s\n", pkg->tags);
+              }
+         }
          break;
      case 'v':
          break;
      case 'v':
-     case 'V': {
-         /* Version */
-         char *version = pkg_version_str_alloc(pkg);
-          temp = (char *)realloc(temp,strlen(version)+14);
-          if ( temp == NULL ){
-             fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-             return NULL;
+     case 'V':
+         {
+              char *version = pkg_version_str_alloc(pkg);
+              if (version == NULL)
+                   return;
+               fprintf(fp, "Version: %s\n", version);
+              free(version);
           }
           }
-          temp[0]='\0';
-          snprintf(temp, (strlen(version)+12), "Version: %s\n", version);
-         free(version);
-     }
          break;
      default:
          goto UNKNOWN_FMT_FIELD;
      }
 
          break;
      default:
          goto UNKNOWN_FMT_FIELD;
      }
 
-     if ( strlen(temp)<2 ) {
-          temp[0]='\0';
-     }
-     return temp;
+     return;
 
 
- UNKNOWN_FMT_FIELD:
+UNKNOWN_FMT_FIELD:
      fprintf(stderr, "%s: ERROR: Unknown field name: %s\n", __FUNCTION__, field);
      fprintf(stderr, "%s: ERROR: Unknown field name: %s\n", __FUNCTION__, field);
-     if ( strlen(temp)<2 ) {
-          temp[0]='\0';
-     }
-
-     return temp;
 }
 
 }
 
-void pkg_print_info(pkg_t *pkg, FILE *file)
+void pkg_formatted_info(FILE *fp, pkg_t *pkg)
 {
 {
-     char * buff;
-     if (pkg == NULL) {
-       return;
-     }
-
-     buff = pkg_formatted_info(pkg);
-     if ( buff == NULL ) 
-         return;
-     if (strlen(buff)>2){
-         fwrite(buff, 1, strlen(buff), file);
-     } 
-     free(buff);
+       pkg_formatted_field(fp, pkg, "Package");
+       pkg_formatted_field(fp, pkg, "Version");
+       pkg_formatted_field(fp, pkg, "Depends");
+       pkg_formatted_field(fp, pkg, "Recommends");
+       pkg_formatted_field(fp, pkg, "Suggests");
+       pkg_formatted_field(fp, pkg, "Provides");
+       pkg_formatted_field(fp, pkg, "Replaces");
+       pkg_formatted_field(fp, pkg, "Conflicts");
+       pkg_formatted_field(fp, pkg, "Status");
+       pkg_formatted_field(fp, pkg, "Section");
+       pkg_formatted_field(fp, pkg, "Essential");
+       pkg_formatted_field(fp, pkg, "Architecture");
+       pkg_formatted_field(fp, pkg, "Maintainer");
+       pkg_formatted_field(fp, pkg, "MD5sum");
+       pkg_formatted_field(fp, pkg, "Size");
+       pkg_formatted_field(fp, pkg, "Filename");
+       pkg_formatted_field(fp, pkg, "Conffiles");
+       pkg_formatted_field(fp, pkg, "Source");
+       pkg_formatted_field(fp, pkg, "Description");
+       pkg_formatted_field(fp, pkg, "Installed-Time");
+       pkg_formatted_field(fp, pkg, "Tags");
+       fputs("\n", fp);
 }
 
 void pkg_print_status(pkg_t * pkg, FILE * file)
 }
 
 void pkg_print_status(pkg_t * pkg, FILE * file)
@@ -998,7 +778,7 @@ void pkg_print_status(pkg_t * pkg, FILE * file)
        can be found in th available file.
 
        But, someone proposed the idea to make it possible to
        can be found in th available file.
 
        But, someone proposed the idea to make it possible to
-       reconstruct a .ipk from an installed package, (ie. for beaming
+       reconstruct a .opk from an installed package, (ie. for beaming
        from one handheld to another). So, maybe we actually want a few
        more fields here, (depends, suggests, etc.), so that that would
        be guaranteed to work even in the absence of more information
        from one handheld to another). So, maybe we actually want a few
        more fields here, (depends, suggests, etc.), so that that would
        be guaranteed to work even in the absence of more information
@@ -1011,39 +791,23 @@ void pkg_print_status(pkg_t * pkg, FILE * file)
        local storage without requiring a Packages file from any feed.
        -Jamey
      */
        local storage without requiring a Packages file from any feed.
        -Jamey
      */
-     pkg_print_field(pkg, file, "Package");
-     pkg_print_field(pkg, file, "Version");
-     pkg_print_field(pkg, file, "Depends");
-     pkg_print_field(pkg, file, "Recommends");
-     pkg_print_field(pkg, file, "Suggests");
-     pkg_print_field(pkg, file, "Provides");
-     pkg_print_field(pkg, file, "Replaces");
-     pkg_print_field(pkg, file, "Conflicts");
-     pkg_print_field(pkg, file, "Status");
-     pkg_print_field(pkg, file, "Essential"); /* @@@@ should be removed in future release. */
-     pkg_print_field(pkg, file, "Architecture");
-     pkg_print_field(pkg, file, "Conffiles");
-     pkg_print_field(pkg, file, "Installed-Time");
-     pkg_print_field(pkg, file, "Auto-Installed");
+     pkg_formatted_field(file, pkg, "Package");
+     pkg_formatted_field(file, pkg, "Version");
+     pkg_formatted_field(file, pkg, "Depends");
+     pkg_formatted_field(file, pkg, "Recommends");
+     pkg_formatted_field(file, pkg, "Suggests");
+     pkg_formatted_field(file, pkg, "Provides");
+     pkg_formatted_field(file, pkg, "Replaces");
+     pkg_formatted_field(file, pkg, "Conflicts");
+     pkg_formatted_field(file, pkg, "Status");
+     pkg_formatted_field(file, pkg, "Essential");
+     pkg_formatted_field(file, pkg, "Architecture");
+     pkg_formatted_field(file, pkg, "Conffiles");
+     pkg_formatted_field(file, pkg, "Installed-Time");
+     pkg_formatted_field(file, pkg, "Auto-Installed");
      fputs("\n", file);
 }
 
      fputs("\n", file);
 }
 
-void pkg_print_field(pkg_t *pkg, FILE *file, const char *field)
-{
-     char *buff;
-     if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) {
-       fprintf(stderr, "%s: ERROR: Unknown field name: %s\n",
-            __FUNCTION__, field);
-     }
-     buff = pkg_formatted_field(pkg, field);
-     if (strlen(buff)>2) {
-       fprintf(file, "%s", buff);
-       fflush(file);
-     }
-     free(buff);
-     return;
-}
-
 /*
  * libdpkg - Debian packaging suite library routines
  * vercmp.c - comparison of version numbers
 /*
  * libdpkg - Debian packaging suite library routines
  * vercmp.c - comparison of version numbers
@@ -1138,10 +902,10 @@ int pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op)
      return 0;
 }
 
      return 0;
 }
 
-int pkg_name_version_and_architecture_compare(void *p1, void *p2)
+int pkg_name_version_and_architecture_compare(const void *p1, const void *p2)
 {
 {
-     const pkg_t *a = *(const pkg_t **)p1;
-     const pkg_t *b = *(const pkg_t **)p2;
+     const pkg_t *a = *(const pkg_t**) p1;
+     const pkg_t *b = *(const pkg_t**) p2;
      int namecmp;
      int vercmp;
      if (!a->name || !b->name) {
      int namecmp;
      int vercmp;
      if (!a->name || !b->name) {
@@ -1168,7 +932,7 @@ int pkg_name_version_and_architecture_compare(void *p1, void *p2)
      return 0;
 }
 
      return 0;
 }
 
-int abstract_pkg_name_compare(void *p1, void *p2)
+int abstract_pkg_name_compare(const void *p1, const void *p2)
 {
      const abstract_pkg_t *a = *(const abstract_pkg_t **)p1;
      const abstract_pkg_t *b = *(const abstract_pkg_t **)p2;
 {
      const abstract_pkg_t *a = *(const abstract_pkg_t **)p1;
      const abstract_pkg_t *b = *(const abstract_pkg_t **)p2;
@@ -1181,32 +945,27 @@ int abstract_pkg_name_compare(void *p1, void *p2)
 }
 
 
 }
 
 
-char *pkg_version_str_alloc(pkg_t *pkg)
+char *
+pkg_version_str_alloc(pkg_t *pkg)
 {
 {
-     char *complete_version;
-     char *epoch_str;
-     char *revision_str;
-
-     if (pkg->epoch) {
-         sprintf_alloc(&epoch_str, "%d:", pkg->epoch);
-     } else {
-         epoch_str = strdup("");
-     }
-
-     if (pkg->revision && strlen(pkg->revision)) {
-         sprintf_alloc(&revision_str, "-%s", pkg->revision);
-     } else {
-         revision_str = strdup("");
-     }
-
-
-     sprintf_alloc(&complete_version, "%s%s%s",
-                  epoch_str, pkg->version, revision_str);
-
-     free(epoch_str);
-     free(revision_str);
-
-     return complete_version;
+       char *version;
+
+       if (pkg->epoch) {
+               if (pkg->revision)
+                       sprintf_alloc(&version, "%d:%s-%s",
+                               pkg->epoch, pkg->version, pkg->revision);
+               else
+                       sprintf_alloc(&version, "%d:%s",
+                               pkg->epoch, pkg->version);
+       } else {
+               if (pkg->revision)
+                       sprintf_alloc(&version, "%s-%s",
+                               pkg->version, pkg->revision);
+               else
+                       version = xstrdup(pkg->version);
+       }
+
+       return version;
 }
 
 str_list_t *pkg_get_installed_files(pkg_t *pkg)
 }
 
 str_list_t *pkg_get_installed_files(pkg_t *pkg)
@@ -1225,12 +984,8 @@ str_list_t *pkg_get_installed_files(pkg_t *pkg)
      }
 
      pkg->installed_files = str_list_alloc();
      }
 
      pkg->installed_files = str_list_alloc();
-     if (pkg->installed_files == NULL) {
-         fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-         return NULL;
-     }
 
 
-     /* For uninstalled packages, get the file list firectly from the package.
+     /* For uninstalled packages, get the file list directly from the package.
        For installed packages, look at the package.list file in the database.
      */
      if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) {
        For installed packages, look at the package.list file in the database.
      */
      if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) {
@@ -1297,6 +1052,7 @@ str_list_t *pkg_get_installed_files(pkg_t *pkg)
               sprintf_alloc(&installed_file_name, "%s", file_name);
          }
          str_list_append(pkg->installed_files, installed_file_name);
               sprintf_alloc(&installed_file_name, "%s", file_name);
          }
          str_list_append(pkg->installed_files, installed_file_name);
+          free(installed_file_name);
          free(line);
      }
 
          free(line);
      }
 
@@ -1312,22 +1068,13 @@ str_list_t *pkg_get_installed_files(pkg_t *pkg)
    work. */
 int pkg_free_installed_files(pkg_t *pkg)
 {
    work. */
 int pkg_free_installed_files(pkg_t *pkg)
 {
-     str_list_elt_t *iter;
-
      pkg->installed_files_ref_cnt--;
      pkg->installed_files_ref_cnt--;
-     if (pkg->installed_files_ref_cnt > 0) {
+
+     if (pkg->installed_files_ref_cnt > 0)
          return 0;
          return 0;
-     }
 
      if (pkg->installed_files) {
 
      if (pkg->installed_files) {
-
-         for (iter = pkg->installed_files->head; iter; iter = iter->next) {
-              /* malloced in pkg_get_installed_files */
-              free (iter->data);
-              iter->data = NULL;
-         }
-
-         str_list_deinit(pkg->installed_files);
+         str_list_purge(pkg->installed_files);
      }
 
      pkg->installed_files = NULL;
      }
 
      pkg->installed_files = NULL;
@@ -1365,8 +1112,8 @@ conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name)
          return NULL;
      }
 
          return NULL;
      }
 
-     for (iter = pkg->conffiles.head; iter; iter = iter->next) {
-         conffile = iter->data;
+     for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
+         conffile = (conffile_t *)iter->data;
 
          if (strcmp(conffile->name, file_name) == 0) {
               return conffile;
 
          if (strcmp(conffile->name, file_name) == 0) {
               return conffile;
@@ -1383,6 +1130,33 @@ int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
      char *path;
      char *cmd;
 
      char *path;
      char *cmd;
 
+     if (conf->noaction)
+            return 0;
+
+     /* XXX: CLEANUP: There must be a better way to handle maintainer
+       scripts when running with offline_root mode and/or a dest other
+       than '/'. I've been playing around with some clever chroot
+       tricks and I might come up with something workable. */
+     /*
+      * Attempt to provide a restricted environment for offline operation
+      * Need the following set as a minimum:
+      * OPKG_OFFLINE_ROOT = absolute path to root dir
+      * D                 = absolute path to root dir (for OE generated postinst)
+      * PATH              = something safe (a restricted set of utilities)
+      */
+
+     if (conf->offline_root) {
+          if (conf->offline_root_path) {
+            setenv("PATH", conf->offline_root_path, 1);
+          } else {
+            opkg_message(conf, OPKG_NOTICE, 
+               "(offline root mode: not running %s.%s)\n", pkg->name, script);
+           return 0;
+          }
+         setenv("OPKG_OFFLINE_ROOT", conf->offline_root, 1);
+         setenv("D", conf->offline_root, 1);
+     }
+
      /* XXX: FEATURE: When conf->offline_root is set, we should run the
        maintainer script within a chroot environment. */
 
      /* XXX: FEATURE: When conf->offline_root is set, we should run the
        maintainer script within a chroot environment. */
 
@@ -1405,15 +1179,6 @@ int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
      }
 
      opkg_message(conf, OPKG_INFO, "Running script %s\n", path);
      }
 
      opkg_message(conf, OPKG_INFO, "Running script %s\n", path);
-     if (conf->noaction) return 0;
-
-     /* XXX: CLEANUP: There must be a better way to handle maintainer
-       scripts when running with offline_root mode and/or a dest other
-       than '/'. I've been playing around with some clever chroot
-       tricks and I might come up with something workable. */
-     if (conf->offline_root) {
-         setenv("OPKG_OFFLINE_ROOT", conf->offline_root, 1);
-     }
 
      setenv("PKG_ROOT",
            pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1);
 
      setenv("PKG_ROOT",
            pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1);
@@ -1423,12 +1188,6 @@ int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
          return 0;
      }
 
          return 0;
      }
 
-     if (conf->offline_root) {
-         fprintf(stderr, "(offline root mode: not running %s.%s)\n", pkg->name, script);
-         free(path);
-         return 0;
-     }
-
      sprintf_alloc(&cmd, "%s %s", path, args);
      free(path);
 
      sprintf_alloc(&cmd, "%s %s", path, args);
      free(path);
 
@@ -1449,13 +1208,13 @@ char *pkg_state_want_to_str(pkg_state_want_t sw)
 
      for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
          if (pkg_state_want_map[i].value == sw) {
 
      for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
          if (pkg_state_want_map[i].value == sw) {
-              return strdup(pkg_state_want_map[i].str);
+              return xstrdup(pkg_state_want_map[i].str);
          }
      }
 
      fprintf(stderr, "%s: ERROR: Illegal value for state_want: %d\n",
             __FUNCTION__, sw);
          }
      }
 
      fprintf(stderr, "%s: ERROR: Illegal value for state_want: %d\n",
             __FUNCTION__, sw);
-     return strdup("<STATE_WANT_UNKNOWN>");
+     return xstrdup("<STATE_WANT_UNKNOWN>");
 }
 
 pkg_state_want_t pkg_state_want_from_str(char *str)
 }
 
 pkg_state_want_t pkg_state_want_from_str(char *str)
@@ -1483,7 +1242,7 @@ char *pkg_state_flag_to_str(pkg_state_flag_t sf)
      sf &= SF_NONVOLATILE_FLAGS;
 
      if (sf == 0) {
      sf &= SF_NONVOLATILE_FLAGS;
 
      if (sf == 0) {
-         return strdup("ok");
+         return xstrdup("ok");
      } else {
 
          for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
      } else {
 
          for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
@@ -1491,11 +1250,7 @@ char *pkg_state_flag_to_str(pkg_state_flag_t sf)
                    len += strlen(pkg_state_flag_map[i].str) + 1;
               }
          }
                    len += strlen(pkg_state_flag_map[i].str) + 1;
               }
          }
-         str = malloc(len);
-          if ( str == NULL ) {
-             fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-              return NULL;
-          }
+         str = xmalloc(len);
          str[0] = 0;
          for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
               if (sf & pkg_state_flag_map[i].value) {
          str[0] = 0;
          for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
               if (sf & pkg_state_flag_map[i].value) {
@@ -1540,13 +1295,13 @@ char *pkg_state_status_to_str(pkg_state_status_t ss)
 
      for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
          if (pkg_state_status_map[i].value == ss) {
 
      for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
          if (pkg_state_status_map[i].value == ss) {
-              return strdup(pkg_state_status_map[i].str);
+              return xstrdup(pkg_state_status_map[i].str);
          }
      }
 
      fprintf(stderr, "%s: ERROR: Illegal value for state_status: %d\n",
             __FUNCTION__, ss);
          }
      }
 
      fprintf(stderr, "%s: ERROR: Illegal value for state_status: %d\n",
             __FUNCTION__, ss);
-     return strdup("<STATE_STATUS_UNKNOWN>");
+     return xstrdup("<STATE_STATUS_UNKNOWN>");
 }
 
 pkg_state_status_t pkg_state_status_from_str(const char *str)
 }
 
 pkg_state_status_t pkg_state_status_from_str(const char *str)
@@ -1571,15 +1326,12 @@ int pkg_arch_supported(opkg_conf_t *conf, pkg_t *pkg)
      if (!pkg->architecture)
          return 1;
 
      if (!pkg->architecture)
          return 1;
 
-     l = conf->arch_list.head;
-
-     while (l) {
-         nv_pair_t *nv = l->data;
+     list_for_each_entry(l , &conf->arch_list.head, node) {
+         nv_pair_t *nv = (nv_pair_t *)l->data;
          if (strcmp(nv->name, pkg->architecture) == 0) {
               opkg_message(conf, OPKG_DEBUG, "arch %s (priority %s) supported for pkg %s\n", nv->name, nv->value, pkg->name);
               return 1;
          }
          if (strcmp(nv->name, pkg->architecture) == 0) {
               opkg_message(conf, OPKG_DEBUG, "arch %s (priority %s) supported for pkg %s\n", nv->name, nv->value, pkg->name);
               return 1;
          }
-         l = l->next;
      }
 
      opkg_message(conf, OPKG_DEBUG, "arch %s unsupported for pkg %s\n", pkg->architecture, pkg->name);
      }
 
      opkg_message(conf, OPKG_DEBUG, "arch %s unsupported for pkg %s\n", pkg->architecture, pkg->name);
@@ -1590,15 +1342,12 @@ int pkg_get_arch_priority(opkg_conf_t *conf, const char *archname)
 {
      nv_pair_list_elt_t *l;
 
 {
      nv_pair_list_elt_t *l;
 
-     l = conf->arch_list.head;
-
-     while (l) {
-         nv_pair_t *nv = l->data;
+     list_for_each_entry(l , &conf->arch_list.head, node) {
+         nv_pair_t *nv = (nv_pair_t *)l->data;
          if (strcmp(nv->name, archname) == 0) {
               int priority = strtol(nv->value, NULL, 0);
               return priority;
          }
          if (strcmp(nv->name, archname) == 0) {
               int priority = strtol(nv->value, NULL, 0);
               return priority;
          }
-         l = l->next;
      }
      return 0;
 }
      }
      return 0;
 }
@@ -1631,7 +1380,7 @@ int pkg_info_preinstall_check(opkg_conf_t *conf)
          pkg_t *pkg = available_pkgs->pkgs[i];
          if (!pkg->arch_priority && (pkg->state_flag || (pkg->state_want != SW_UNKNOWN))) {
               /* clear flags and want for any uninstallable package */
          pkg_t *pkg = available_pkgs->pkgs[i];
          if (!pkg->arch_priority && (pkg->state_flag || (pkg->state_want != SW_UNKNOWN))) {
               /* clear flags and want for any uninstallable package */
-              opkg_message(conf, OPKG_NOTICE, "Clearing state_want and state_flag for pkg=%s (arch_priority=%d flag=%d want=%d)\n", 
+              opkg_message(conf, OPKG_DEBUG, "Clearing state_want and state_flag for pkg=%s (arch_priority=%d flag=%d want=%d)\n", 
                            pkg->name, pkg->arch_priority, pkg->state_flag, pkg->state_want);
               pkg->state_want = SW_UNKNOWN;
               pkg->state_flag = 0;
                            pkg->name, pkg->arch_priority, pkg->state_flag, pkg->state_want);
               pkg->state_want = SW_UNKNOWN;
               pkg->state_flag = 0;
@@ -1645,16 +1394,19 @@ int pkg_info_preinstall_check(opkg_conf_t *conf)
      for (i = 0; i < installed_pkgs->len; i++) {
          pkg_t *pkg = installed_pkgs->pkgs[i];
          str_list_t *installed_files = pkg_get_installed_files(pkg); /* this causes installed_files to be cached */
      for (i = 0; i < installed_pkgs->len; i++) {
          pkg_t *pkg = installed_pkgs->pkgs[i];
          str_list_t *installed_files = pkg_get_installed_files(pkg); /* this causes installed_files to be cached */
-         str_list_elt_t *iter;
+         str_list_elt_t *iter, *niter;
          if (installed_files == NULL) {
               opkg_message(conf, OPKG_ERROR, "No installed files for pkg %s\n", pkg->name);
               break;
          }
          if (installed_files == NULL) {
               opkg_message(conf, OPKG_ERROR, "No installed files for pkg %s\n", pkg->name);
               break;
          }
-         for (iter = installed_files->head; iter; iter = iter->next) {
-              char *installed_file = iter->data;
+         for (iter = str_list_first(installed_files), niter = str_list_next(installed_files, iter); 
+                  iter; 
+                  iter = niter, niter = str_list_next(installed_files, iter)) {
+              char *installed_file = (char *) iter->data;
               // opkg_message(conf, OPKG_DEBUG2, "pkg %s: file=%s\n", pkg->name, installed_file);
               file_hash_set_file_owner(conf, installed_file, pkg);
          }
               // opkg_message(conf, OPKG_DEBUG2, "pkg %s: file=%s\n", pkg->name, installed_file);
               file_hash_set_file_owner(conf, installed_file, pkg);
          }
+         pkg_free_installed_files(pkg);
      }
      pkg_vec_free(installed_pkgs);
 
      }
      pkg_vec_free(installed_pkgs);
 
@@ -1707,6 +1459,8 @@ int pkg_write_filelist(opkg_conf_t *conf, pkg_t *pkg)
      fclose(data.stream);
      free(list_file_name);
 
      fclose(data.stream);
      free(list_file_name);
 
+     pkg->state_flag &= ~SF_FILELIST_CHANGED;
+
      return err;
 }
 
      return err;
 }
 
@@ -1730,5 +1484,6 @@ int pkg_write_changed_filelists(opkg_conf_t *conf)
                    opkg_message(conf, OPKG_NOTICE, "pkg_write_filelist pkg=%s returned %d\n", pkg->name, err);
          }
      }
                    opkg_message(conf, OPKG_NOTICE, "pkg_write_filelist pkg=%s returned %d\n", pkg->name, err);
          }
      }
+     pkg_vec_free (installed_pkgs);
      return 0;
 }
      return 0;
 }