[asterisk-commits] mjordan: trunk r418834 - in /trunk: ./ include/asterisk/ menuselect/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Jul 17 14:02:27 CDT 2014


Author: mjordan
Date: Thu Jul 17 14:02:22 2014
New Revision: 418834

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=418834
Log:
menuselect: Add libxml2 support (Patch 3)

This is the final patch in adding menuselect to Asterisk.
 - The first patch (r418832) added menuselect along with mxml
 - The second patch (r418833) removed mxml from menuselect

This patch adds support for libxml2 to menuselect, and makes libxml2 a
required library for Asterisk.

Note that the libxml2 portion of this patch was written by Sean Bright,
and was made available on a team branch:
  http://svn.digium.com/svn/menuselect/team/seanbright/libxml2/

Review: https://reviewboard.asterisk.org/r/3773/

ASTERISK-20703 #close
patches:
  some_mysterious_team_branch uploaded by seanbright (License 5060)


Modified:
    trunk/UPGRADE.txt
    trunk/configure
    trunk/configure.ac
    trunk/include/asterisk/autoconfig.h.in
    trunk/menuselect/Makefile
    trunk/menuselect/README
    trunk/menuselect/acinclude.m4
    trunk/menuselect/aclocal.m4
    trunk/menuselect/autoconfig.h.in
    trunk/menuselect/configure
    trunk/menuselect/configure.ac
    trunk/menuselect/example_menuselect-tree
    trunk/menuselect/makeopts.in
    trunk/menuselect/menuselect.c
    trunk/menuselect/menuselect.h

Modified: trunk/UPGRADE.txt
URL: http://svnview.digium.com/svn/asterisk/trunk/UPGRADE.txt?view=diff&rev=418834&r1=418833&r2=418834
==============================================================================
--- trunk/UPGRADE.txt (original)
+++ trunk/UPGRADE.txt Thu Jul 17 14:02:22 2014
@@ -23,6 +23,9 @@
 
 From 12 to 13:
 
+ - The menuselect utility has been pulled into the Asterisk repository. As a
+   result, the libxml2 library is now a required dependency for Asterisk.
+
  - The asterisk command line -I option and the asterisk.conf internal_timing
    option are removed and always enabled if any timing module is loaded.
 

Modified: trunk/configure.ac
URL: http://svnview.digium.com/svn/asterisk/trunk/configure.ac?view=diff&rev=418834&r1=418833&r2=418834
==============================================================================
--- trunk/configure.ac (original)
+++ trunk/configure.ac Thu Jul 17 14:02:22 2014
@@ -550,6 +550,12 @@
   AC_MSG_ERROR([*** JSON support not found (this typically means the libjansson development package is missing)])
 fi
 
+if test "x$PBX_LIBXML2" == "x"; then
+	AC_MSG_NOTICE(*** The Asterisk menuselect tool requires the 'libxml2' package.)
+	AC_MSG_NOTICE(*** Please install the 'libxml2' package.)
+	exit 1
+fi
+
 AST_EXT_LIB_CHECK([URIPARSER], [uriparser], [uriParseUriA], [uriparser/Uri.h])
 
 # Another mandatory item (unless it's explicitly disabled)
@@ -567,13 +573,6 @@
 	[#include <libxml/tree.h>
 	#include <libxml/parser.h>],
 	[LIBXML_TEST_VERSION])
-	if test "${PBX_LIBXML2}" != 1; then
-		AC_MSG_NOTICE(*** XML documentation will not be available because the 'libxml2' development package is missing.)
-		AC_MSG_NOTICE(*** Please run the 'configure' script with the '--disable-xmldoc' parameter option)
-		AC_MSG_NOTICE(*** or install the 'libxml2' development package.)
-		exit 1
-	fi
-
         AST_EXT_LIB_CHECK([LIBXSLT], [xslt], [xsltLoadStylesheetPI], [libxslt/xsltInternals.h], [${LIBXML2_LIB}], [${LIBXML2_INCLUDE}])
         AST_EXT_LIB_CHECK([LIBXSLT_CLEANUP], [xslt], [xsltCleanupGlobals], [libxslt/xsltInternals.h], [${LIBXML2_LIB}], [${LIBXML2_INCLUDE}])
 

