@ -30,12 +30,17 @@
# include <unistd.h>
# include <stdarg.h>
# include <getopt.h>
# include <ctype.h>
# include <libxml/parser.h>
# include <libxml/tree.h>
# include "autoconfig.h"
# include "mxml/mxml.h"
# include "linkedlists.h"
# include "menuselect.h"
# define ARRAY_LEN(a) (size_t) (sizeof(a) / sizeof(0[a]))
# ifdef MENUSELECT_DEBUG
static FILE * debug ;
# endif
@ -52,7 +57,7 @@ struct categories categories = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
*/
struct tree {
/*! the root of the tree */
mxml_node_t * root ;
xmlDoc * root ;
/*! for linking */
AST_LIST_ENTRY ( tree ) list ;
} ;
@ -157,83 +162,68 @@ static void close_debug(void)
# endif
}
/*! \brief Add a category to the category list, ensuring that there are no duplicates */
static struct category * add_category( struct category * cat )
/*! \brief Finds a category with the given name or creates it if not found */
static struct category * category_find_or_create( const char * name )
{
struct category * tmp ;
struct category * c ;
AST_LIST_TRAVERSE ( & categories , tmp , list ) {
if ( ! strcmp ( tmp - > name , cat - > name ) ) {
return tmp ;
AST_LIST_TRAVERSE ( & categories , c , list ) {
if ( ! strcmp ( c - > name , name ) ) {
xmlFree ( ( void * ) name ) ;
return c ;
}
}
AST_LIST_INSERT_TAIL ( & categories , cat , list ) ;
return cat ;
}
if ( ! ( c = calloc ( 1 , sizeof ( * c ) ) ) ) {
return NULL ;
}
#if 0
/*! \brief Add a member to the member list of a category, ensuring that there are no duplicates */
static int add_member ( struct member * mem , struct category * cat )
{
struct member * tmp ;
c - > name = name ;
AST_LIST_TRAVERSE ( & cat - > members , tmp , list ) {
if ( ! strcmp ( tmp - > name , mem - > name ) ) {
fprintf ( stderr , " Member '%s' already exists in category '%s', ignoring. \n " , mem - > name , cat - > name ) ;
return - 1 ;
}
}
AST_LIST_INSERT_TAIL ( & cat - > members , mem , list ) ;
AST_LIST_INSERT_TAIL ( & categories , c , list ) ;
return 0 ;
return c ;
}
# endif
static int add_member_after ( struct member * mem , struct category * cat , struct member * place )
static void free_reference ( struct reference * ref )
{
struct member * tmp ;
AST_LIST_TRAVERSE ( & cat - > members , tmp , list ) {
if ( ! strcmp ( tmp - > name , mem - > name ) ) {
fprintf ( stderr , " Member '%s' already exists in category '%s', ignoring. \n " , mem - > name , cat - > name ) ;
return - 1 ;
}
/* If name and displayname point to the same place, only free one of them */
if ( ref - > name = = ref - > displayname ) {
xmlFree ( ( void * ) ref - > name ) ;
} else {
xmlFree ( ( void * ) ref - > name ) ;
xmlFree ( ( void * ) ref - > displayname ) ;
}
AST_LIST_INSERT_AFTER ( & cat - > members , place , mem , list ) ;
return 0 ;
free ( ref ) ;
}
static int add_member_head ( struct member * mem , struct category * cat )
/*! \brief Free a member structure and all of its members */
static void free_member ( struct member * mem )
{
struct member * tmp ;
struct reference * ref ;
AST_LIST_TRAVERSE ( & cat - > members , tmp , list ) {
if ( ! strcmp ( tmp - > name , mem - > name ) ) {
fprintf ( stderr , " Member '%s' already exists in category '%s', ignoring. \n " , mem - > name , cat - > name ) ;
return - 1 ;
}
if ( ! mem ) {
return ;
}
AST_LIST_INSERT_HEAD ( & cat - > members , mem , list ) ;
return 0 ;
}
while ( ( ref = AST_LIST_REMOVE_HEAD ( & mem - > deps , list ) ) )
free_reference ( ref ) ;
while ( ( ref = AST_LIST_REMOVE_HEAD ( & mem - > conflicts , list ) ) )
free_reference ( ref ) ;
while ( ( ref = AST_LIST_REMOVE_HEAD ( & mem - > uses , list ) ) )
free_reference ( ref ) ;
/*! \brief Free a member structure and all of its members */
static void free_member ( struct member * mem )
{
struct reference * dep ;
struct reference * cnf ;
struct reference * use ;
if ( ! mem - > is_separator ) {
xmlFree ( ( void * ) mem - > name ) ;
xmlFree ( ( void * ) mem - > displayname ) ;
xmlFree ( ( void * ) mem - > touch_on_change ) ;
xmlFree ( ( void * ) mem - > remove_on_change ) ;
xmlFree ( ( void * ) mem - > defaultenabled ) ;
xmlFree ( ( void * ) mem - > support_level ) ;
xmlFree ( ( void * ) mem - > replacement ) ;
}
while ( ( dep = AST_LIST_REMOVE_HEAD ( & mem - > deps , list ) ) )
free ( dep ) ;
while ( ( cnf = AST_LIST_REMOVE_HEAD ( & mem - > conflicts , list ) ) )
free ( cnf ) ;
while ( ( use = AST_LIST_REMOVE_HEAD ( & mem - > uses , list ) ) )
free ( use ) ;
free ( mem ) ;
}
@ -264,294 +254,358 @@ static const char *support_level_to_string(enum support_level_values support_lev
{
switch ( support_level ) {
case SUPPORT_CORE :
return " c ore" ;
return " C ore" ;
case SUPPORT_EXTENDED :
return " e xtended" ;
return " E xtended" ;
case SUPPORT_DEPRECATED :
return " d eprecated" ;
return " D eprecated" ;
default :
return " unspecified " ;
return " Unspecified " ;
}
}
static void categories_flatten ( )
{
int idx ;
struct category * c ;
struct member * m ;
AST_LIST_TRAVERSE ( & categories , c , list ) {
for ( idx = 0 ; idx < SUPPORT_COUNT ; idx + + ) {
struct support_level_bucket bucket = c - > buckets [ idx ] ;
while ( ( m = AST_LIST_REMOVE_HEAD ( & bucket , list ) ) ) {
AST_LIST_INSERT_TAIL ( & c - > members , m , list ) ;
}
}
}
}
/*! \sets default values for a given separator */
static int initialize_separator ( struct member * separators [ ] , enum support_level_values level )
static struct member * create_separator ( enum support_level_values level )
{
separators [ level ] = calloc ( 1 , sizeof ( * ( separators [ level ] ) ) ) ;
separators [ level ] - > name = support_level_to_string ( level ) ;
separators [ level ] - > displayname = " " ;
separators [ level ] - > is_separator = 1 ;
struct member * separator = calloc ( 1 , sizeof ( * separator ) ) ;
separator - > name = support_level_to_string ( level ) ;
separator - > displayname = " " ;
separator - > is_separator = 1 ;
return separator ;
}
/*! \adds a member to a category and attaches it to the last element of a particular support level used */
static int add_member_list_order ( struct member * mem , struct category * cat )
{
enum support_level_values support_level = string_to_support_level ( mem - > support_level ) ;
struct support_level_bucket * bucket = & cat - > buckets [ support_level ] ;
if ( AST_LIST_EMPTY ( bucket ) ) {
struct member * sep = create_separator ( support_level ) ;
AST_LIST_INSERT_TAIL ( bucket , sep , list ) ;
}
AST_LIST_INSERT_TAIL ( bucket , mem , list ) ;
return 0 ;
}
/*! \Iterates through an existing category's members. If separators are found, they are
added to the provided separator array . Any separators left unfound will then be
initialized with initialize_separator . */
static void find_or_initialize_separators ( struct member * separators [ ] , struct category * cat , int used [ ] )
static int process_xml_defaultenabled_node ( xmlNode * node , struct member * mem )
{
enum support_level_values level ;
struct member * tmp ;
AST_LIST_TRAVERSE ( & cat - > members , tmp , list ) {
if ( tmp - > is_separator ) {
level = string_to_support_level ( tmp - > name ) ;
separators [ level ] = tmp ;
used [ level ] = 1 ;
}
const char * tmp = ( const char * ) xmlNodeGetContent ( node ) ;
if ( tmp & & ! strlen_zero ( tmp ) ) {
mem - > defaultenabled = tmp ;
}
for ( level = 0 ; level < SUPPORT_COUNT ; level + + ) {
if ( ! used [ level ] ) {
initialize_separator ( separators , level ) ;
}
return 0 ;
}
static int process_xml_supportlevel_node ( xmlNode * node , struct member * mem )
{
const char * tmp = ( const char * ) xmlNodeGetContent ( node ) ;
if ( tmp & & ! strlen_zero ( tmp ) ) {
xmlFree ( ( void * ) mem - > support_level ) ;
mem - > support_level = tmp ;
print_debug ( " Set support_level for %s to %s \n " , mem - > name , mem - > support_level ) ;
}
return 0 ;
}
/*! \adds a member to a category and attaches it to the last element of a particular support level used */
static int add_member_list_order ( struct member * mem , struct category * cat , struct member * tails [ ] , int used [ ] , struct member * separators [ ] )
static int process_xml_replacement_node ( xmlNode * node , struct member * mem )
{
enum support_level_values support_level = string_to_support_level ( mem - > support_level ) ;
int tail_index ;
const char * tmp = ( const char * ) xmlNodeGetContent ( node ) ;
/* Works backwards from support_level to find properly ordered linked list member to insert from */
for ( tail_index = support_level ; ; tail_index - - ) {
if ( tail_index = = - 1 ) {
break ;
}
if ( used [ tail_index ] ) {
break ;
}
if ( tmp & & ! strlen_zero ( tmp ) ) {
mem - > replacement = tmp ;
}
if ( tail_index = = - 1 ) { /* None of the nodes that should come before the list were in use, so use head. */
if ( add_member_head ( mem , cat ) ) { /* Failure to insert the node... */
return - 1 ;
}
return 0 ;
}
/* If we successfully added the member, we need to update its support level pointer info */
tails [ support_level ] = mem ;
used [ support_level ] = 1 ;
if ( add_member_head ( separators [ support_level ] , cat ) ) {
printf ( " Separator insertion failed. This should be impossible, report an issue if this occurs. \n " ) ;
return - 1 ;
}
return 0 ;
static int process_xml_ref_node ( xmlNode * node , struct member * mem , struct reference_list * refs )
{
struct reference * ref ;
const char * tmp ;
} else { /* We found an appropriate node to use to insert before we reached the head. */
if ( add_member_after ( mem , cat , tails [ tail_index ] ) ) {
return - 1 ;
if ( ! ( ref = calloc ( 1 , sizeof ( * ref ) ) ) ) {
free_member ( mem ) ;
return - 1 ;
}
if ( ( tmp = ( const char * ) xmlGetProp ( node , BAD_CAST " name " ) ) ) {
if ( ! strlen_zero ( tmp ) ) {
ref - > name = tmp ;
}
}
tails [ support_level ] = mem ;
used [ support_level ] = 1 ;
if ( support_level ! = tail_index ) {
if ( add_member_after ( separators [ support_level ] , cat , tails [ tail_index ] ) ) {
printf ( " Separator insertion failed. This should be impossible, report an issue if this occurs. \n " ) ;
return - 1 ;
}
tmp = ( const char * ) xmlNodeGetContent ( node ) ;
if ( tmp & & ! strlen_zero ( tmp ) ) {
ref - > displayname = tmp ;
if ( ! ref - > name ) {
ref - > name = ref - > displayname ;
}
return 0 ;
AST_LIST_INSERT_TAIL ( refs , ref , list ) ;
} else {
free_reference ( ref ) ;
}
return 0 ;
}
static int process_xml_depend_node ( xmlNode * node , struct member * mem )
{
return process_xml_ref_node ( node , mem , & mem - > deps ) ;
}
static int process_xml_conflict_node ( xmlNode * node , struct member * mem )
{
return process_xml_ref_node ( node , mem , & mem - > conflicts ) ;
}
static int process_xml_use_node ( xmlNode * node , struct member * mem )
{
return process_xml_ref_node ( node , mem , & mem - > uses ) ;
}
static int process_xml_unknown_node ( xmlNode * node , struct member * mem )
{
fprintf ( stderr , " Encountered unknown node: %s \n " , node - > name ) ;
return 0 ;
}
typedef int ( * node_handler ) ( xmlNode * , struct member * ) ;
static const struct {
const char * name ;
node_handler func ;
} node_handlers [ ] = {
{ " defaultenabled " , process_xml_defaultenabled_node } ,
{ " support_level " , process_xml_supportlevel_node } ,
{ " replacement " , process_xml_replacement_node } ,
{ " depend " , process_xml_depend_node } ,
{ " conflict " , process_xml_conflict_node } ,
{ " use " , process_xml_use_node } ,
} ;
static node_handler lookup_node_handler ( xmlNode * node )
{
int i ;
for ( i = 0 ; i < ARRAY_LEN ( node_handlers ) ; i + + ) {
if ( ! strcmp ( node_handlers [ i ] . name , ( const char * ) node - > name ) ) {
return node_handlers [ i ] . func ;
}
}
return - 2 ; /* failed to place... for whatever reason. This should be impossible to reach. */
return process_xml_unknown_node ;
}
/*! \brief Parse an input makeopts file */
static int parse_tree ( const char * tree_file )
static int process_process_xml_category_child_node ( xmlNode * node , struct member * mem )
{
FILE * f ;
struct tree * tree ;
node_handler handler = lookup_node_handler ( node ) ;
return handler ( node , mem ) ;
}
static int process_xml_member_node ( xmlNode * node , struct category * cat )
{
xmlNode * cur ;
struct member * mem ;
struct reference * dep ;
struct reference * cnf ;
struct reference * use ;
mxml_node_t * cur ;
mxml_node_t * cur2 ;
mxml_node_t * cur3 ;
mxml_node_t * menu ;
const char * tmp ;
xmlChar * tmp ;
if ( ! ( f = fopen ( tree_file , " r " ) ) ) {
fprintf ( stderr , " Unable to open '%s' for reading! \n " , tree_file ) ;
if ( ! ( mem = calloc ( 1 , sizeof ( * mem ) ) ) ) {
return - 1 ;
}
if ( ! ( tree = calloc ( 1 , sizeof ( * tree ) ) ) ) {
fclose ( f ) ;
return - 1 ;
mem - > name = ( const char * ) xmlGetProp ( node , BAD_CAST " name " ) ;
mem - > displayname = ( const char * ) xmlGetProp ( node , BAD_CAST " displayname " ) ;
mem - > touch_on_change = ( const char * ) xmlGetProp ( node , BAD_CAST " touch_on_change " ) ;
mem - > remove_on_change = ( const char * ) xmlGetProp ( node , BAD_CAST " remove_on_change " ) ;
mem - > support_level = ( const char * ) xmlCharStrdup ( " unspecified " ) ;
if ( ( tmp = xmlGetProp ( node , BAD_CAST " explicitly_enabled_only " ) ) ) {
mem - > explicitly_enabled_only = ! xmlStrcasecmp ( tmp , BAD_CAST " yes " ) ;
xmlFree ( tmp ) ;
}
if ( ! ( tree - > root = mxmlLoadFile ( NULL , f , MXML_OPAQUE_CALLBACK ) ) ) {
fclose ( f ) ;
free ( tree ) ;
return - 1 ;
for ( cur = node - > children ; cur ; cur = cur - > next ) {
if ( cur - > type ! = XML_ELEMENT_NODE ) {
continue ;
}
process_process_xml_category_child_node ( cur , mem ) ;
}
AST_LIST_INSERT_HEAD ( & trees , tree , list ) ;
if ( ! cat - > positive_output ) {
mem - > enabled = 1 ;
if ( ! ( mem - > defaultenabled & & strcasecmp ( mem - > defaultenabled , " no " ) ) ) {
mem - > was_enabled = 1 ;
print_debug ( " Enabled %s because the category does not have positive output \n " , mem - > name ) ;
}
}
menu = mxmlFindElement ( tree - > root , tree - > root , " menu " , NULL , NULL , MXML_DESCEND ) ;
if ( ( tmp = mxmlElementGetAttr ( menu , " name " ) ) )
menu_name = tmp ;
for ( cur = mxmlFindElement ( menu , menu , " category " , NULL , NULL , MXML_DESCEND_FIRST ) ;
cur ;
cur = mxmlFindElement ( cur , menu , " category " , NULL , NULL , MXML_NO_DESCEND ) )
{
struct category * cat ;
struct category * newcat ;
if ( add_member_list_order ( mem , cat ) ) {
free_member ( mem ) ;
}
/* Member seperator definitions */
struct member * separators [ SUPPORT_COUNT ] ;
return 0 ;
}
/* link list tails... used to put new elements in in order of support level */
struct member * support_tails [ SUPPORT_COUNT ] ;
int support_tails_placed [ SUPPORT_COUNT ] = { 0 } ;
static void free_category ( struct category * cat )
{
struct member * mem ;
if ( ! ( cat = calloc ( 1 , sizeof ( * cat ) ) ) )
return - 1 ;
xmlFree ( ( void * ) cat - > name ) ;
xmlFree ( ( void * ) cat - > displayname ) ;
xmlFree ( ( void * ) cat - > remove_on_change ) ;
xmlFree ( ( void * ) cat - > touch_on_change ) ;
while ( ( mem = AST_LIST_REMOVE_HEAD ( & cat - > members , list ) ) ) {
free_member ( mem ) ;
}
free ( cat ) ;
}
cat - > name = mxmlElementGetAttr ( cur , " name " ) ;
static int process_xml_category_node ( xmlNode * node )
{
struct category * cat ;
const char * tmp ;
xmlNode * cur ;
newcat = add_category ( cat ) ;
if ( ! ( tmp = ( const char * ) xmlGetProp ( node , BAD_CAST " name " ) ) ) {
fprintf ( stderr , " Missing 'name' attribute for 'category' element. Skipping... \n " ) ;
/* Return success here so we don't bail on the whole document */
return 0 ;
}
cat = category_find_or_create ( tmp ) ;
if ( newcat ! = cat ) {
/* want to append members, and potentially update the category. */
free ( cat ) ;
cat = newcat ;
if ( ( tmp = ( const char * ) xmlGetProp ( node , BAD_CAST " displayname " ) ) ) {
xmlFree ( ( void * ) cat - > displayname ) ;
cat - > displayname = tmp ;
}
if ( ( tmp = ( const char * ) xmlGetProp ( node , BAD_CAST " remove_on_change " ) ) ) {
xmlFree ( ( void * ) cat - > remove_on_change ) ;
cat - > remove_on_change = tmp ;
}
if ( ( tmp = ( const char * ) xmlGetProp ( node , BAD_CAST " touch_on_change " ) ) ) {
xmlFree ( ( void * ) cat - > touch_on_change ) ;
cat - > touch_on_change = tmp ;
}
if ( ( tmp = ( const char * ) xmlGetProp ( node , BAD_CAST " positive_output " ) ) ) {
cat - > positive_output = ! strcasecmp ( tmp , " yes " ) ;
xmlFree ( ( void * ) tmp ) ;
}
if ( ( tmp = ( const char * ) xmlGetProp ( node , BAD_CAST " exclusive " ) ) ) {
cat - > exclusive = ! strcasecmp ( tmp , " yes " ) ;
xmlFree ( ( void * ) tmp ) ;
}
for ( cur = node - > children ; cur ; cur = cur - > next ) {
if ( cur - > type ! = XML_ELEMENT_NODE ) {
continue ;
}
find_or_initialize_separators ( separators , cat , support_tails_placed ) ;
if ( ( tmp = mxmlElementGetAttr ( cur , " displayname " ) ) )
cat - > displayname = tmp ;
if ( ( tmp = mxmlElementGetAttr ( cur , " positive_output " ) ) )
cat - > positive_output = ! strcasecmp ( tmp , " yes " ) ;
if ( ( tmp = mxmlElementGetAttr ( cur , " exclusive " ) ) )
cat - > exclusive = ! strcasecmp ( tmp , " yes " ) ;
if ( ( tmp = mxmlElementGetAttr ( cur , " remove_on_change " ) ) )
cat - > remove_on_change = tmp ;
if ( ( tmp = mxmlElementGetAttr ( cur , " touch_on_change " ) ) )
cat - > touch_on_change = tmp ;
for ( cur2 = mxmlFindElement ( cur , cur , " member " , NULL , NULL , MXML_DESCEND_FIRST ) ;
cur2 ;
cur2 = mxmlFindElement ( cur2 , cur , " member " , NULL , NULL , MXML_NO_DESCEND ) )
{
if ( ! ( mem = calloc ( 1 , sizeof ( * mem ) ) ) )
return - 1 ;
mem - > name = mxmlElementGetAttr ( cur2 , " name " ) ;
mem - > displayname = mxmlElementGetAttr ( cur2 , " displayname " ) ;
mem - > touch_on_change = mxmlElementGetAttr ( cur2 , " touch_on_change " ) ;
mem - > remove_on_change = mxmlElementGetAttr ( cur2 , " remove_on_change " ) ;
mem - > support_level = " unspecified " ;
if ( ( tmp = mxmlElementGetAttr ( cur2 , " explicitly_enabled_only " ) ) ) {
mem - > explicitly_enabled_only = ! strcasecmp ( tmp , " yes " ) ;
}
if ( xmlStrcmp ( cur - > name , BAD_CAST " member " ) ) {
fprintf ( stderr , " Ignoring unknown element: %s \n " , cur - > name ) ;
continue ;
}
cur3 = mxmlFindElement ( cur2 , cur2 , " defaultenabled " , NULL , NULL , MXML_DESCEND ) ;
if ( cur3 & & cur3 - > child ) {
mem - > defaultenabled = cur3 - > child - > value . opaque ;
}
process_xml_member_node ( cur , cat ) ;
}
if ( ! cat - > positive_output ) {
mem - > enabled = 1 ;
if ( ! ( mem - > defaultenabled & & strcasecmp ( mem - > defaultenabled , " no " ) ) ) {
mem - > was_enabled = 1 ;
print_debug ( " Enabled %s because the category does not have positive output \n " , mem - > name ) ;
}
}
return 0 ;
}
cur3 = mxmlFindElement ( cur2 , cur2 , " support_level " , NULL , NULL , MXML_DESCEND ) ;
if ( cur3 & & cur3 - > child ) {
mem - > support_level = cur3 - > child - > value . opaque ;
print_debug ( " Set support_level for %s to %s \n " , mem - > name , mem - > support_level ) ;
}
static int process_xml_menu_node ( struct tree * tree , xmlNode * node )
{
xmlNode * cur ;
xmlChar * tmp ;
cur3 = mxmlFindElement ( cur2 , cur2 , " replacement " , NULL , NULL , MXML_DESCEND ) ;
if ( cur3 & & cur3 - > child ) {
mem - > replacement = cur3 - > child - > value . opaque ;
}
if ( strcmp ( ( const char * ) node - > name , " menu " ) ) {
fprintf ( stderr , " Invalid document: Expected \" menu \" element. \n " ) ;
return - 1 ;
}
for ( cur3 = mxmlFindElement ( cur2 , cur2 , " depend " , NULL , NULL , MXML_DESCEND_FIRST ) ;
cur3 & & cur3 - > child ;
cur3 = mxmlFindElement ( cur3 , cur2 , " depend " , NULL , NULL , MXML_NO_DESCEND ) )
{
if ( ! ( dep = calloc ( 1 , sizeof ( * dep ) ) ) ) {
free_member ( mem ) ;
return - 1 ;
}
if ( ( tmp = mxmlElementGetAttr ( cur3 , " name " ) ) ) {
if ( ! strlen_zero ( tmp ) ) {
dep - > name = tmp ;
}
}
if ( ! strlen_zero ( cur3 - > child - > value . opaque ) ) {
dep - > displayname = cur3 - > child - > value . opaque ;
if ( ! dep - > name ) {
dep - > name = dep - > displayname ;
}
AST_LIST_INSERT_TAIL ( & mem - > deps , dep , list ) ;
} else
free ( dep ) ;
}
AST_LIST_INSERT_HEAD ( & trees , tree , list ) ;
for ( cur3 = mxmlFindElement ( cur2 , cur2 , " conflict " , NULL , NULL , MXML_DESCEND_FIRST ) ;
cur3 & & cur3 - > child ;
cur3 = mxmlFindElement ( cur3 , cur2 , " conflict " , NULL , NULL , MXML_NO_DESCEND ) )
{
if ( ! ( cnf = calloc ( 1 , sizeof ( * cnf ) ) ) ) {
free_member ( mem ) ;
return - 1 ;
}
if ( ( tmp = mxmlElementGetAttr ( cur3 , " name " ) ) ) {
if ( ! strlen_zero ( tmp ) ) {
cnf - > name = tmp ;
}
}
if ( ! strlen_zero ( cur3 - > child - > value . opaque ) ) {
cnf - > displayname = cur3 - > child - > value . opaque ;
if ( ! cnf - > name ) {
cnf - > name = cnf - > displayname ;
}
AST_LIST_INSERT_TAIL ( & mem - > conflicts , cnf , list ) ;
} else
free ( cnf ) ;
}
if ( ( tmp = xmlGetProp ( node , BAD_CAST " name " ) ) ) {
menu_name = ( const char * ) tmp ;
}
for ( cur3 = mxmlFindElement ( cur2 , cur2 , " use " , NULL , NULL , MXML_DESCEND_FIRST ) ;
cur3 & & cur3 - > child ;
cur3 = mxmlFindElement ( cur3 , cur2 , " use " , NULL , NULL , MXML_NO_DESCEND ) )
{
if ( ! ( use = calloc ( 1 , sizeof ( * use ) ) ) ) {
free_member ( mem ) ;
return - 1 ;
}
if ( ( tmp = mxmlElementGetAttr ( cur3 , " name " ) ) ) {
if ( ! strlen_zero ( tmp ) ) {
use - > name = tmp ;
}
}
if ( ! strlen_zero ( cur3 - > child - > value . opaque ) ) {
use - > displayname = cur3 - > child - > value . opaque ;
if ( ! use - > name ) {
use - > name = use - > displayname ;
}
for ( cur = node - > children ; cur ; cur = cur - > next ) {
if ( cur - > type ! = XML_ELEMENT_NODE ) {
continue ;
}
AST_LIST_INSERT_TAIL ( & mem - > uses , use , list ) ;
} else {
free ( use ) ;
}
}
if ( xmlStrcmp ( cur - > name , BAD_CAST " category " ) ) {
fprintf ( stderr , " Ignoring unknown element: %s \n " , cur - > name ) ;
continue ;
}
if ( add_member_list_order ( mem , cat , support_tails , support_tails_placed , separators ) ) {
free_member ( mem ) ;
}
if ( process_xml_category_node ( cur ) ) {
return - 1 ;
}
}
fclose ( f ) ;
categories_flatten ( ) ;
return 0 ;
}
/*! \brief Parse an input makeopts file */
static int parse_tree ( const char * tree_file )
{
struct tree * tree ;
xmlNode * menu ;
if ( ! ( tree = calloc ( 1 , sizeof ( * tree ) ) ) ) {
return - 1 ;
}
if ( ! ( tree - > root = xmlParseFile ( tree_file ) ) ) {
free ( tree ) ;
return - 1 ;
}
if ( ! ( menu = xmlDocGetRootElement ( tree - > root ) ) ) {
fprintf ( stderr , " Invalid document: No root element \n " ) ;
xmlFreeDoc ( tree - > root ) ;
free ( tree ) ;
return - 1 ;
}
if ( process_xml_menu_node ( tree , menu ) ) {
xmlFreeDoc ( tree - > root ) ;
free ( tree ) ;
return - 1 ;
}
return 0 ;
}
@ -1605,22 +1659,9 @@ static void dump_member_list(void)
static void free_member_list ( void )
{
struct category * cat ;
struct member * mem ;
struct reference * dep ;
struct reference * cnf ;
struct reference * use ;
while ( ( cat = AST_LIST_REMOVE_HEAD ( & categories , list ) ) ) {
while ( ( mem = AST_LIST_REMOVE_HEAD ( & cat - > members , list ) ) ) {
while ( ( dep = AST_LIST_REMOVE_HEAD ( & mem - > deps , list ) ) )
free ( dep ) ;
while ( ( cnf = AST_LIST_REMOVE_HEAD ( & mem - > conflicts , list ) ) )
free ( cnf ) ;
while ( ( use = AST_LIST_REMOVE_HEAD ( & mem - > uses , list ) ) )
free ( use ) ;
free ( mem ) ;
}
free ( cat ) ;
free_category ( cat ) ;
}
}
@ -1630,7 +1671,7 @@ static void free_trees(void)
struct tree * tree ;
while ( ( tree = AST_LIST_REMOVE_HEAD ( & trees , list ) ) ) {
mxmlDelete ( tree - > root ) ;
xmlFreeDoc ( tree - > root ) ;
free ( tree ) ;
}
}
@ -1923,6 +1964,8 @@ int main(int argc, char *argv[])
exit ( 1 ) ;
}
LIBXML_TEST_VERSION ;
/* Parse the input XML files to build the list of available options */
if ( ( res = build_member_list ( ) ) )
exit ( res ) ;
@ -2100,5 +2143,7 @@ int main(int argc, char *argv[])
close_debug ( ) ;
xmlCleanupParser ( ) ;
exit ( res ) ;
}