Radix cross Linux Package Tools

Package Tools – is a set of utilities to create, install, and update RcL packages

8 Commits   0 Branches   2 Tags
     5         kx 
     5         kx /**********************************************************************
     5         kx 
     5         kx   Copyright 2019 Andrey V.Kosteltsev
     5         kx 
     5         kx   Licensed under the Radix.pro License, Version 1.0 (the "License");
     5         kx   you may not use this file  except  in compliance with the License.
     5         kx   You may obtain a copy of the License at
     5         kx 
     5         kx      https://radix.pro/licenses/LICENSE-1.0-en_US.txt
     5         kx 
     5         kx   Unless required by applicable law or agreed to in writing, software
     5         kx   distributed under the License is distributed on an "AS IS" BASIS,
     5         kx   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
     5         kx   implied.
     5         kx 
     5         kx  **********************************************************************/
     5         kx 
     5         kx #include <config.h>
     5         kx 
     5         kx #include <stdlib.h>
     5         kx #include <stdio.h>
     5         kx #include <string.h>
     5         kx #include <linux/limits.h>
     5         kx #include <libgen.h>   /* basename(3) */
     5         kx #include <unistd.h>
     5         kx #include <time.h>
     5         kx #include <math.h>
     5         kx 
     5         kx #include <msglog.h>
     5         kx #include <wrapper.h>
     5         kx 
     5         kx #include <make-pkglist.h>
     5         kx 
     5         kx #include <cmpvers.h>
     5         kx #include <dlist.h>
     5         kx #include <btree.h>
     5         kx #include <jsmin.h>
     5         kx #include <pkglist.h>
     5         kx 
     5         kx 
     5         kx char *htmlroot = NULL;
     5         kx char *hardware = NULL;
     5         kx int   minimize = 0;
     5         kx 
     5         kx struct dlist *srcpkgs  = NULL;
     5         kx 
     5         kx struct dlist *packages = NULL;
     5         kx struct dlist *tarballs = NULL;
     5         kx 
     5         kx struct dlist *provides = NULL;
     5         kx struct dlist *extern_requires = NULL;
     5         kx 
     5         kx static struct dlist *tree = NULL;
     5         kx 
     5         kx static char *pkgs_fname = NULL,
     5         kx             *tree_fname = NULL,
     5         kx             *html_fname = NULL;
     5         kx 
     5         kx static char *pkgs_min_fname = NULL,
     5         kx             *tree_min_fname = NULL;
     5         kx 
     5         kx static const char *tarball_suffix = "txz";
     5         kx 
     5         kx /***************************************************************
     5         kx   tarballs List functions:
     5         kx   =======================
     5         kx 
     5         kx   NOTE:
     5         kx   ----
     5         kx     TARBALLS  is an optional list  created in case when we have
     5         kx     a set of PACKAGES as input of make-pkglist utility. When we
     5         kx     are working with a set of input PKGLOGs the  TARBALLS  list
     5         kx     is not chreated and pointer to the tarballs == NULL.
     5         kx  */
     5         kx void add_tarball( char *tarball )
     5         kx {
     5         kx   tarballs = dlist_append( tarballs, (void *)xstrdup( (const char *)tarball ) );
     5         kx }
     5         kx 
     5         kx static void __free_tarball( void *data, void *user_data )
     5         kx {
     5         kx   if( data ) { free( data ); }
     5         kx }
     5         kx 
     5         kx void free_tarballs( void )
     5         kx {
     5         kx   if( tarballs ) { dlist_free( tarballs, __free_tarball ); tarballs = NULL; }
     5         kx }
     5         kx 
     5         kx static int __compare_tarballs( const void *a, const void *b )
     5         kx {
     5         kx   return strncmp( (const char *)a, (const char *)b, (size_t)strlen((const char *)b) );
     5         kx }
     5         kx 
     5         kx const char *find_tarball( const char *name )
     5         kx {
     5         kx   struct dlist *node = NULL;
     5         kx 
     5         kx   if( !tarballs || !name ) return NULL;
     5         kx 
     5         kx   node = dlist_find_data( tarballs, __compare_tarballs, (const void *)name );
     5         kx   if( node )
     5         kx   {
     5         kx     return (const char *)node->data;
     5         kx   }
     5         kx 
     5         kx   return NULL;
     5         kx }
     5         kx 
     5         kx /*********************
     5         kx   Just for debugging:
     5         kx  */
     5         kx static void __print_tarball( void *data, void *user_data )
     5         kx {
     5         kx   int *counter = (int *)user_data;
     5         kx 
     5         kx   if( counter ) { fprintf( stdout, "tarball[%.5d]: %s\n", *counter, (char *)data ); ++(*counter); }
     5         kx   else          { fprintf( stdout, "tarball: %s\n", (char *)data ); }
     5         kx }
     5         kx 
     5         kx void print_tarballs( void )
     5         kx {
     5         kx   int cnt = 0;
     5         kx   if( tarballs ) { dlist_foreach( tarballs, __print_tarball, (void *)&cnt ); }
     5         kx }
     5         kx /*
     5         kx   End of tarballs List functions.
     5         kx  ***************************************************************/
     5         kx 
     5         kx 
     5         kx 
     5         kx char *strprio( enum _priority priority, int short_name )
     5         kx {
     5         kx   char *p = NULL;
     5         kx 
     5         kx   switch( priority )
     5         kx   {
     5         kx     case REQUIRED:
     5         kx       p = ( short_name ) ? "REQ" : "REQUIRED";
     5         kx       break;
     5         kx     case RECOMMENDED:
     5         kx       p = ( short_name ) ? "REC" : "RECOMMENDED";
     5         kx       break;
     5         kx     case OPTIONAL:
     5         kx       p = ( short_name ) ? "OPT" : "OPTIONAL";
     5         kx       break;
     5         kx     case SKIP:
     5         kx       p = ( short_name ) ? "SKP" : "SKIP";
     5         kx       break;
     5         kx   }
     5         kx   return p;
     5         kx }
     5         kx 
     5         kx char *strproc( enum _procedure procedure )
     5         kx {
     5         kx   char *p = NULL;
     5         kx 
     5         kx   switch( procedure )
     5         kx   {
     5         kx     case INSTALL:
     5         kx       p = "install";
     5         kx       break;
     5         kx     case UPDATE:
     5         kx       p = "update";
     5         kx       break;
     5         kx   }
     5         kx   return p;
     5         kx }
     5         kx 
     5         kx 
     5         kx /***************************************************************
     5         kx   PACKAGE functions:
     5         kx  */
     5         kx 
     5         kx struct pkg *pkg_alloc( void )
     5         kx {
     5         kx   struct pkg *pkg = NULL;
     5         kx 
     5         kx   pkg = (struct pkg *)malloc( sizeof( struct pkg ) );
     5         kx   if( !pkg ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)pkg, sizeof( struct pkg ) );
     5         kx 
     5         kx   return pkg;
     5         kx }
     5         kx 
     5         kx void pkg_free( struct pkg *pkg )
     5         kx {
     5         kx   if( pkg )
     5         kx   {
     5         kx     if( pkg->group )   { free( pkg->group );   pkg->group   = NULL; }
     5         kx     if( pkg->name )    { free( pkg->name );    pkg->name    = NULL; }
     5         kx     if( pkg->version ) { free( pkg->version ); pkg->version = NULL; }
     5         kx 
     5         kx     free( pkg );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __pkg_free_func( void *data, void *user_data )
     5         kx {
     5         kx   struct pkg *pkg = (struct pkg *)data;
     5         kx   if( pkg ) { pkg_free( pkg ); }
     5         kx }
     5         kx 
     5         kx void free_srcpkgs( void )
     5         kx {
     5         kx   if( srcpkgs ) { dlist_free( srcpkgs, __pkg_free_func ); srcpkgs = NULL; }
     5         kx }
     5         kx 
     5         kx void add_srcpkg( struct pkg *pkg )
     5         kx {
     5         kx   srcpkgs = dlist_append( srcpkgs, (void *)pkg );
     5         kx }
     5         kx 
     5         kx 
     5         kx static struct pkginfo *__pkginfo_alloc( void )
     5         kx {
     5         kx   struct pkginfo *pkginfo = NULL;
     5         kx 
     5         kx   pkginfo = (struct pkginfo *)malloc( sizeof( struct pkginfo ) );
     5         kx   if( !pkginfo ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)pkginfo, sizeof( struct pkginfo ) );
     5         kx 
     5         kx   return pkginfo;
     5         kx }
     5         kx 
     5         kx static void __pkginfo_free( struct pkginfo *pkginfo )
     5         kx {
     5         kx   if( pkginfo )
     5         kx   {
     5         kx     if( pkginfo->name )              { free( pkginfo->name );              pkginfo->name              = NULL; }
     5         kx     if( pkginfo->version )           { free( pkginfo->version );           pkginfo->version           = NULL; }
     5         kx     if( pkginfo->arch )              { free( pkginfo->arch );              pkginfo->arch              = NULL; }
     5         kx     if( pkginfo->distro_name )       { free( pkginfo->distro_name );       pkginfo->distro_name       = NULL; }
     5         kx     if( pkginfo->distro_version )    { free( pkginfo->distro_version );    pkginfo->distro_version    = NULL; }
     5         kx     if( pkginfo->group )             { free( pkginfo->group );             pkginfo->group             = NULL; }
     5         kx     if( pkginfo->short_description ) { free( pkginfo->short_description ); pkginfo->short_description = NULL; }
     5         kx     if( pkginfo->url )               { free( pkginfo->url );               pkginfo->url               = NULL; }
     5         kx     if( pkginfo->license )           { free( pkginfo->license );           pkginfo->license           = NULL; }
     5         kx 
     5         kx     free( pkginfo );
     5         kx   }
     5         kx }
     5         kx 
     5         kx 
     5         kx static struct references *__references_alloc( void )
     5         kx {
     5         kx   struct references *references = NULL;
     5         kx 
     5         kx   references = (struct references *)malloc( sizeof( struct references ) );
     5         kx   if( !references ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)references, sizeof( struct references ) );
     5         kx 
     5         kx   return references;
     5         kx }
     5         kx 
     5         kx static void __references_free( struct references *references )
     5         kx {
     5         kx   if( references )
     5         kx   {
     5         kx     if( references->list ) { dlist_free( references->list, __pkg_free_func ); references->list = NULL; }
     5         kx     free( references );
     5         kx   }
     5         kx }
     5         kx 
     5         kx 
     5         kx static struct requires *__requires_alloc( void )
     5         kx {
     5         kx   struct requires *requires = NULL;
     5         kx 
     5         kx   requires = (struct requires *)malloc( sizeof( struct requires ) );
     5         kx   if( !requires ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)requires, sizeof( struct requires ) );
     5         kx 
     5         kx   return requires;
     5         kx }
     5         kx 
     5         kx static void __requires_free( struct requires *requires )
     5         kx {
     5         kx   if( requires )
     5         kx   {
     5         kx     if( requires->list ) { dlist_free( requires->list, __pkg_free_func ); requires->list = NULL; }
     5         kx     free( requires );
     5         kx   }
     5         kx }
     5         kx 
     5         kx 
     5         kx static struct files *__files_alloc( void )
     5         kx {
     5         kx   struct files *files = NULL;
     5         kx 
     5         kx   files = (struct files *)malloc( sizeof( struct files ) );
     5         kx   if( !files ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)files, sizeof( struct files ) );
     5         kx 
     5         kx   return files;
     5         kx }
     5         kx 
     5         kx static void __files_free_func( void *data, void *user_data )
     5         kx {
     5         kx   if( data ) { free( data ); }
     5         kx }
     5         kx 
     5         kx static void __files_free( struct files *files )
     5         kx {
     5         kx   if( files )
     5         kx   {
     5         kx     if( files->list ) { dlist_free( files->list, __files_free_func ); files->list = NULL; }
     5         kx     free( files );
     5         kx   }
     5         kx }
     5         kx 
     5         kx 
     5         kx struct package *package_alloc( void )
     5         kx {
     5         kx   struct package    *package    = NULL;
     5         kx   struct pkginfo    *pkginfo    = __pkginfo_alloc();
     5         kx   struct references *references = __references_alloc();
     5         kx   struct requires   *requires   = __requires_alloc();
     5         kx   struct files      *files      = __files_alloc();
     5         kx 
     5         kx   package = (struct package *)malloc( sizeof( struct package ) );
     5         kx   if( !package ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)package, sizeof( struct package ) );
     5         kx 
     5         kx   package->pkginfo    = pkginfo;
     5         kx   package->references = references;
     5         kx   package->requires   = requires;
     5         kx   package->files      = files;
     5         kx 
     5         kx   return package;
     5         kx }
     5         kx 
     5         kx void package_free( struct package *package )
     5         kx {
     5         kx   if( package )
     5         kx   {
     5         kx     if( package->pkginfo )    {    __pkginfo_free( package->pkginfo );    package->pkginfo    = NULL; }
     5         kx     if( package->references ) { __references_free( package->references ); package->references = NULL; }
     5         kx     if( package->requires )   {   __requires_free( package->requires );   package->requires   = NULL; }
     5         kx     if( package->files )      {      __files_free( package->files );      package->files      = NULL; }
     5         kx 
     5         kx     if( package->description )    { free( package->description );     package->description    = NULL; }
     5         kx     if( package->restore_links )  { free( package->restore_links );   package->restore_links  = NULL; }
     5         kx     if( package->install_script ) { free( package->install_script );  package->install_script = NULL; }
     5         kx     if( package->hardware )       { free( package->hardware );        package->hardware       = NULL; }
     5         kx     if( package->tarball )        { free( package->tarball );         package->tarball        = NULL; }
     5         kx 
     5         kx     free( package );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __package_free_func( void *data, void *user_data )
     5         kx {
     5         kx   struct package *package = (struct package *)data;
     5         kx   if( package ) { package_free( package ); }
     5         kx }
     5         kx 
     5         kx void free_packages( void )
     5         kx {
     5         kx   if( packages ) { dlist_free( packages, __package_free_func ); packages = NULL; }
     5         kx }
     5         kx 
     5         kx 
     5         kx static int __compare_packages( const void *a, const void *b )
     5         kx {
     5         kx   int  ret = -1;
     5         kx 
     5         kx   struct package *pkg1 = (struct package *)a;
     5         kx   struct package *pkg2 = (struct package *)b;
     5         kx 
     5         kx   if( pkg1->pkginfo->group && pkg2->pkginfo->group )
     5         kx   {
     5         kx     ret = strcmp( pkg1->pkginfo->group, pkg2->pkginfo->group );
     5         kx   }
     5         kx   else if( !pkg1->pkginfo->group && !pkg2->pkginfo->group )
     5         kx   {
     5         kx     ret = 0;
     5         kx   }
     5         kx   else if( pkg1->pkginfo->group )
     5         kx   {
     5         kx     ret = 1;
     5         kx   }
     5         kx 
     5         kx   if( ! ret )
     5         kx   {
     5         kx     return strcmp( pkg1->pkginfo->name, pkg2->pkginfo->name );
     5         kx   }
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx static int __compare_packages_with_version( const void *a, const void *b )
     5         kx {
     5         kx   int  ret = -1;
     5         kx 
     5         kx   struct package *pkg1 = (struct package *)a;
     5         kx   struct package *pkg2 = (struct package *)b;
     5         kx 
     5         kx   if( pkg1->pkginfo->group && pkg2->pkginfo->group )
     5         kx   {
     5         kx     ret = strcmp( pkg1->pkginfo->group, pkg2->pkginfo->group );
     5         kx   }
     5         kx   else if( !pkg1->pkginfo->group && !pkg2->pkginfo->group )
     5         kx   {
     5         kx     ret = 0;
     5         kx   }
     5         kx   else if( pkg1->pkginfo->group )
     5         kx   {
     5         kx     ret = 1;
     5         kx   }
     5         kx 
     5         kx   if( ! ret )
     5         kx   {
     5         kx     ret = strcmp( pkg1->pkginfo->name, pkg2->pkginfo->name );
     5         kx     if( ! ret )
     5         kx     {
     5         kx       return cmp_version( (const char *)pkg1->pkginfo->version, (const char *)pkg2->pkginfo->version );
     5         kx     }
     5         kx   }
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx 
     5         kx void add_package( struct package *package )
     5         kx {
     5         kx   packages = dlist_append( packages, (void *)package );
     5         kx }
     5         kx 
     5         kx void add_reference( struct package *package, struct pkg *pkg )
     5         kx {
     5         kx   if( package && package->references && pkg )
     5         kx   {
     5         kx     package->references->list = dlist_append( package->references->list, (void *)pkg );
     5         kx     package->references->size = dlist_length( package->references->list );
     5         kx   }
     5         kx }
     5         kx 
     5         kx void add_required( struct package *package, struct pkg *pkg )
     5         kx {
     5         kx   if( package && package->requires && pkg )
     5         kx   {
     5         kx     package->requires->list = dlist_append( package->requires->list, (void *)pkg );
     5         kx     package->requires->size = dlist_length( package->requires->list );
     5         kx   }
     5         kx }
     5         kx 
     5         kx void add_file( struct package *package, const char *fname )
     5         kx {
     5         kx   if( package && package->files && fname )
     5         kx   {
     5         kx     package->files->list = dlist_append( package->files->list, (void *)xstrdup( (const char *)fname ) );
     5         kx     package->files->size = dlist_length( package->files->list );
     5         kx   }
     5         kx }
     5         kx 
     5         kx /*********************
     5         kx   Just for debugging:
     5         kx  */
     5         kx static void __print_reference( void *data, void *user_data )
     5         kx {
     5         kx   struct pkg *pkg = (struct pkg *)data;
     5         kx 
     5         kx   if( pkg )
     5         kx   {
     5         kx     if( pkg->group ) { fprintf( stdout, "reference: %s/%s=%s\n", pkg->group, pkg->name, pkg->version ); }
     5         kx     else             { fprintf( stdout, "reference: %s=%s\n",                pkg->name, pkg->version ); }
     5         kx   }
     5         kx }
     5         kx 
     5         kx void package_print_references( struct package *package )
     5         kx {
     5         kx   if( !package ) return;
     5         kx 
     5         kx   if( package->references->list )
     5         kx   {
     5         kx     dlist_foreach( package->references->list, __print_reference, NULL );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __print_required( void *data, void *user_data )
     5         kx {
     5         kx   struct pkg *pkg = (struct pkg *)data;
     5         kx 
     5         kx   if( pkg )
     5         kx   {
     5         kx     if( pkg->group ) { fprintf( stdout, "required: %s/%s=%s\n", pkg->group, pkg->name, pkg->version ); }
     5         kx     else             { fprintf( stdout, "required: %s=%s\n",                pkg->name, pkg->version ); }
     5         kx   }
     5         kx }
     5         kx 
     5         kx void package_print_requires( struct package *package )
     5         kx {
     5         kx   if( !package ) return;
     5         kx 
     5         kx   if( package->requires->list )
     5         kx   {
     5         kx     dlist_foreach( package->requires->list, __print_required, NULL );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __print_file( void *data, void *user_data )
     5         kx {
     5         kx   int *counter = (int *)user_data;
     5         kx 
     5         kx   if( counter ) { fprintf( stdout, "file[%.5d]: %s\n", *counter, (char *)data ); ++(*counter); }
     5         kx   else          { fprintf( stdout, "file: %s\n", (char *)data ); }
     5         kx }
     5         kx 
     5         kx void package_print_files( struct package *package )
     5         kx {
     5         kx   int cnt = 0;
     5         kx 
     5         kx   if( !package ) return;
     5         kx 
     5         kx   if( package->files->list )
     5         kx   {
     5         kx     dlist_foreach( package->files->list, __print_file, (void *)&cnt );
     5         kx   }
     5         kx }
     5         kx 
     5         kx /*
     5         kx   End of PACKAGES functions.
     5         kx  ***************************************************************/
     5         kx 
     5         kx /***************************************************************
     5         kx   Extern REQUIRES list functions:
     5         kx  */
     5         kx 
     5         kx static int __compare_required( const void *a, const void *b )
     5         kx {
     5         kx   int  ret = -1;
     5         kx 
     5         kx   struct pkg *pkg1 = (struct pkg *)a;
     5         kx   struct pkg *pkg2 = (struct pkg *)b;
     5         kx 
     5         kx   if( pkg1->group && pkg2->group )
     5         kx   {
     5         kx     ret = strcmp( pkg1->group, pkg2->group );
     5         kx   }
     5         kx   else if( !pkg1->group && !pkg2->group )
     5         kx   {
     5         kx     ret = 0;
     5         kx   }
     5         kx   else if( pkg1->group )
     5         kx   {
     5         kx     ret = 1;
     5         kx   }
     5         kx 
     5         kx   if( ! ret )
     5         kx   {
     5         kx     return strcmp( pkg1->name, pkg2->name );
     5         kx   }
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx static int __compare_required_with_version( const void *a, const void *b )
     5         kx {
     5         kx   int  ret = -1;
     5         kx 
     5         kx   struct pkg *pkg1 = (struct pkg *)a;
     5         kx   struct pkg *pkg2 = (struct pkg *)b;
     5         kx 
     5         kx   if( pkg1->group && pkg2->group )
     5         kx   {
     5         kx     ret = strcmp( pkg1->group, pkg2->group );
     5         kx   }
     5         kx   else if( !pkg1->group && !pkg2->group )
     5         kx   {
     5         kx     ret = 0;
     5         kx   }
     5         kx   else if( pkg1->group )
     5         kx   {
     5         kx     ret = 1;
     5         kx   }
     5         kx 
     5         kx   if( ! ret )
     5         kx   {
     5         kx     ret = strcmp( pkg1->name, pkg2->name );
     5         kx     if( ! ret )
     5         kx     {
     5         kx       return cmp_version( (const char *)pkg1->version, (const char *)pkg2->version );
     5         kx     }
     5         kx   }
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx static void __add_unique_required( void *data, void *user_data )
     5         kx {
     5         kx   struct pkg *pkg = (struct pkg *)data;
     5         kx 
     5         kx   if( pkg )
     5         kx   {
     5         kx     struct dlist *found = dlist_find_data( extern_requires, __compare_required, (const void *)data );
     5         kx 
     5         kx     if( found )
     5         kx     {
     5         kx       if( cmp_version( (const char *)((struct pkg *)found->data)->version, (const char *)pkg->version ) )
     5         kx       {
     5         kx         char *s = ((struct pkg *)found->data)->version;
     5         kx         ((struct pkg *)found->data)->version =
     5         kx            xstrdup( (const char *)max_version( (const char *)((struct pkg *)found->data)->version,
     5         kx                                                (const char *)pkg->version ) );
     5         kx         free( s );
     5         kx       }
     5         kx     }
     5         kx     else
     5         kx     {
     5         kx       struct pkg *req = pkg_alloc();
     5         kx       if( req )
     5         kx       {
     5         kx         if( pkg->group )
     5         kx         {
     5         kx           req->group = xstrdup( (const char *)pkg->group   );
     5         kx         }
     5         kx         req->name    = xstrdup( (const char *)pkg->name    );
     5         kx         req->version = xstrdup( (const char *)pkg->version );
     5         kx 
     5         kx         extern_requires = dlist_append( extern_requires, (void *)req );
     5         kx       }
     5         kx     }
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __fill_extern_requires( void *data, void *user_data )
     5         kx {
     5         kx   struct package *package = (struct package *)data;
     5         kx 
     5         kx   if( package )
     5         kx   {
     5         kx     struct pkg *provide = pkg_alloc();
     5         kx 
     5         kx     if( provide )
     5         kx     {
     5         kx       if( package->pkginfo->group )
     5         kx       {
     5         kx         provide->group = xstrdup( (const char *)package->pkginfo->group   );
     5         kx       }
     5         kx       provide->name    = xstrdup( (const char *)package->pkginfo->name    );
     5         kx       provide->version = xstrdup( (const char *)package->pkginfo->version );
     5         kx 
     5         kx       provides = dlist_append( provides, (void *)provide );
     5         kx     }
     5         kx 
     5         kx     if( package->requires->list )
     5         kx     {
     5         kx       dlist_foreach( package->requires->list, __add_unique_required, NULL );
     5         kx     }
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __clean_extern_requires( void *data, void *user_data )
     5         kx {
     5         kx   if( data )
     5         kx   {
     5         kx     extern_requires = dlist_remove_data( extern_requires, __compare_required_with_version, __pkg_free_func, (const void *)data );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static int __compare_provided_old_package( const void *a, const void *b )
     5         kx {
     5         kx   int  ret = -1;
     5         kx 
     5         kx   struct package *pkg1 = (struct package *)a;
     5         kx   struct     pkg *pkg2 = (struct     pkg *)b;
     5         kx 
     5         kx   if( pkg1->pkginfo->group && pkg2->group )
     5         kx   {
     5         kx     ret = strcmp( pkg1->pkginfo->group, pkg2->group );
     5         kx   }
     5         kx   else if( !pkg1->pkginfo->group && !pkg2->group )
     5         kx   {
     5         kx     ret = 0;
     5         kx   }
     5         kx   else if( pkg1->pkginfo->group )
     5         kx   {
     5         kx     ret = 1;
     5         kx   }
     5         kx 
     5         kx   if( ! ret )
     5         kx   {
     5         kx     ret = strcmp( pkg1->pkginfo->name, pkg2->name );
     5         kx     if( ! ret )
     5         kx     {
     5         kx       pkg2->procedure = UPDATE; /* mark as too old */
     5         kx       return ret;
     5         kx     }
     5         kx   }
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx static void __remove_old_package( void *data, void *user_data )
     5         kx {
     5         kx   packages = dlist_remove_data( packages, __compare_provided_old_package, __package_free_func, (const void *)data );
     5         kx }
     5         kx 
     5         kx static void remove_old_packages( void )
     5         kx {
     5         kx   dlist_foreach( extern_requires, __remove_old_package, NULL );
     5         kx }
     5         kx /*
     5         kx   End of Extern REQUIRES list functions.
     5         kx  ***************************************************************/
     5         kx 
     5         kx 
     5         kx /***************************************************************
     5         kx   Check REQUIRES functions:
     5         kx  */
     5         kx static int __compare_provided( const void *a, const void *b )
     5         kx {
     5         kx   int  ret = -1;
     5         kx 
     5         kx   struct package *pkg1 = (struct package *)a;
     5         kx   struct     pkg *pkg2 = (struct     pkg *)b;
     5         kx 
     5         kx   if( pkg1->pkginfo->group && pkg2->group )
     5         kx   {
     5         kx     ret = strcmp( pkg1->pkginfo->group, pkg2->group );
     5         kx   }
     5         kx   else if( !pkg1->pkginfo->group && !pkg2->group )
     5         kx   {
     5         kx     ret = 0;
     5         kx   }
     5         kx   else if( pkg1->pkginfo->group )
     5         kx   {
     5         kx     ret = 1;
     5         kx   }
     5         kx 
     5         kx   if( ! ret )
     5         kx   {
     5         kx     return strcmp( pkg1->pkginfo->name, pkg2->name );
     5         kx   }
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx static int __compare_packages_by_name( const void *a, const void *b )
     5         kx {
     5         kx   int  ret = -1;
     5         kx 
     5         kx   struct package *pkg1 = (struct package *)a;
     5         kx   struct package *pkg2 = (struct package *)b;
     5         kx 
     5         kx   if( !strcmp( pkg1->pkginfo->name, pkg2->pkginfo->name ) )
     5         kx   {
     5         kx     if( pkg1->pkginfo->group && pkg2->pkginfo->group )
     5         kx     {
     5         kx       ret = strcmp( pkg1->pkginfo->group, pkg2->pkginfo->group );
     5         kx     }
     5         kx     else if( !pkg1->pkginfo->group && !pkg2->pkginfo->group )
     5         kx     {
     5         kx       ret = 0;
     5         kx     }
     5         kx     else if( pkg1->pkginfo->group )
     5         kx     {
     5         kx       ret = 1;
     5         kx     }
     5         kx 
     5         kx     /* returns equal only if groups are not equal */
     5         kx     if( ret ) return 0;
     5         kx   }
     5         kx 
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx static int check_dependencies( struct package *package )
     5         kx {
     5         kx   struct dlist *list = NULL, *next = NULL, *update = NULL;
     5         kx   int    depended    = -1;
     5         kx 
     5         kx   if( !package ) return depended;
     5         kx   depended = 0;
     5         kx 
     5         kx   if( !(list = package->requires->list) ) return depended;
     5         kx 
     5         kx   while( list )
     5         kx   {
     5         kx     next = dlist_next( list );
     5         kx     {
     5         kx       int has_extern_dependencies = 0, already_provided = 0;
     5         kx 
     5         kx       struct pkg   *pkg   = (struct pkg *)list->data;
     5         kx       struct dlist *found = dlist_find_data( extern_requires, __compare_required, (const void *)pkg );
     5         kx 
     5         kx       if( found )
     5         kx       {
     5         kx         if( cmp_version( (const char *)((struct pkg *)found->data)->version, (const char *)pkg->version ) >= 0 )
     5         kx         {
     5         kx           /* required package is found in the extern_requires list */
     5         kx           has_extern_dependencies += 1;
     5         kx         }
     5         kx       }
     5         kx 
     5         kx       found = dlist_find_data( provides, __compare_provided, (const void *)pkg );
     5         kx       if( found )
     5         kx       {
     5         kx         if( cmp_version( (const char *)((struct package *)found->data)->pkginfo->version, (const char *)pkg->version ) >= 0 )
     5         kx         {
     5         kx           /* required package is found in the extern_requires list */
     5         kx           already_provided += 1;
     5         kx         }
     5         kx       }
     5         kx 
     5         kx       if( !already_provided && !has_extern_dependencies ) depended += 1;
     5         kx     }
     5         kx     list = next;
     5         kx   }
     5         kx 
     5         kx   /* Check if the package with the same name already exists in the provides list */
     5         kx   update = dlist_find_data( provides, __compare_packages_by_name, (const void *)package );
     5         kx   if( update )
     5         kx   {
     5         kx     /* Set install procedure to UPDATE: */
     5         kx     package->procedure = UPDATE;
     5         kx   }
     5         kx 
     5         kx   return depended;
     5         kx }
     5         kx /*
     5         kx   End of Check REQUIRES functions.
     5         kx  ***************************************************************/
     5         kx 
     5         kx static void __fill_provides_list( void *data, void *user_data )
     5         kx {
     5         kx   struct package *package = (struct package *)data;
     5         kx 
     5         kx   if( package )
     5         kx   {
     5         kx     if( !check_dependencies( package ) )
     5         kx     {
     5         kx       /* move independed package to the provides list */
     5         kx       packages = dlist_remove( packages, (const void *)data );
     5         kx       provides = dlist_append( provides, (void *)package );
     5         kx     }
     5         kx   }
     5         kx }
     5         kx 
     5         kx 
     5         kx static void __print_extern_package( void *data, void *user_data )
     5         kx {
     5         kx   FILE *output = (FILE *)user_data;
     5         kx   struct pkg *pkg = (struct pkg *)data;
     5         kx 
     5         kx   if( pkg )
     5         kx   {
     5         kx     if( pkg->group ) { fprintf( output, "# required: %s/%s=%s\n", pkg->group, pkg->name, pkg->version ); }
     5         kx     else             { fprintf( output, "# required: %s=%s\n",                pkg->name, pkg->version ); }
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __print_provided_package( void *data, void *user_data )
     5         kx {
     5         kx   FILE *output = (FILE *)user_data;
     5         kx   struct package *package = (struct package *)data;
     5         kx 
     5         kx   if( package )
     5         kx   {
     5         kx     fprintf( output, "%s:",  package->pkginfo->name );
     5         kx     fprintf( output, "%s:",  package->pkginfo->version );
     5         kx     fprintf( output, "%s:",  package->pkginfo->short_description );
     5         kx     if( package->tarball )
     5         kx     {
     5         kx       fprintf( output, "%s:",  package->tarball );
     5         kx     }
     5         kx     else
     5         kx     {
     5         kx       if( package->pkginfo->group ) fprintf( output, "%s/", package->pkginfo->group );
     5         kx 
     5         kx       fprintf( output, "%s-", package->pkginfo->name );
     5         kx       fprintf( output, "%s-", package->pkginfo->version );
     5         kx       fprintf( output, "%s-", package->pkginfo->arch );
     5         kx       fprintf( output, "%s-", package->pkginfo->distro_name );
     5         kx       fprintf( output, "%s.", package->pkginfo->distro_version );
     5         kx       fprintf( output, "%s:", tarball_suffix ); /* default is '.txz' */
     5         kx     }
     5         kx     fprintf( output, "%s:",  strproc( package->procedure ) );
     5         kx     fprintf( output, "%s\n", strprio( package->priority, 0 ) );
     5         kx   }
     5         kx }
     5         kx 
     5         kx 
     5         kx static void __reduce_packages_list( struct pkg *pkg )
     5         kx {
     5         kx   struct package *package = NULL;
     5         kx   struct dlist   *found   = NULL;
     5         kx 
     5         kx   if( !pkg ) return;
     5         kx 
     5         kx   found = dlist_find_data( packages, __compare_provided, (const void *)pkg );
     5         kx   if( found && found->data )
     5         kx   {
     5         kx     struct dlist *list = NULL, *next = NULL;
     5         kx 
     5         kx     package = (struct package *)found->data;
     5         kx 
     5         kx     packages = dlist_remove( packages, (const void *)package );
     5         kx     provides = dlist_append( provides, (void *)package );
     5         kx 
     5         kx     if( !(list = package->requires->list) ) return;
     5         kx 
     5         kx     while( list )
     5         kx     {
     5         kx       next = dlist_next( list );
     5         kx       {
     5         kx         __reduce_packages_list( (struct pkg *)list->data );
     5         kx       }
     5         kx       list = next;
     5         kx     }
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __reduce_packages_list_single( void *data, void *user_data )
     5         kx {
     5         kx   struct pkg *pkg = (struct pkg *)data;
     5         kx 
     5         kx   if( pkg ) { __reduce_packages_list( pkg ); }
     5         kx }
     5         kx 
     5         kx 
     5         kx static void reduce_packages_list( struct dlist *srcpkgs )
     5         kx {
     5         kx   if( ! srcpkgs ) return;
     5         kx 
     5         kx   dlist_foreach( srcpkgs, __reduce_packages_list_single, NULL );
     5         kx 
     5         kx   dlist_free( packages, __package_free_func );
     5         kx   if( dlist_length( provides ) != 0 )
     5         kx   {
     5         kx     packages = provides;
     5         kx     provides = NULL;
     5         kx   }
     5         kx }
     5         kx 
     5         kx int create_provides_list( struct dlist *srcpkgs )
     5         kx {
     5         kx   int ret = 0;
     5         kx 
     5         kx   if( !packages ) return ret;
     5         kx 
     5         kx   if( srcpkgs && dlist_length( srcpkgs ) > 0 )
     5         kx   {
     5         kx     /******************************************************************
     5         kx       Reduce packages list to the list of requires of source packages:
     5         kx      */
     5         kx     reduce_packages_list( srcpkgs );
     5         kx   }
     5         kx 
     5         kx   /* Fill two lists: provides and extern_requires: */
     5         kx   dlist_foreach( packages, __fill_extern_requires, NULL );
     5         kx 
     5         kx   /* Remove packages from extern_requires list which present in the provides list: */
     5         kx   dlist_foreach( provides, __clean_extern_requires, NULL );
     5         kx 
     5         kx   /* Now we don't need previous contents of provides list: */
     5         kx   dlist_free( provides, __pkg_free_func );
     5         kx   provides = NULL;
     5         kx 
     5         kx   /* Remove old packages if required new version of them */
     5         kx   remove_old_packages();
     5         kx 
     5         kx   /* move packages into provides list in order of installation: */
     5         kx   while( dlist_length( packages ) != 0 )
     5         kx   {
     5         kx     dlist_foreach( packages, __fill_provides_list, NULL );
     5         kx   }
     5         kx 
     5         kx   return dlist_length( extern_requires );
     5         kx }
     5         kx 
     5         kx void free_provides_list( void )
     5         kx {
     5         kx   if( htmlroot ) { free( htmlroot ); htmlroot = NULL; }
     5         kx   if( hardware ) { free( hardware ); hardware = NULL; }
     5         kx 
     5         kx   dlist_free( extern_requires, __pkg_free_func );
     5         kx   dlist_free( provides, __package_free_func );
     5         kx }
     5         kx 
     5         kx void print_provides_list( const char *plist_fname )
     5         kx {
     5         kx   FILE *plist = NULL;
     5         kx 
     5         kx   if( !plist_fname || !provides ) return;
     5         kx 
     5         kx   plist = fopen( plist_fname, "w" );
     5         kx   if( !plist )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot create output %s file", basename( (char *)plist_fname ) );
     5         kx   }
     5         kx 
     5         kx   fprintf( plist, "#\n" );
     5         kx   fprintf( plist, "# file format:\n" );
     5         kx   fprintf( plist, "# ===========\n" );
     5         kx   fprintf( plist, "#\n" );
     5         kx   fprintf( plist, "# Each line contains six fields separated by colon symbol ':' like following.\n" );
     5         kx   fprintf( plist, "#\n" );
     5         kx   fprintf( plist, "# pkgname:version:description:tarball:procedure:priority\n" );
     5         kx   fprintf( plist, "#\n" );
     5         kx   fprintf( plist, "# where:\n" );
     5         kx   fprintf( plist, "#\n" );
     5         kx   fprintf( plist, "#   pkgname     - should be the same as the value of pkgname  in the '.DESCRIPTION' file;\n" );
     5         kx   fprintf( plist, "#   version     - package version for showing in check list  dialog box  if this file is\n" );
     5         kx   fprintf( plist, "#                 used to complete common check dialog for installing group  of packages;\n" );
     5         kx   fprintf( plist, "#   description - short description for showing in check list dialog box if this file is\n" );
     5         kx   fprintf( plist, "#                 used to complete common check dialog for installing  group of packages;\n" );
     5         kx   fprintf( plist, "#   tarball     - should end in '.txz';\n" );
     5         kx   fprintf( plist, "#   procedure   - installation procedure {install | update}:\n" );
     5         kx   fprintf( plist, "#                  * 'install' - if package requires normal installation,\n" );
     5         kx   fprintf( plist, "#                  * 'update'  - if already installed package should be updated by this\n" );
     5         kx   fprintf( plist, "#                                package archive;\n" );
     5         kx   fprintf( plist, "#   priority    - { REQUIRED|RECOMMENDED|OPTIONAL|SKIP }\n" );
     5         kx   fprintf( plist, "#                  synonims:\n" );
     5         kx   fprintf( plist, "#                    { REQUIRED    | required    | REQ | req }\n" );
     5         kx   fprintf( plist, "#                    { RECOMMENDED | recommended | REC | rec }\n" );
     5         kx   fprintf( plist, "#                    { OPTIONAL    | optional    | OPT | opt }\n" );
     5         kx   fprintf( plist, "#                    { SKIP        | skip        | SKP | skp }\n" );
     5         kx   fprintf( plist, "#\n" );
     5         kx 
     5         kx   if( extern_requires )
     5         kx   {
     5         kx     dlist_foreach( extern_requires, __print_extern_package, plist );
     5         kx     fprintf( plist, "#\n" );
     5         kx   }
     5         kx   dlist_foreach( provides, __print_provided_package, plist );
     5         kx 
     5         kx   fflush( plist );
     5         kx   fclose( plist );
     5         kx }
     5         kx 
     5         kx 
     5         kx /***************************************************************
     5         kx   Requires TREE functions:
     5         kx  */
     5         kx 
     5         kx struct _ctx
     5         kx {
     5         kx   FILE *output;
     5         kx   int   index, size, depth;
     5         kx };
     5         kx 
     5         kx /**************************
     5         kx   HTML Template Variables:
     5         kx  */
     5         kx static char *root       = NULL;
     5         kx static char *bug_url    = NULL;
     5         kx 
     5         kx static int   svg_width  = 2;
     5         kx static int   svg_height = 2;
     5         kx 
     5         kx static char *json_pkgs_file = NULL;
     5         kx static char *json_tree_file = NULL;
     5         kx 
     5         kx static char *copying = "Radix cross Linux";
     5         kx 
     5         kx #define max(a,b) ({ typeof (a) _a = (a); typeof (b) _b = (b); _a > _b ? _a : _b; })
     5         kx 
     5         kx /*
     5         kx   формирование имен файлов для вывода REQUIRES tree:
     5         kx 
     5         kx    json_fname              | last argument of make-pkglist | last argument type
     5         kx   -------------------------+-------------------------------+--------------------
     5         kx    './a.txt'               | a.txt                         | regular file
     5         kx    './a.json'              | a.json                        | regular file
     5         kx    './.json'               | .json                         | regular file
     5         kx    './khadas-vim.json'     | .                             | directory
     5         kx    './tmp/khadas-vim.json' | tmp                           | directory
     5         kx   -------------------------+-------------------------------+--------------------
     5         kx 
     5         kx    - если есть основное базовое имя файла и расширение,  то расширение
     5         kx      заменяем на: '.pkgs.json', '.tree.json', '.tree.html';
     5         kx 
     5         kx    - если есть основное базовое имя файла без расширения, то добавляем
     5         kx      расширение: '.pkgs.json', '.tree.json', '.tree.html';
     5         kx 
     5         kx    - если основное базовое имя файла начинается с точки, то расширение
     5         kx      заменяем на: 'pkgs.json', 'tree.json', 'tree.html'.
     5         kx */
     5         kx static void allocate_fnames( const char *json_fname )
     5         kx {
     5         kx   char *p, *e, *f = NULL;
     5         kx   char *buf = NULL;
     5         kx 
     5         kx   buf = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)buf, PATH_MAX );
     5         kx 
     5         kx   (void)sprintf( &buf[0], "%s", json_fname );
     5         kx   p = rindex( (const char *)&buf[0], '/' );
     5         kx   if( p )
     5         kx   {
     5         kx     if( p != &buf[0] ) f = ++p;
     5         kx     else               f = &buf[0];
     5         kx   }
     5         kx   e = rindex( (const char *)f, '.' );
     5         kx   if( e )
     5         kx   {
     5         kx     if( e != f )
     5         kx     {
     5         kx       (void)sprintf( e, ".pkgs.json" ); pkgs_fname = xstrdup( (const char *)&buf[0] );
     5         kx       (void)sprintf( e, ".tree.json" ); tree_fname = xstrdup( (const char *)&buf[0] );
     5         kx       (void)sprintf( e, ".tree.html" ); html_fname = xstrdup( (const char *)&buf[0] );
     5         kx 
     5         kx       (void)sprintf( e, ".pkgs.min.json" ); pkgs_min_fname = xstrdup( (const char *)&buf[0] );
     5         kx       (void)sprintf( e, ".tree.min.json" ); tree_min_fname = xstrdup( (const char *)&buf[0] );
     5         kx     }
     5         kx     else
     5         kx     {
     5         kx       (void)sprintf( e, "pkgs.json" ); pkgs_fname = xstrdup( (const char *)&buf[0] );
     5         kx       (void)sprintf( e, "tree.json" ); tree_fname = xstrdup( (const char *)&buf[0] );
     5         kx       (void)sprintf( e, "tree.html" ); html_fname = xstrdup( (const char *)&buf[0] );
     5         kx 
     5         kx       (void)sprintf( e, "pkgs.min.json" ); pkgs_min_fname = xstrdup( (const char *)&buf[0] );
     5         kx       (void)sprintf( e, "tree.min.json" ); tree_min_fname = xstrdup( (const char *)&buf[0] );
     5         kx     }
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     e = f + strlen( f );
     5         kx 
     5         kx     (void)sprintf( e, ".pkgs.json" ); pkgs_fname = xstrdup( (const char *)&buf[0] );
     5         kx     (void)sprintf( e, ".tree.json" ); tree_fname = xstrdup( (const char *)&buf[0] );
     5         kx     (void)sprintf( e, ".tree.html" ); html_fname = xstrdup( (const char *)&buf[0] );
     5         kx 
     5         kx     (void)sprintf( e, ".pkgs.min.json" ); pkgs_min_fname = xstrdup( (const char *)&buf[0] );
     5         kx     (void)sprintf( e, ".tree.min.json" ); tree_min_fname = xstrdup( (const char *)&buf[0] );
     5         kx   }
     5         kx 
     5         kx   if( minimize )
     5         kx   {
     5         kx     json_pkgs_file = xstrdup( (const char *)basename( pkgs_min_fname ) );
     5         kx     json_tree_file = xstrdup( (const char *)basename( tree_min_fname ) );
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     json_pkgs_file = xstrdup( (const char *)basename( pkgs_fname ) );
     5         kx     json_tree_file = xstrdup( (const char *)basename( tree_fname ) );
     5         kx   }
     5         kx 
     5         kx   free( buf );
     5         kx }
     5         kx 
     5         kx 
     5         kx /*******************************************************************
     5         kx   find_pkg():
     5         kx   ----------
     5         kx     Returns package found in packages list coresponded to pkg.
     5         kx  */
     5         kx static struct package *find_pkg( struct dlist *list, struct pkg *pkg )
     5         kx {
     5         kx   struct package *package = NULL;
     5         kx   struct dlist   *found   = NULL;
     5         kx 
     5         kx   if( !pkg ) return package;
     5         kx 
     5         kx   found = dlist_find_data( list, __compare_provided, (const void *)pkg );
     5         kx   if( found )
     5         kx   {
     5         kx     return (struct package *)found->data;
     5         kx   }
     5         kx 
     5         kx   return package;
     5         kx }
     5         kx 
     5         kx /*******************************************************************
     5         kx   find_package():
     5         kx   --------------
     5         kx     Returns package found in packages list coresponded to package.
     5         kx  */
     5         kx static struct package *find_package( struct dlist *list, struct package *pkg )
     5         kx {
     5         kx   struct package *package = NULL;
     5         kx   struct dlist   *found   = NULL;
     5         kx 
     5         kx   if( !pkg ) return package;
     5         kx 
     5         kx   found = dlist_find_data( list, __compare_packages, (const void *)pkg );
     5         kx   if( found )
     5         kx   {
     5         kx     return (struct package *)found->data;
     5         kx   }
     5         kx 
     5         kx   return package;
     5         kx }
     5         kx 
     5         kx static void __print_package_data( FILE *output, struct package *package )
     5         kx {
     5         kx   if( !output || !package ) return;
     5         kx 
     5         kx   /* "id": "net:bind-9.10.1", */
     5         kx   if( package->pkginfo->group ) {
     5         kx     fprintf( output, "  \"id\": \"%s:%s-%s\",\n", package->pkginfo->group,
     5         kx                                                   package->pkginfo->name,
     5         kx                                                   package->pkginfo->version );
     5         kx   } else {
     5         kx     fprintf( output, "  \"id\": \"%s-%s\",\n", package->pkginfo->name,
     5         kx                                                package->pkginfo->version );
     5         kx   }
     5         kx   /* "name": "bind", */
     5         kx   fprintf( output, "  \"name\": \"%s\",\n", package->pkginfo->name );
     5         kx   /* "version": "9.10.1", */
     5         kx   fprintf( output, "  \"version\": \"%s\",\n", package->pkginfo->version );
     5         kx   /* "group": "net", */
     5         kx   if( package->pkginfo->group ) {
     5         kx     fprintf( output, "  \"group\": \"%s\",\n", package->pkginfo->group );
     5         kx   } else {
     5         kx     fprintf( output, "  \"group\": \"\",\n" );
     5         kx   }
     5         kx   /* "arch": "omap543x-eglibc", */
     5         kx   fprintf( output, "  \"arch\": \"%s\",\n", package->pkginfo->arch );
     5         kx   /* "hardware": "omap5uevm", */
     5         kx   fprintf( output, "  \"hardware\": \"%s\",\n", hardware );
     5         kx   /* "license": "custom", */
     5         kx   fprintf( output, "  \"license\": \"%s\",\n", package->pkginfo->license );
     5         kx   /* "description": "bind 9.10.1 (DNS server and utilities)", */
     5         kx   fprintf( output, "  \"description\": \"%s %s (%s)\",\n", package->pkginfo->name,
     5         kx                                                            package->pkginfo->version,
     5         kx                                                            package->pkginfo->short_description );
     5         kx   /* "uncompressed_size": "17M", */
     5         kx   fprintf( output, "  \"uncompressed_size\": \"" );
     5         kx   if( package->pkginfo->uncompressed_size > 1048576 ) {
     5         kx     fprintf( output, "%ldG\",\n", package->pkginfo->uncompressed_size / 1048576 );
     5         kx   } else if( package->pkginfo->uncompressed_size > 1024 ) {
     5         kx     fprintf( output, "%ldM\",\n", package->pkginfo->uncompressed_size / 1024 );
     5         kx   } else {
     5         kx     fprintf( output, "%ldK\",\n", package->pkginfo->uncompressed_size );
     5         kx   }
     5         kx   /* "total_files": "421" */
     5         kx   fprintf( output, "  \"total_files\": \"%d\"\n", package->pkginfo->total_files );
     5         kx }
     5         kx 
     5         kx static void __print_pkgs_node( void *data, void *user_data )
     5         kx {
     5         kx   struct package *package = (struct package *)data;
     5         kx   struct _ctx    *ctx     = (struct _ctx *)user_data;
     5         kx 
     5         kx   if( !package || !ctx ) return;
     5         kx 
     5         kx   if( ctx->index != 0 )
     5         kx   {
     5         kx     fprintf( ctx->output, " },\n {\n" );
     5         kx   }
     5         kx   __print_package_data( ctx->output, package );
     5         kx   ++ctx->index;
     5         kx }
     5         kx 
     5         kx static void print_pkgs_json( FILE *output, struct dlist *list )
     5         kx {
     5         kx   struct _ctx ctx;
     5         kx 
     5         kx   if( !output ) return;
     5         kx 
     5         kx   bzero( (void *)&ctx, sizeof(struct _ctx) );
     5         kx 
     5         kx   ctx.output = output;
     5         kx   ctx.index  = 0;
     5         kx 
     5         kx   fprintf( output, "[{\n" );
     5         kx 
     5         kx   dlist_foreach( list, __print_pkgs_node, (void *)&ctx );
     5         kx 
     5         kx   fprintf( output, " }]\n" );
     5         kx }
     5         kx 
     5         kx static void __remove_required_package( void *data, void *user_data )
     5         kx {
     5         kx   struct package *package = NULL;
     5         kx   struct pkg     *pkg = (struct pkg *)data;
     5         kx 
     5         kx   if( pkg )
     5         kx   {
     5         kx     package = find_pkg( tree, pkg );
     5         kx     if( package )
     5         kx     {
     5         kx       /*******************************************
     5         kx         if package reqired for some other package
     5         kx         we have to remove it from tree list:
     5         kx        */
     5         kx       tree = dlist_remove_data( tree, __compare_packages, NULL, (const void *)package );
     5         kx     }
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __remove_required_packages( void *data, void *user_data )
     5         kx {
     5         kx   struct package *package = (struct package *)data;
     5         kx   struct dlist   *list = NULL;
     5         kx 
     5         kx   if( !package ) return;
     5         kx 
     5         kx   if( !(list = package->requires->list) ) return;
     5         kx 
     5         kx   dlist_foreach( list, __remove_required_package, NULL );
     5         kx }
     5         kx 
     5         kx static void remove_required_packages( struct dlist *list )
     5         kx {
     5         kx   dlist_foreach( list, __remove_required_packages, NULL );
     5         kx }
     5         kx 
     5         kx 
     5         kx static void __check_pkg_requires( void *data, void *user_data )
     5         kx {
     5         kx   struct pkg *pkg     = (struct pkg *)data;
     5         kx   int        *counter = (int *)user_data;
     5         kx 
     5         kx   if( pkg )
     5         kx   {
     5         kx     struct package *package = find_pkg( provides, pkg );
     5         kx     if( package ) { ++(*counter); }
     5         kx   }
     5         kx }
     5         kx 
     5         kx static int check_pkg_requires( struct dlist *list )
     5         kx {
     5         kx   int cnt = 0;
     5         kx   dlist_foreach( list, __check_pkg_requires, (void *)&cnt );
     5         kx   return cnt;
     5         kx }
     5         kx 
     5         kx 
     5         kx /***************************************************************
     5         kx   Sort Requires Tree functions:
     5         kx   ----------------------------
     5         kx 
     5         kx   NOTE:
     5         kx     Requires sorted in reverse installation order according to
     5         kx     provides list.
     5         kx  */
     5         kx 
     5         kx static int __install_pkg_index( struct dlist *list, struct pkg *pkg )
     5         kx {
     5         kx   int index = -1;
     5         kx 
     5         kx   if( !pkg ) return index;
     5         kx 
     5         kx   if( list )
     5         kx   {
     5         kx     struct package *package = find_pkg( list, pkg );
     5         kx 
     5         kx     index = dlist_index( list, package );
     5         kx   }
     5         kx 
     5         kx   return index;
     5         kx }
     5         kx 
     5         kx static int __install_package_index( struct dlist *list, struct package *package )
     5         kx {
     5         kx   int index = -1;
     5         kx 
     5         kx   if( !package ) return index;
     5         kx 
     5         kx   if( list )
     5         kx     index = dlist_index( list, package );
     5         kx 
     5         kx   return index;
     5         kx }
     5         kx 
     5         kx static int __compare_pkg_order( const void *a, const void *b )
     5         kx {
     5         kx   int  ret = 0;
     5         kx   int  ia = -1, ib = -1;
     5         kx 
     5         kx   ia = __install_pkg_index( provides, (struct pkg *)a );
     5         kx   ib = __install_pkg_index( provides, (struct pkg *)b );
     5         kx 
     5         kx   if( ia < ib ) ret = -1;
     5         kx   if( ia > ib ) ret =  1;
     5         kx 
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx static int __compare_package_order( const void *a, const void *b )
     5         kx {
     5         kx   int  ret = 0;
     5         kx   int  ia = -1, ib = -1;
     5         kx 
     5         kx   ia = __install_package_index( provides, (struct package *)a );
     5         kx   ib = __install_package_index( provides, (struct package *)b );
     5         kx 
     5         kx   if( ia < ib ) ret = -1;
     5         kx   if( ia > ib ) ret =  1;
     5         kx 
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx static void __sort_requires( void *data, void *user_data )
     5         kx {
     5         kx   struct package *package = (struct package *)data;
     5         kx   struct dlist   *reqs    = NULL;
     5         kx 
     5         kx   if( !package ) return;
     5         kx 
     5         kx   if( (reqs = package->requires->list) && check_pkg_requires( reqs ) > 0 )
     5         kx   {
     5         kx     package->requires->list = reqs = dlist_sort( reqs, __compare_pkg_order );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static struct dlist *sort_requires_tree( struct dlist *list )
     5         kx {
     5         kx   int lenght = 0;
     5         kx 
     5         kx   if( !list ) return list;
     5         kx 
     5         kx   lenght = dlist_length( list );
     5         kx 
     5         kx   if( lenght > 1 )
     5         kx     list = dlist_sort( list, __compare_package_order );
     5         kx 
     5         kx   return list;
     5         kx }
     5         kx 
     5         kx static void sort_requires( struct dlist *list )
     5         kx {
     5         kx   int lenght = 0;
     5         kx 
     5         kx   if( !list ) return;
     5         kx 
     5         kx   dlist_foreach( list, __sort_requires, NULL );
     5         kx }
     5         kx /*
     5         kx   End of Sort Requires Tree functions:
     5         kx  ***************************************************************/
     5         kx 
     5         kx /***************************************************************
     5         kx   Binary Tree functions:
     5         kx   ---------------------
     5         kx  */
     5         kx static struct dlist *pkgs  = NULL;
     5         kx static struct btree *btree = NULL;
     5         kx 
     5         kx static struct pkg *duplicate_pkg( struct package *package )
     5         kx {
     5         kx   struct pkg *pkg = NULL;
     5         kx 
     5         kx   if( !package ) return pkg;
     5         kx 
     5         kx   pkg = pkg_alloc();
     5         kx   pkg->name      = xstrdup( (const char *)package->pkginfo->name );
     5         kx   pkg->group     = xstrdup( (const char *)package->pkginfo->group );
     5         kx   pkg->version   = xstrdup( (const char *)package->pkginfo->version );
     5         kx   pkg->procedure = package->procedure;
     5         kx 
     5         kx   return pkg;
     5         kx }
     5         kx 
     5         kx static void __fill_pkgs_list( void *data, void *user_data )
     5         kx {
     5         kx   struct package *package = (struct package *)data;
     5         kx   struct pkg     *pkg     = NULL;
     5         kx 
     5         kx   if( !package ) return;
     5         kx 
     5         kx   pkg  = duplicate_pkg( package );
     5         kx   pkgs = dlist_append( pkgs, (void *)pkg );
     5         kx }
     5         kx 
     5         kx /*******************************************
     5         kx    create_pkgs_list():
     5         kx    ------------------
     5         kx      Creates pkgs list from provides list.
     5         kx  */
     5         kx static void create_pkgs_list( struct dlist *list )
     5         kx {
     5         kx   if( !list ) return;
     5         kx 
     5         kx   dlist_foreach( list, __fill_pkgs_list, NULL );
     5         kx }
     5         kx 
     5         kx static void free_pkgs_list()
     5         kx {
     5         kx   if( pkgs )
     5         kx   {
     5         kx     dlist_free( pkgs, __pkg_free_func );
     5         kx     pkgs = NULL;
     5         kx   }
     5         kx }
     5         kx 
     5         kx static int __compare_pkg( const void *a, const void *b )
     5         kx {
     5         kx   int  ret = -1;
     5         kx 
     5         kx   struct pkg *pkg1 = (struct pkg *)a;
     5         kx   struct pkg *pkg2 = (struct pkg *)b;
     5         kx 
     5         kx   if( pkg1->group && pkg2->group )
     5         kx   {
     5         kx     ret = strcmp( pkg1->group, pkg2->group );
     5         kx   }
     5         kx   else if( !pkg1->group && !pkg2->group )
     5         kx   {
     5         kx     ret = 0;
     5         kx   }
     5         kx   else if( pkg1->group )
     5         kx   {
     5         kx     ret = 1;
     5         kx   }
     5         kx 
     5         kx   if( ! ret )
     5         kx   {
     5         kx     return strcmp( pkg1->name, pkg2->name );
     5         kx   }
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx static struct pkg *__find_pkg( struct dlist *list, struct pkg *package )
     5         kx {
     5         kx   struct pkg   *pkg   = NULL;
     5         kx   struct dlist *found = NULL;
     5         kx 
     5         kx   if( !package ) return pkg;
     5         kx 
     5         kx   found = dlist_find_data( list, __compare_pkg, (const void *)package );
     5         kx   if( found )
     5         kx   {
     5         kx     return (struct pkg *)found->data;
     5         kx   }
     5         kx 
     5         kx   return pkg;
     5         kx }
     5         kx 
     5         kx static int __compare_pkg_with_package( const void *a, const void *b )
     5         kx {
     5         kx   int  ret = -1;
     5         kx 
     5         kx   struct     pkg *pkg1 = (struct     pkg *)a;
     5         kx   struct package *pkg2 = (struct package *)b;
     5         kx 
     5         kx   if( pkg1->group && pkg2->pkginfo->group )
     5         kx   {
     5         kx     ret = strcmp( pkg1->group, pkg2->pkginfo->group );
     5         kx   }
     5         kx   else if( !pkg1->group && !pkg2->pkginfo->group )
     5         kx   {
     5         kx     ret = 0;
     5         kx   }
     5         kx   else if( pkg2->pkginfo->group )
     5         kx   {
     5         kx     ret = 1;
     5         kx   }
     5         kx 
     5         kx   if( ! ret )
     5         kx   {
     5         kx     return strcmp( pkg1->name, pkg2->pkginfo->name );
     5         kx   }
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx static struct pkg *__find_pkg_by_package( struct dlist *list, struct package *package )
     5         kx {
     5         kx   struct pkg   *pkg   = NULL;
     5         kx   struct dlist *found = NULL;
     5         kx 
     5         kx   if( !package ) return pkg;
     5         kx 
     5         kx   found = dlist_find_data( list, __compare_pkg_with_package, (const void *)package );
     5         kx   if( found )
     5         kx   {
     5         kx     return (struct pkg *)found->data;
     5         kx   }
     5         kx 
     5         kx   return pkg;
     5         kx }
     5         kx 
     5         kx static struct pkg *__find_pkg_by_pkg( struct dlist *list, struct pkg *package )
     5         kx {
     5         kx   struct pkg   *pkg   = NULL;
     5         kx   struct dlist *found = NULL;
     5         kx 
     5         kx   if( !package ) return pkg;
     5         kx 
     5         kx   found = dlist_find_data( list, __compare_pkg, (const void *)package );
     5         kx   if( found )
     5         kx   {
     5         kx     return (struct pkg *)found->data;
     5         kx   }
     5         kx 
     5         kx   return pkg;
     5         kx }
     5         kx 
     5         kx static void __btree_add_requires( struct btree *tree );
     5         kx 
     5         kx static struct btree *__btree_add_left( void *data, void *user_data )
     5         kx {
     5         kx   struct btree   *tree = (struct btree *)user_data;
     5         kx   struct pkg     *left = (struct pkg *)data;
     5         kx   struct pkg     *pkg  = NULL;
     5         kx   struct btree   *node = NULL;
     5         kx 
     5         kx   if( !tree || !left ) return node;
     5         kx 
     5         kx   pkg = __find_pkg_by_pkg( pkgs, left );
     5         kx 
     5         kx   node = btree_insert_left( tree, __btree_alloc( (void *)pkg ) );
     5         kx   __btree_add_requires( node );
     5         kx 
     5         kx   return node;
     5         kx }
     5         kx 
     5         kx static void __btree_add_right( void *data, void *user_data )
     5         kx {
     5         kx   struct btree   *tree  = *((struct btree **)user_data);
     5         kx   struct pkg     *right = (struct pkg *)data;
     5         kx   struct pkg     *pkg  = NULL;
     5         kx   struct btree   *node  = NULL;
     5         kx 
     5         kx   if( !tree || !right ) return;
     5         kx 
     5         kx   pkg = __find_pkg_by_pkg( pkgs, right );
     5         kx 
     5         kx   node = btree_insert_right( tree, __btree_alloc( (void *)pkg ) );
     5         kx   __btree_add_requires( node );
     5         kx 
     5         kx   *((struct btree **)user_data) = node;
     5         kx }
     5         kx 
     5         kx static void __btree_add_requires( struct btree *tree )
     5         kx {
     5         kx   struct package *package = NULL;
     5         kx 
     5         kx   if( !tree ) return;
     5         kx 
     5         kx   package = find_pkg( provides, (struct pkg *)tree->data );
     5         kx   if( package )
     5         kx   {
     5         kx     struct dlist *list = NULL;
     5         kx 
     5         kx     if( (list = package->requires->list) )
     5         kx     {
     5         kx       struct pkg   *pkg  = NULL;
     5         kx       struct btree *node = NULL;
     5         kx 
     5         kx       pkg = __find_pkg_by_pkg( pkgs, (struct pkg *)list->data );
     5         kx 
     5         kx       node = __btree_add_left( (void *)pkg, (void *)tree );
     5         kx 
     5         kx       if( dlist_length( list ) > 1 )
     5         kx       {
     5         kx         dlist_foreach( list->next, __btree_add_right, (void *)&node );
     5         kx       }
     5         kx     }
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __fill_btree( void *data, void *user_data )
     5         kx {
     5         kx   struct btree   *tree    = *((struct btree **)user_data);
     5         kx   struct package *package = (struct package *)data;
     5         kx   struct pkg     *pkg     = NULL;
     5         kx   struct btree   *node    = NULL;
     5         kx 
     5         kx   if( !tree || !package ) return;
     5         kx 
     5         kx   pkg = __find_pkg_by_package( pkgs, package );
     5         kx 
     5         kx   node = btree_insert_right( tree, __btree_alloc( (void *)pkg ) );
     5         kx   __btree_add_requires( node );
     5         kx 
     5         kx   *((struct btree **)user_data) = node;
     5         kx }
     5         kx 
     5         kx /*******************************************************************
     5         kx   __print_btree_pkg():
     5         kx   -------------------
     5         kx     Print out package "group/name-version". Used for debuging only.
     5         kx  */
     5         kx static void __print_btree_pkg( void *data, void *user_data )
     5         kx {
     5         kx   struct pkg *pkg = (struct pkg *)data;
     5         kx 
     5         kx   if( !pkg ) return;
     5         kx 
     5         kx   fprintf( stdout, "%s/%s-%s\n", pkg->group, pkg->name, pkg->version );
     5         kx }
     5         kx 
     5         kx /*****************************************************************
     5         kx   __print_btree_node():
     5         kx   --------------------
     5         kx     Print out package in JSON format. Used by btree_print_json().
     5         kx  */
     5         kx static void __print_btree_node( void *data, void *user_data )
     5         kx {
     5         kx   struct pkg   *pkg = (struct pkg *)data;
     5         kx   struct _bctx *ctx = (struct _bctx *)user_data;
     5         kx 
     5         kx   char *p, buf[PATH_MAX*2];
     5         kx   int   depth = 0, max_depth = PATH_MAX + PATH_MAX / 2;
     5         kx 
     5         kx   if( !pkg || !ctx ) return;
     5         kx 
     5         kx   buf[0] = ' ';
     5         kx   buf[1] = '\0';
     5         kx 
     5         kx   p = (char *)&buf[1];
     5         kx   depth = ctx->indent;
     5         kx 
     5         kx   if( depth < 1 ) depth = 0;
     5         kx   if( depth > max_depth ) depth = max_depth;
     5         kx 
     5         kx   while( depth )
     5         kx   {
     5         kx     (void)sprintf( p, " " ); --depth; ++p; *p = '\0';
     5         kx   }
     5         kx 
     5         kx   if( pkg->group )
     5         kx     (void)sprintf( p, "\"name\": \"%s:%s-%s\"", pkg->group,
     5         kx                                                 pkg->name,
     5         kx                                                 pkg->version );
     5         kx   else
     5         kx     (void)sprintf( p, "\"name\": \"%s-%s\"", pkg->name,
     5         kx                                              pkg->version );
     5         kx 
     5         kx   fprintf( ctx->output, (char *)&buf[0] );
     5         kx }
     5         kx 
     5         kx static int __width_factor( int width )
     5         kx {
     5         kx   double w, x = (double)width;
     5         kx 
     5         kx   if( width < 2 ) return 48;
     5         kx 
     5         kx   if( width > 1 && width < 150 )
     5         kx   {
     5         kx     w = floor( (38.399 - 7.4262 * log( x )) + 8.0 );
     5         kx 
     5         kx     return (int)w;
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     return 8;
     5         kx   }
     5         kx }
     5         kx 
     5         kx /*******************************************************************
     5         kx   __print_btree_header():
     5         kx   ----------------------
     5         kx     Print out Binary Tree Header.
     5         kx  */
     5         kx static void __print_btree_header( FILE *fp, struct btree *btree, struct dlist *tree )
     5         kx {
     5         kx   struct package *package = NULL;
     5         kx 
     5         kx   if( !fp || !btree || !tree ) return;
     5         kx 
     5         kx   package = find_pkg( provides, (struct pkg *)btree->data );
     5         kx 
     5         kx   if( package )
     5         kx   {
     5         kx     char *buf = NULL;
     5         kx 
     5         kx     if( dlist_length( tree ) > 1 )
     5         kx     {
     5         kx       buf = (char *)malloc( (size_t)PATH_MAX );
     5         kx       if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx       bzero( (void *)buf, PATH_MAX );
     5         kx 
     5         kx       (void)sprintf( &buf[0], "%s", htmlroot );
     5         kx       root = xstrdup( (const char *)&buf[0] );
     5         kx       (void)sprintf( &buf[0], "%s", package->pkginfo->url );
     5         kx       bug_url = xstrdup( (const char *)&buf[0] );
     5         kx       free( buf );
     5         kx     }
     5         kx     else
     5         kx     {
     5         kx       buf = (char *)malloc( (size_t)PATH_MAX );
     5         kx       if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx       bzero( (void *)buf, PATH_MAX );
     5         kx 
     5         kx       if( package->pkginfo->group )
     5         kx         (void)sprintf( &buf[0], "%s/%s-%s", package->pkginfo->group,
     5         kx                                             package->pkginfo->name,
     5         kx                                             package->pkginfo->version );
     5         kx       else
     5         kx         (void)sprintf( &buf[0], "%s-%s", package->pkginfo->name,
     5         kx                                          package->pkginfo->version );
     5         kx 
     5         kx       root = xstrdup( (const char *)&buf[0] );
     5         kx       (void)sprintf( &buf[0], "%s", package->pkginfo->url );
     5         kx       bug_url = xstrdup( (const char *)&buf[0] );
     5         kx       free( buf );
     5         kx     }
     5         kx 
     5         kx     fprintf( fp, " \"distro\": [ \"%s\", \"%s\", \"%s\" ],\n",
     5         kx                                    package->pkginfo->distro_name,
     5         kx                                            package->pkginfo->distro_version,
     5         kx                                                     package->pkginfo->url );
     5         kx   }
     5         kx }
     5         kx 
     5         kx 
     5         kx /***************************************
     5         kx   create_btree():
     5         kx   --------------
     5         kx     Creates btree from tree list (DAG).
     5         kx  */
     5         kx static void create_btree( struct dlist *dag, struct dlist *install )
     5         kx {
     5         kx   struct pkg     *pkg        = NULL;
     5         kx   struct package *package    = NULL;
     5         kx   struct dlist   *list       = NULL;
     5         kx   struct btree   *node       = NULL;
     5         kx 
     5         kx   if( !dag || !install ) return;
     5         kx 
     5         kx   /* first package: */
     5         kx   package = (struct package *)dag->data;
     5         kx   pkg     = __find_pkg_by_package( pkgs, package );
     5         kx 
     5         kx   node = btree = __btree_alloc( (void *)pkg );
     5         kx 
     5         kx   __btree_add_requires( node );
     5         kx 
     5         kx   if( dlist_length( dag ) > 1 )
     5         kx     dlist_foreach( dag->next, __fill_btree, (void *)&node );
     5         kx 
     5         kx   btree_reduce( btree, __compare_pkg, NULL );
     5         kx }
     5         kx /*
     5         kx   End of Binary Tree functions:
     5         kx  ***************************************************************/
     5         kx 
     5         kx 
     5         kx /***************************************************************
     5         kx   Print json format of DAG functions:
     5         kx  */
     5         kx static void __print_pkg_tree( struct _ctx *ctx, struct dlist *list )
     5         kx {
     5         kx   struct dlist *next = NULL;
     5         kx 
     5         kx   if( !ctx || !list ) return;
     5         kx 
     5         kx   ctx->depth += 2;
     5         kx   svg_width = max( svg_width, ctx->depth );
     5         kx 
     5         kx   while( list )
     5         kx   {
     5         kx     next = dlist_next( list );
     5         kx     {
     5         kx       struct pkg     *pkg     = (struct pkg *)list->data;
     5         kx       struct package *package = find_pkg( provides, pkg );
     5         kx 
     5         kx       if( package )
     5         kx       {
     5         kx         char *p, *buf = NULL;
     5         kx         int   depth = 0;
     5         kx 
     5         kx         struct dlist *reqs = NULL;
     5         kx 
     5         kx         buf = (char *)malloc( (size_t)PATH_MAX );
     5         kx         if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx         bzero( (void *)buf, PATH_MAX );
     5         kx 
     5         kx         buf[0] = ' ';
     5         kx         buf[1] = '\0';
     5         kx 
     5         kx         p = (char *)&buf[1];
     5         kx         depth = ctx->depth;
     5         kx 
     5         kx         while( depth ) { (void)sprintf( p, " " ); --depth; ++p; *p = '\0'; }
     5         kx 
     5         kx         (void)sprintf( p - 1, "{\n" );
     5         kx         fprintf( ctx->output, (char *)&buf[0] );
     5         kx         *(p - 1) = ' '; *p = '\0';
     5         kx 
     5         kx         if( pkg->group )
     5         kx           (void)sprintf( p, "\"name\": \"%s:%s-%s\"", pkg->group,
     5         kx                                                       pkg->name,
     5         kx                                                       pkg->version );
     5         kx         else
     5         kx           (void)sprintf( p, "\"name\": \"%s-%s\"", pkg->name,
     5         kx                                                    pkg->version );
     5         kx 
     5         kx         fprintf( ctx->output, (char *)&buf[0] );
     5         kx 
     5         kx         if( (reqs = package->requires->list) && check_pkg_requires( reqs ) > 0 )
     5         kx         {
     5         kx           fprintf( ctx->output, ",\n" );
     5         kx 
     5         kx           (void)sprintf( p, "\"children\": [\n" );
     5         kx           fprintf( ctx->output, (char *)&buf[0] );
     5         kx 
     5         kx           __print_pkg_tree( ctx, reqs );
     5         kx 
     5         kx           (void)sprintf( p, "]\n" );
     5         kx           fprintf( ctx->output, (char *)&buf[0] );
     5         kx         }
     5         kx         else
     5         kx         {
     5         kx           fprintf( ctx->output, "\n" );
     5         kx         }
     5         kx 
     5         kx         (void)sprintf( p - 1, "}" );
     5         kx         fprintf( ctx->output, (char *)&buf[0] );
     5         kx         *(p - 1) = ' '; *p = '\0';
     5         kx 
     5         kx         if( next ) { fprintf( ctx->output, ",\n" ); }
     5         kx         else       { fprintf( ctx->output, "\n" );  }
     5         kx 
     5         kx         free( buf );
     5         kx       } /* End if( package )  */
     5         kx     }
     5         kx     list = next;
     5         kx   } /* End of while( list ) */
     5         kx 
     5         kx   ctx->depth -= 2;
     5         kx }
     5         kx 
     5         kx static void __print_package_node( struct _ctx *ctx, struct package *package )
     5         kx {
     5         kx   char *p, *buf = NULL;
     5         kx   int   depth = 0;
     5         kx 
     5         kx   struct dlist *list = NULL;
     5         kx 
     5         kx   if( !package || !ctx ) return;
     5         kx 
     5         kx   buf = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)buf, PATH_MAX );
     5         kx 
     5         kx   buf[0] = ' ';
     5         kx   buf[1] = '\0';
     5         kx 
     5         kx   p = (char *)&buf[1];
     5         kx   depth = ctx->depth;
     5         kx 
     5         kx   while( depth ) { (void)sprintf( p, " " ); --depth; ++p; *p = '\0'; }
     5         kx 
     5         kx   (void)sprintf( p - 1, "{\n" );
     5         kx   fprintf( ctx->output, (char *)&buf[0] );
     5         kx   *(p - 1) = ' '; *p = '\0';
     5         kx 
     5         kx   if( package->pkginfo->group )
     5         kx     (void)sprintf( p, "\"name\": \"%s:%s-%s\"", package->pkginfo->group,
     5         kx                                                 package->pkginfo->name,
     5         kx                                                 package->pkginfo->version );
     5         kx   else
     5         kx     (void)sprintf( p, "\"name\": \"%s-%s\"", package->pkginfo->name,
     5         kx                                              package->pkginfo->version );
     5         kx 
     5         kx   fprintf( ctx->output, (char *)&buf[0] );
     5         kx 
     5         kx   if( (list = package->requires->list) && check_pkg_requires( list ) > 0 )
     5         kx   {
     5         kx     fprintf( ctx->output, ",\n" );
     5         kx 
     5         kx     (void)sprintf( p, "\"children\": [\n" );
     5         kx     fprintf( ctx->output, (char *)&buf[0] );
     5         kx 
     5         kx     __print_pkg_tree( ctx, list );
     5         kx 
     5         kx     (void)sprintf( p, "]\n" );
     5         kx     fprintf( ctx->output, (char *)&buf[0] );
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     fprintf( ctx->output, "\n" );
     5         kx   }
     5         kx 
     5         kx   (void)sprintf( p - 1, "}" );
     5         kx   fprintf( ctx->output, (char *)&buf[0] );
     5         kx   *(p - 1) = ' '; *p = '\0';
     5         kx 
     5         kx   free( buf );
     5         kx }
     5         kx 
     5         kx static void __print_tree_node( void *data, void *user_data )
     5         kx {
     5         kx   struct package *package = (struct package *)data;
     5         kx   struct _ctx    *ctx     = (struct _ctx *)user_data;
     5         kx 
     5         kx   if( !package || !ctx ) return;
     5         kx 
     5         kx   if( ctx->size > 1 )
     5         kx   {
     5         kx     if( ctx->index == 0 )
     5         kx     {
     5         kx       char *buf = NULL;
     5         kx 
     5         kx       buf = (char *)malloc( (size_t)PATH_MAX );
     5         kx       if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx       bzero( (void *)buf, PATH_MAX );
     5         kx 
     5         kx       (void)sprintf( &buf[0], "%s", htmlroot );
     5         kx       root = xstrdup( (const char *)&buf[0] );
     5         kx       (void)sprintf( &buf[0], "%s", package->pkginfo->url );
     5         kx       bug_url = xstrdup( (const char *)&buf[0] );
     5         kx       free( buf );
     5         kx 
     5         kx       fprintf( ctx->output, " \"distro\": [ \"%s\", \"%s\", \"%s\" ],\n",
     5         kx                                               package->pkginfo->distro_name,
     5         kx                                                       package->pkginfo->distro_version,
     5         kx                                                                package->pkginfo->url );
     5         kx       fprintf( ctx->output, " \"name\": \"%s\",\n", htmlroot );
     5         kx       fprintf( ctx->output, " \"children\": [\n" );
     5         kx     }
     5         kx 
     5         kx 
     5         kx     __print_package_node( ctx, package );
     5         kx     svg_height += 2;
     5         kx 
     5         kx 
     5         kx     if( ctx->index < ctx->size - 1 ) fprintf( ctx->output, "," );
     5         kx     else                             fprintf( ctx->output, "\n ]" );
     5         kx 
     5         kx     fprintf( ctx->output, "\n" );
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     struct dlist *reqs = NULL;
     5         kx     char *buf = NULL;
     5         kx 
     5         kx     buf = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx     bzero( (void *)buf, PATH_MAX );
     5         kx 
     5         kx     if( package->pkginfo->group )
     5         kx       (void)sprintf( &buf[0], "%s/%s-%s", package->pkginfo->group,
     5         kx                                           package->pkginfo->name,
     5         kx                                           package->pkginfo->version );
     5         kx     else
     5         kx       (void)sprintf( &buf[0], "%s-%s", package->pkginfo->name,
     5         kx                                        package->pkginfo->version );
     5         kx 
     5         kx     root = xstrdup( (const char *)&buf[0] );
     5         kx     (void)sprintf( &buf[0], "%s", package->pkginfo->url );
     5         kx     bug_url = xstrdup( (const char *)&buf[0] );
     5         kx     free( buf );
     5         kx 
     5         kx     fprintf( ctx->output, " \"distro\": [ \"%s\", \"%s\", \"%s\" ],\n",
     5         kx                                             package->pkginfo->distro_name,
     5         kx                                                     package->pkginfo->distro_version,
     5         kx                                                              package->pkginfo->url );
     5         kx     if( package->pkginfo->group )
     5         kx       fprintf( ctx->output, " \"name\": \"%s:%s-%s\"", package->pkginfo->group,
     5         kx                                                        package->pkginfo->name,
     5         kx                                                        package->pkginfo->version );
     5         kx     else
     5         kx       fprintf( ctx->output, " \"name\": \"%s-%s\"", package->pkginfo->name,
     5         kx                                                     package->pkginfo->version );
     5         kx 
     5         kx 
     5         kx     svg_height += 2;
     5         kx     ctx->depth  -=2;
     5         kx 
     5         kx     if( (reqs = package->requires->list) && check_pkg_requires( reqs ) > 0 )
     5         kx     {
     5         kx       fprintf( ctx->output, ",\n" );
     5         kx 
     5         kx       fprintf( ctx->output, " \"children\": [\n" );
     5         kx 
     5         kx       __print_pkg_tree( ctx, reqs );
     5         kx 
     5         kx       fprintf( ctx->output, " ]\n" );
     5         kx     }
     5         kx 
     5         kx   }
     5         kx 
     5         kx   ++ctx->index;
     5         kx }
     5         kx 
     5         kx static void print_tree_json( FILE *output, struct dlist *list )
     5         kx {
     5         kx   struct _ctx ctx;
     5         kx 
     5         kx   if( !output || !list ) return;
     5         kx 
     5         kx   bzero( (void *)&ctx, sizeof(struct _ctx) );
     5         kx 
     5         kx   ctx.output = output;
     5         kx   ctx.index  = 0;
     5         kx   ctx.size   = dlist_length( list );
     5         kx   ctx.depth  = 2;
     5         kx 
     5         kx   fprintf( output, "{\n" );
     5         kx   dlist_foreach( list, __print_tree_node, (void *)&ctx );
     5         kx   fprintf( output, "}\n" );
     5         kx 
     5         kx   svg_height += svg_width / 2;
     5         kx 
     5         kx   svg_width  = (svg_width  + 4) * 160;
     5         kx   svg_height = (svg_height + 4) * 24;
     5         kx }
     5         kx /*
     5         kx   End of print json format of DAG functions.
     5         kx  ***************************************************************/
     5         kx 
     5         kx #include <pkglist.html.c>
     5         kx 
     5         kx void print_provides_tree( const char *json_fname, enum _tree_format tree_format )
     5         kx {
     5         kx   FILE *pkgs_fp = NULL, *tree_fp = NULL, *html_fp = NULL;
     5         kx 
     5         kx   allocate_fnames( json_fname );
     5         kx 
     5         kx   pkgs_fp = fopen( (const char *)pkgs_fname, "w" );
     5         kx   if( !pkgs_fp ) { FATAL_ERROR( "Cannot create %s file", basename( pkgs_fname ) ); }
     5         kx   tree_fp = fopen( (const char *)tree_fname, "w" );
     5         kx   if( !tree_fp ) { FATAL_ERROR( "Cannot create %s file", basename( tree_fname ) ); }
     5         kx   html_fp = fopen( (const char *)html_fname, "w" );
     5         kx   if( !html_fp ) { FATAL_ERROR( "Cannot create %s file", basename( html_fname ) ); }
     5         kx 
     5         kx   tree = dlist_copy( provides );
     5         kx 
     5         kx   /*****************************************************
     5         kx     print out the array of all packages in JSON format:
     5         kx    */
     5         kx   print_pkgs_json( pkgs_fp, provides );
     5         kx   fflush( pkgs_fp ); fclose( pkgs_fp );
     5         kx 
     5         kx   provides = dlist_reverse( provides );
     5         kx   sort_requires( provides ); /* sort requires in reverse installation order */
     5         kx 
     5         kx   /********************************************************
     5         kx     Sort the REQUIRES TREE in reverse installation order.
     5         kx    */
     5         kx   tree = sort_requires_tree( tree );
     5         kx 
     5         kx   /********************************************************
     5         kx     remove unneded packages from tree list to leave the
     5         kx     last installation layer of packages presented in DAG:
     5         kx    */
     5         kx   remove_required_packages( provides );
     5         kx 
     5         kx 
     5         kx   if( tree_format == TFMT_BIN )
     5         kx   {
     5         kx     int width = 0, height = 0;
     5         kx 
     5         kx     /********************************************************************
     5         kx       print out the REQUIRES TREE in JSON format as reduced binary tree:
     5         kx      */
     5         kx     create_pkgs_list( provides );
     5         kx     create_btree( tree, provides );
     5         kx 
     5         kx     width  =  btree_width( btree );
     5         kx     height = btree_height( btree );
     5         kx 
     5         kx     svg_width  = (height + 4) * 240;
     5         kx     svg_height =  (width + 4) * __width_factor( width );
     5         kx 
     5         kx     fprintf( tree_fp, "{\n" );
     5         kx     __print_btree_header( tree_fp, btree, tree );
     5         kx     btree_print_json( tree_fp, btree, __print_btree_node );
     5         kx     fprintf( tree_fp, "}\n" );
     5         kx 
     5         kx     __btree_free( btree );
     5         kx     free_pkgs_list();
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     /****************************************************
     5         kx       print out the REQUIRES TREE in JSON format as DAG:
     5         kx      */
     5         kx     print_tree_json( tree_fp, tree );
     5         kx   }
     5         kx 
     5         kx   fflush( tree_fp ); fclose( tree_fp );
     5         kx 
     5         kx   if( minimize )
     5         kx   {
     5         kx     if( minimize_json( (const char *)pkgs_fname, (const char *)pkgs_min_fname ) < 1 )
     5         kx     {
     5         kx       (void)unlink( (const char *)pkgs_min_fname );
     5         kx     }
     5         kx     if( minimize_json( (const char *)tree_fname, (const char *)tree_min_fname ) < 1 )
     5         kx     {
     5         kx       (void)unlink( (const char *)tree_min_fname );
     5         kx     }
     5         kx   }
     5         kx 
     5         kx 
     5         kx   /***********************************************
     5         kx     print out the HTML to view REQIIRES TREE:
     5         kx    */
     5         kx   print_tree_html( html_fp );
     5         kx   fflush( html_fp ); fclose( html_fp );
     5         kx 
     5         kx 
     5         kx   /*****************
     5         kx     free resources:
     5         kx    */
     5         kx   if( root )    { free( root );       root = NULL; }
     5         kx   if( bug_url ) { free( bug_url ); bug_url = NULL; }
     5         kx 
     5         kx   if( pkgs_fname ) { free( pkgs_fname ); pkgs_fname = NULL; }
     5         kx   if( tree_fname ) { free( tree_fname ); tree_fname = NULL; }
     5         kx   if( html_fname ) { free( html_fname ); html_fname = NULL; }
     5         kx 
     5         kx   if( pkgs_min_fname ) { free( pkgs_min_fname ); pkgs_min_fname = NULL; }
     5         kx   if( tree_min_fname ) { free( tree_min_fname ); tree_min_fname = NULL; }
     5         kx 
     5         kx   if( json_pkgs_file ) { free( json_pkgs_file ); json_pkgs_file = NULL; }
     5         kx   if( json_tree_file ) { free( json_tree_file ); json_tree_file = NULL; }
     5         kx 
     5         kx   __dlist_free( tree ); /* do not free node data */
     5         kx }
     5         kx /*
     5         kx   End of Requires TREE functions.
     5         kx  ***************************************************************/