Modified: trunk/include/asterisk/autoconfig.h.in
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/autoconfig.h.in?view=diff&rev=418834&r1=418833&r2=418834
==============================================================================
--- trunk/include/asterisk/autoconfig.h.in (original)
+++ trunk/include/asterisk/autoconfig.h.in Thu Jul 17 14:02:22 2014
@@ -1289,11 +1289,6 @@
 /* Define to 1 if running on Darwin. */
 #undef _DARWIN_UNLIMITED_SELECT
 
-/* Enable large inode numbers on Mac OS X 10.5.  */
-#ifndef _DARWIN_USE_64_BIT_INODE
-# define _DARWIN_USE_64_BIT_INODE 1
-#endif
-
 /* Number of bits in a file offset, on hosts where this is settable. */
 #undef _FILE_OFFSET_BITS
 

Modified: trunk/menuselect/Makefile
URL: http://svnview.digium.com/svn/asterisk/trunk/menuselect/Makefile?view=diff&rev=418834&r1=418833&r2=418834
==============================================================================
--- trunk/menuselect/Makefile (original)
+++ trunk/menuselect/Makefile Thu Jul 17 14:02:22 2014
@@ -57,6 +57,7 @@
 endif
 
 M_OBJS += menuselect_stub.o
+M_LIBS += $(LIBXML2_LIB)
 ALL_TGTS += menuselect
 
 all: $(ALL_TGTS)
@@ -65,13 +66,16 @@
 
 makeopts autoconfig.h: autoconfig.h.in makeopts.in
 	@./configure $(CONFIGURE_SILENT)
-
-$(ALL_TGTS): mxml/libmxml.a
+	@echo "****"
+	@echo "**** The configure script was just executed, so 'make' needs to be"
+	@echo "**** restarted."
+	@echo "****"
+	@exit 1
 
 ifdef C_OBJS
 menuselect_curses.o: CFLAGS+=$(C_INCLUDE)
 cmenuselect: $(OBJS) $(C_OBJS)
-	$(CC) $(LDFLAGS) -o $@ $^ $(C_LIBS)
+	$(CC) $(LDFLAGS) -o $@ $^ $(C_LIBS) $(LIBXML2_LIB)
 else
 cmenuselect:
 endif
@@ -79,7 +83,7 @@
 ifdef G_OBJS
 menuselect_gtk.o: CFLAGS+=$(G_INCLUDE)
 gmenuselect: $(OBJS) $(G_OBJS)
-	$(CC) $(LDFLAGS) -o $@ $^ $(G_LIBS)
+	$(CC) $(LDFLAGS) -o $@ $^ $(G_LIBS) $(LIBXML2_LIB)
 else
 gmenuselect:
 endif
@@ -87,17 +91,15 @@
 ifdef N_OBJS
 menuselect_newt.o: CFLAGS+=$(N_INCLUDE)
 nmenuselect: $(OBJS) $(N_OBJS)
-	$(CC) $(LDFLAGS) -o $@ $^ $(N_LIBS)
+	$(CC) $(LDFLAGS) -o $@ $^ $(N_LIBS) $(LIBXML2_LIB)
 else
 nmenuselect:
 endif
 
+menuselect.o: CFLAGS+=$(LIBXML2_INCLUDE)
+
 menuselect: $(OBJS) $(M_OBJS)
 	$(CC) $(LDFLAGS) -o $@ $^ $(M_LIBS)
-
-mxml/libmxml.a:
-	@if test ! -f mxml/Makefile ; then cd mxml && ./configure ; fi
-	@$(MAKE) -C mxml libmxml.a
 
 test: menuselect
 	(cd test; ../$< menuselect.makeopts)
@@ -113,11 +115,9 @@
 
 clean:
 	rm -f menuselect cmenuselect gmenuselect nmenuselect $(OBJS) $(M_OBJS) $(C_OBJS) $(G_OBJS) $(N_OBJS)
-	@if test -f mxml/Makefile ; then $(MAKE) -C mxml clean ; fi
 
 dist-clean: distclean
 
 distclean: clean
-	@if test -f mxml/Makefile ; then $(MAKE) -C mxml distclean ; fi
 	rm -f autoconfig.h config.status config.log makeopts
 	rm -rf autom4te.cache

Modified: trunk/menuselect/README
URL: http://svnview.digium.com/svn/asterisk/trunk/menuselect/README?view=diff&rev=418834&r1=418833&r2=418834
==============================================================================
--- trunk/menuselect/README (original)
+++ trunk/menuselect/README Thu Jul 17 14:02:22 2014
@@ -34,10 +34,9 @@
 
 libncurses -- This is needed for the curses frontend.
 libnewt -- This is needed for the newt frontend (optional).
-libmxml -- This library, Mini-XML, is used for XML parsing. 
-           (http://www.easysw.com/~mike/mxml/)
-	   (Asterisk uses the code in http://svn.digium.com/svn/mxml/ )
-
+libxml2 -- This library, the XML C parser and toolkit of Gnome, is used for
+           XML parsing. 
+           (http://xmlsoft.org/)
 
 ENVIRONMENT SETUP
 

Modified: trunk/menuselect/acinclude.m4
URL: http://svnview.digium.com/svn/asterisk/trunk/menuselect/acinclude.m4?view=diff&rev=418834&r1=418833&r2=418834
==============================================================================
--- trunk/menuselect/acinclude.m4 (original)
+++ trunk/menuselect/acinclude.m4 Thu Jul 17 14:02:22 2014
@@ -197,3 +197,45 @@
       [ac_cv_func_fork_works=no],
       [ac_cv_func_fork_works=cross])])]
 )# _AST_FUNC_FORK
+
+# Check for a package using $2-config. Similar to AST_EXT_LIB_CHECK,
+# but use $2-config to determine cflags and libraries to use.
+# $3 and $4 can be used to replace --cflags and --libs in the request
+
+# AST_EXT_TOOL_CHECK([package], [tool name], [--cflags], [--libs], [includes], [expression])
+AC_DEFUN([AST_EXT_TOOL_CHECK],
+[
+	if test "x${PBX_$1}" != "x1" -a "${USE_$1}" != "no"; then
+		PBX_$1=0
+		AC_PATH_TOOL(CONFIG_$1, $2, No, [${$1_DIR}/bin:$PATH])
+		if test ! "x${CONFIG_$1}" = xNo; then
+			if test x"$3" = x ; then A=--cflags ; else A="$3" ; fi
+			$1_INCLUDE=$(${CONFIG_$1} $A)
+			$1_INCLUDE=$(echo ${$1_INCLUDE} | sed -e "s|-I|-I${$1_DIR}|g")
+
+			if test x"$4" = x ; then A=--libs ; else A="$4" ; fi
+			$1_LIB=$(${CONFIG_$1} $A)
+			$1_LIB=$(echo ${$1_LIB} | sed -e "s|-L|-L${$1_DIR}|g")
+
+			if test x"$5" != x ; then
+				saved_cppflags="${CPPFLAGS}"
+				CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE}"
+
+				saved_libs="${LIBS}"
+				LIBS=${$1_LIB}
+
+				AC_LINK_IFELSE(
+					[ AC_LANG_PROGRAM( [ $5 ], [ $6; ])],
+					[ PBX_$1=1 AC_DEFINE([HAVE_$1], 1,
+						[Define if your system has the $1 headers.])],
+					[]
+				)
+				CPPFLAGS="${saved_cppflags}"
+				LIBS="${saved_libs}"
+			else
+				PBX_$1=1
+				AC_DEFINE([HAVE_$1], 1, [Define if your system has the $1 libraries.])
+			fi
+		fi
+	fi
+])

Modified: trunk/menuselect/aclocal.m4
URL: http://svnview.digium.com/svn/asterisk/trunk/menuselect/aclocal.m4?view=diff&rev=418834&r1=418833&r2=418834
==============================================================================
--- trunk/menuselect/aclocal.m4 (original)
+++ trunk/menuselect/aclocal.m4 Thu Jul 17 14:02:22 2014
@@ -1,7 +1,8 @@
-# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
+# generated automatically by aclocal 1.11.3 -*- Autoconf -*-
 
 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-# 2005, 2006, 2007, 2008, 2009  Free Software Foundation, Inc.
+# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
+# Inc.
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.

Modified: trunk/menuselect/autoconfig.h.in
URL: http://svnview.digium.com/svn/asterisk/trunk/menuselect/autoconfig.h.in?view=diff&rev=418834&r1=418833&r2=418834
==============================================================================
--- trunk/menuselect/autoconfig.h.in (original)
+++ trunk/menuselect/autoconfig.h.in Thu Jul 17 14:02:22 2014
@@ -46,6 +46,9 @@
 
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H
+
+/* Define if your system has the LIBXML2 libraries. */
+#undef HAVE_LIBXML2
 
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
@@ -110,6 +113,9 @@
 /* Define to the one symbol short name of this package. */
 #undef PACKAGE_TARNAME
 
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
@@ -124,5 +130,8 @@
 /* Define to 1 if you have the ANSI C header files. */
 #undef STDC_HEADERS
 
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
 #endif
 

Modified: trunk/menuselect/configure.ac
URL: http://svnview.digium.com/svn/asterisk/trunk/menuselect/configure.ac?view=diff&rev=418834&r1=418833&r2=418834
==============================================================================
--- trunk/menuselect/configure.ac (original)
+++ trunk/menuselect/configure.ac Thu Jul 17 14:02:22 2014
@@ -120,10 +120,19 @@
 AST_EXT_LIB_SETUP([NEWT], [newt], [newt])
 AST_EXT_LIB_SETUP([CURSES], [curses], [curses])
 AST_EXT_LIB_SETUP([NCURSES], [ncurses], [ncurses])
+AST_EXT_LIB_SETUP([LIBXML2], [LibXML2], [libxml2])
 
 AST_EXT_LIB_CHECK([NEWT], [newt], [newtBell], [newt.h])
 AST_EXT_LIB_CHECK([CURSES], [curses], [initscr], [curses.h])
 AST_EXT_LIB_CHECK([NCURSES], [ncurses], [initscr], [curses.h])
+AST_EXT_TOOL_CHECK([LIBXML2], [xml2-config], , ,
+        [#include <libxml/tree.h>
+        #include <libxml/parser.h>],
+        [LIBXML_TEST_VERSION])
+
+if test "${PBX_LIBXML2}" != 1; then
+  AC_MSG_ERROR([coult not find required 'Libxml2' development package])
+fi
 
 PBX_GTK2=0
 AC_CHECK_TOOL(PKGCONFIG, pkg-config, No)
@@ -140,7 +149,6 @@
 test "$silent"=yes && ac_sub_configure_args="${ac_sub_configure_args} --silent"
 
 AC_CONFIG_FILES([makeopts])
-AC_CONFIG_SUBDIRS([mxml])
 AC_OUTPUT
 
 AC_MSG_NOTICE(Menuselect build configuration successfully completed)

Modified: trunk/menuselect/example_menuselect-tree
URL: http://svnview.digium.com/svn/asterisk/trunk/menuselect/example_menuselect-tree?view=diff&rev=418834&r1=418833&r2=418834
==============================================================================
--- trunk/menuselect/example_menuselect-tree (original)
+++ trunk/menuselect/example_menuselect-tree Thu Jul 17 14:02:22 2014
@@ -1,4 +1,4 @@
-<?xml version=1.0?>
+<?xml version="1.0"?>
 
 <menu name="Asterisk Module Selection">
 	<category name="MENUSELECT_APPS" displayname="Applications">

Modified: trunk/menuselect/makeopts.in
URL: http://svnview.digium.com/svn/asterisk/trunk/menuselect/makeopts.in?view=diff&rev=418834&r1=418833&r2=418834
==============================================================================
--- trunk/menuselect/makeopts.in (original)
+++ trunk/menuselect/makeopts.in Thu Jul 17 14:02:22 2014
@@ -20,3 +20,7 @@
 
 NEWT_INCLUDE=@NEWT_INCLUDE@
 NEWT_LIB=@NEWT_LIB@
+
+LIBXML2_INCLUDE=@LIBXML2_INCLUDE@
+LIBXML2_LIB=@LIBXML2_LIB@
+

Modified: trunk/menuselect/menuselect.c
URL: http://svnview.digium.com/svn/asterisk/trunk/menuselect/menuselect.c?view=diff&rev=418834&r1=418833&r2=418834
==============================================================================
--- trunk/menuselect/menuselect.c (original)
+++ trunk/menuselect/menuselect.c Thu Jul 17 14:02:22 2014
@@ -30,11 +30,16 @@
 #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;
@@ -52,7 +57,7 @@
 */
 struct tree {
 	/*! the root of the tree */
-	mxml_node_t *root;
+	xmlDoc *root;
 	/*! for linking */
 	AST_LIST_ENTRY(tree) list;
 };
@@ -157,83 +162,68 @@
 #endif
 }
 
-/*! \brief Add a category to the category list, ensuring that there are no duplicates */
-static struct category *add_category(struct category *cat)
-{
-	struct category *tmp;
-
-	AST_LIST_TRAVERSE(&categories, tmp, list) {
-		if (!strcmp(tmp->name, cat->name)) {
-			return tmp;
-		}
-	}
-	AST_LIST_INSERT_TAIL(&categories, cat, list);
-
-	return cat;
-}
-
-#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;
-
-	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);
-
-	return 0;
-}
-#endif
-
-static int add_member_after(struct member *mem, struct category *cat, struct member *place)
-{
-	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;
-		}
-	}
-	AST_LIST_INSERT_AFTER(&cat->members, place, mem, list);
-
-	return 0;
-
-}
-
-static int add_member_head(struct member *mem, struct category *cat)
-{
-	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;
-		}
-	}
-	AST_LIST_INSERT_HEAD(&cat->members, mem, list);
-
-	return 0;
+/*! \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 *c;
+
+	AST_LIST_TRAVERSE(&categories, c, list) {
+		if (!strcmp(c->name, name)) {
+			xmlFree((void *) name);
+			return c;
+		}
+	}
+
+	if (!(c = calloc(1, sizeof(*c)))) {
+		return NULL;
+	}
+
+	c->name = name;
+
+	AST_LIST_INSERT_TAIL(&categories, c, list);
+
+	return c;
+}
+
+static void free_reference(struct reference *ref)
+{
+	/* 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);
+	}
+
+	free(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;
-
-	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);
+	struct reference *ref;
+
+	if (!mem) {
+		return;
+	}
+
+	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);
+
+	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);
+	}
+
 	free(mem);
 }
 
@@ -264,294 +254,358 @@
 {
 	switch (support_level) {
 	case SUPPORT_CORE:
-		return "core";
+		return "Core";
 	case SUPPORT_EXTENDED:
-		return "extended";
+		return "Extended";
 	case SUPPORT_DEPRECATED:
-		return "deprecated";
+		return "Deprecated";
 	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)
-{
-	separators[level] = calloc(1, sizeof(*(separators[level])));
-	separators[level]->name = support_level_to_string(level);
-	separators[level]->displayname = "";
-	separators[level]->is_separator = 1;
+static struct member *create_separator(enum support_level_values level)
+{
+	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[])
-{
-	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;
-		}
-	}
-
-	for (level = 0; level < SUPPORT_COUNT; level++) {
-		if (!used[level]) {
-			initialize_separator(separators, level);
-		}
-	}
-}
-
-/*! \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[])
-{
-	enum support_level_values support_level = string_to_support_level(mem->support_level);
-	int tail_index;
-
-	/* 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 (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... */
+static int process_xml_defaultenabled_node(xmlNode *node, struct member *mem)
+{
+	const char *tmp = (const char *) xmlNodeGetContent(node);
+
+	if (tmp && !strlen_zero(tmp)) {
+		mem->defaultenabled = tmp;
+	}
+
+	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;
+}
+
+static int process_xml_replacement_node(xmlNode *node, struct member *mem)
+{
+	const char *tmp = (const char *) xmlNodeGetContent(node);
+
+	if (tmp && !strlen_zero(tmp)) {
+		mem->replacement = tmp;
+	}
+
+	return 0;
+}
+
+static int process_xml_ref_node(xmlNode *node, struct member *mem, struct reference_list *refs)
+{
+	struct reference *ref;
+	const char *tmp;
+
+	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;
+		}
+	}
+
+	tmp = (const char *) xmlNodeGetContent(node);
+
+	if (tmp && !strlen_zero(tmp)) {
+		ref->displayname = tmp;
+		if (!ref->name) {
+			ref->name = ref->displayname;
+		}
+
+		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 process_xml_unknown_node;
+}
+
+static int process_process_xml_category_child_node(xmlNode *node, struct member *mem)
+{
+	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;
+	xmlChar *tmp;
+
+	if (!(mem = calloc(1, sizeof(*mem)))) {
+		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);
+	}
+
+	for (cur = node->children; cur; cur = cur->next) {
+		if (cur->type != XML_ELEMENT_NODE) {
+			continue;
+		}
+
+		process_process_xml_category_child_node(cur, mem);
+	}
+
+	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);
+		}
+	}
+
+	if (add_member_list_order(mem, cat)) {
+		free_member(mem);
+	}
+
+	return 0;
+}
+
+static void free_category(struct category *cat)
+{
+	struct member *mem;
+
+	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);
+}
+
+static int process_xml_category_node(xmlNode *node)
+{
+	struct category *cat;
+	const char *tmp;
+	xmlNode *cur;
+
+	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 ((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;
+		}
+
+		if (xmlStrcmp(cur->name, BAD_CAST "member")) {
+			fprintf(stderr, "Ignoring unknown element: %s\n", cur->name);
+			continue;
+		}
+
+		process_xml_member_node(cur, cat);
+	}
+
+	return 0;
+}
+
+static int process_xml_menu_node(struct tree *tree, xmlNode *node)
+{
+	xmlNode *cur;
+	xmlChar *tmp;
+
+	if (strcmp((const char *) node->name, "menu")) {
+		fprintf(stderr, "Invalid document: Expected \"menu\" element.\n");
+		return -1;
+	}
+
+	AST_LIST_INSERT_HEAD(&trees, tree, list);
+
+	if ((tmp = xmlGetProp(node, BAD_CAST "name"))) {
+		menu_name = (const char *) tmp;
+	}
+
+	for (cur = node->children; cur; cur = cur->next) {
+		if (cur->type != XML_ELEMENT_NODE) {
+			continue;
+		}
+
+		if (xmlStrcmp(cur->name, BAD_CAST "category")) {
+			fprintf(stderr, "Ignoring unknown element: %s\n", cur->name);
+			continue;
+		}
+
+		if (process_xml_category_node(cur)) {
 			return -1;
 		}
-
-		/* 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;
-
-	} 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;
-		}
-
-		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;
-			}
-		}
-
-		return 0;
-
-	}
-
-	return -2; /* failed to place... for whatever reason.  This should be impossible to reach. */
+	}
+
+	categories_flatten();
+
+	return 0;
 }
 
 /*! \brief Parse an input makeopts file */
 static int parse_tree(const char *tree_file)
 {
-	FILE *f;
 	struct tree *tree;
-	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;
-
-	if (!(f = fopen(tree_file, "r"))) {
-		fprintf(stderr, "Unable to open '%s' for reading!\n", tree_file);
+	xmlNode *menu;
+
+	if (!(tree = calloc(1, sizeof(*tree)))) {
 		return -1;
 	}
 
-	if (!(tree = calloc(1, sizeof(*tree)))) {
-		fclose(f);
-		return -1;
-	}
-
-	if (!(tree->root = mxmlLoadFile(NULL, f, MXML_OPAQUE_CALLBACK))) {
-		fclose(f);
+	if (!(tree->root = xmlParseFile(tree_file))) {
 		free(tree);
 		return -1;
 	}
 
-	AST_LIST_INSERT_HEAD(&trees, tree, list);
-
-	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;
-
-		/* Member seperator definitions */
-		struct member *separators[SUPPORT_COUNT];
-
-		/* 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 };
-
-		if (!(cat = calloc(1, sizeof(*cat))))
-			return -1;
-
-		cat->name = mxmlElementGetAttr(cur, "name");
-
-		newcat = add_category(cat);
-
-		if (newcat != cat) {
-			/* want to append members, and potentially update the category. */
-			free(cat);
-			cat = newcat;
-		}
-
-		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");
-			}
-
-			cur3 = mxmlFindElement(cur2, cur2, "defaultenabled", NULL, NULL, MXML_DESCEND);
-			if (cur3 && cur3->child) {
-				mem->defaultenabled = cur3->child->value.opaque;
-			}
-
-			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);
-				}
-			}
-
-			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);
-			}
-
-			cur3 = mxmlFindElement(cur2, cur2, "replacement", NULL, NULL, MXML_DESCEND);
-			if (cur3 && cur3->child) {
-				mem->replacement = cur3->child->value.opaque;
-			}
-
-			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);
-			}
-
-			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);
-			}
-
-			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;
-					}
-
-					AST_LIST_INSERT_TAIL(&mem->uses, use, list);
-				} else {
-					free(use);
-				}
-			}
-
-			if (add_member_list_order(mem, cat, support_tails, support_tails_placed, separators)) {
-				free_member(mem);
-			}
-		}
-	}
-
-	fclose(f);
+	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 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 @@
 	struct tree *tree;
 
 	while ((tree = AST_LIST_REMOVE_HEAD(&trees, list))) {
-		mxmlDelete(tree->root);
+		xmlFreeDoc(tree->root);
 		free(tree);
 	}
 }
@@ -1923,6 +1964,8 @@
 		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 @@
 
 	close_debug();
 
+	xmlCleanupParser();
+
 	exit(res);
 }

Modified: trunk/menuselect/menuselect.h
URL: http://svnview.digium.com/svn/asterisk/trunk/menuselect/menuselect.h?view=diff&rev=418834&r1=418833&r2=418834
==============================================================================
--- trunk/menuselect/menuselect.h (original)
+++ trunk/menuselect/menuselect.h Thu Jul 17 14:02:22 2014
@@ -53,6 +53,8 @@
 	HARD_FAILURE = 2,
 };
 
+AST_LIST_HEAD_NOLOCK(reference_list, reference);
+
 struct member {
 	/*! What will be sent to the makeopts file */
 	const char *name;
@@ -87,11 +89,11 @@
 	 * be passed over for many of the usual purposes associated with members. */
 	unsigned int is_separator:1;
 	/*! dependencies of this module */
-	AST_LIST_HEAD_NOLOCK(, reference) deps;
+	struct reference_list deps;
 	/*! conflicts of this module */
-	AST_LIST_HEAD_NOLOCK(, reference) conflicts;
+	struct reference_list conflicts;
 	/*! optional packages used by this module */
-	AST_LIST_HEAD_NOLOCK(, reference) uses;
+	struct reference_list uses;
 	/*! for making a list of modules */
 	AST_LIST_ENTRY(member) list;
 };
@@ -104,8 +106,11 @@
 	SUPPORT_COUNT = 4, /* Keep this item at the end of the list. Tracks total number of support levels. */
 };
 
+AST_LIST_HEAD_NOLOCK(support_level_bucket, member);
+
 struct category {
-	struct member *separators[SUPPORT_COUNT];
+	/*! Workspace for building support levels */
+	struct support_level_bucket buckets[SUPPORT_COUNT];
 	/*! the Makefile variable */
 	const char *name;
 	/*! the name displayed in the menu */




More information about the asterisk-commits mailing list