[asterisk-commits] mvanbaak: branch group/appdocsxml r137270 - /team/group/appdocsxml/main/pbx.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Aug 11 15:16:42 CDT 2008


Author: mvanbaak
Date: Mon Aug 11 15:16:42 2008
New Revision: 137270

URL: http://svn.digium.com/view/asterisk?view=rev&rev=137270
Log:
Lets generate syntax.
Patch taken verbatim from eliel's mail.

My patch had the two defined helper functions inline.
This is cleaner. Thank you for the work on it.

Output is a mess, we'll have to take a look at that later.

I think we are ready to start converting stuff.

Modified:
    team/group/appdocsxml/main/pbx.c

Modified: team/group/appdocsxml/main/pbx.c
URL: http://svn.digium.com/view/asterisk/team/group/appdocsxml/main/pbx.c?view=diff&rev=137270&r1=137269&r2=137270
==============================================================================
--- team/group/appdocsxml/main/pbx.c (original)
+++ team/group/appdocsxml/main/pbx.c Mon Aug 11 15:16:42 2008
@@ -2836,9 +2836,238 @@
 	return node;
 }
 
+/*! \brief Helper function used to build the syntax, it allocates the needed buffer (or reallocates it),
+ *         and based on the reverse value it makes use of fmt or fmtrev to print paramname inside the 
+ *         realloced buffer (syntax).
+ *  \param reverse We are goinf backwards while generating the syntax?
+ *  \param len Current length of 'syntax' buffer.
+ *  \param syntax Output buffer for the concatenated values.
+ *  \param paramname Parameter name, it can't be NULL! at least put "".
+ *  \param fmt A format string that will be used in a sprintf call, it must always have a %s inside it, even if
+ *         not needed!.
+ *  \param fmtrev A format string that will be used in a sprintf call when reverse=1, it must always have a %s
+ *         inside it, event if not used.
+ */
+static void ast_xml_doc_reverse_helper(int reverse, int *len, char **syntax, const char *paramname, char *fmt, char *fmtrev)
+{
+	int fmtlen = (reverse ? strlen(fmtrev) : strlen(fmt));
+	int i;
+	char *usefmt = (reverse ? fmtrev : fmt), tmp;
+	int totlen = *len + fmtlen + strlen(paramname) + 1 - 2; /* -2 to remove %s */
+
+	if (!paramname) {
+		paramname = "";
+	}
+
+	/* '- 2' do not count %s that is always present! */
+	*syntax = ast_realloc(*syntax, totlen);
+
+	if (!*syntax) {
+		/* memory allocation failure. */
+		return;
+	}
+
+	if (reverse) {
+		memmove(*syntax + totlen - *len - 1, *syntax, *len);
+		(*syntax)[totlen - 1] = '\0';
+		/* This char will be overwritten by the '\0', so save it. */
+		tmp = (*syntax)[0];
+		i = sprintf(*syntax, usefmt, paramname);
+		(*syntax)[i] = tmp;
+		/* Recover the over written char. */
+		*len = totlen - 1;
+	} else {
+		*len += sprintf(*syntax + *len, usefmt, paramname);
+	}
+}
+
+/*! \brief Build the syntax for an application or a function.
+ *  \param type 'application' or 'function' ?
+ *  \param name Name of the application or function to build the syntax.
+ *  \retval NULL on error.
+ *  \retval A ast_malloc'ed string with the syntax generated. */
 static char *ast_xml_doc_build_syntax(const char *type, const char *name) 
-{	
-	return NULL;
+{
+#define GOTONEXT(__rev, __a) (__rev ? __a->AST_XML_PREV : __a->AST_XML_NEXT)
+#define ISLAST(__rev, __a)  (__rev == 1 ? (__a->AST_XML_PREV ? 0 : 1) : (__a->AST_XML_NEXT ? 0 : 1))
+	ast_xml_node *node, *firstparam, *lastparam;
+	ast_xml_attr *paramtype, *paramname;
+	int reverse = 0, required = 0, paramcount = 0, openbrackets = 0, len = 0;
+	char *syntax = NULL;
+
+	if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
+		ast_log(LOG_WARNING, "Tried to look in XML tree with faulty values.\n");
+		return NULL;
+	}
+
+	node = ast_xml_doc_get_node(documentation_tree, type, name, documentation_language);
+	if (!node || !node->AST_XML_CHILD) {
+		return NULL;
+	}
+
+	/* Find the syntax field. */
+	node = node->AST_XML_CHILD;
+	while (node) {
+		if (!strcasecmp((char *)node->AST_XML_NAME, "syntax")) {
+			break;
+		}
+		node = node->AST_XML_NEXT;
+	}
+	
+	if (!node || !node->AST_XML_CHILD) {
+		/* If the syntax field is not found, at least print the
+		   application/function name. */
+		syntax = ast_malloc(strlen(name) + 3);
+		sprintf(syntax, "%s()", name);
+		return syntax;
+	}
+
+	/* Get order of evaluation. */
+	node = node->AST_XML_CHILD;
+	firstparam = node;
+	while (node) {
+		if (!strcasecmp((char *)node->AST_XML_NAME, "parameter")) {
+			paramtype = ast_xml_get_attribute(node, "required");
+			reverse = 1;
+			if (paramtype) {
+				if (ast_true((char *)paramtype)) {
+					reverse = 0;
+				}
+				ast_xml_free_attr(paramtype);
+			}
+			break;
+		}
+		node = node->AST_XML_NEXT;
+	}
+
+	if (reverse) {
+		/* Go to the last element. */
+		while (node) {
+			if (!node->AST_XML_NEXT) {
+				break;
+			}
+			node = node->AST_XML_NEXT;
+		}
+	}
+
+	/* If starts with an optional parameter and ends with an optional paramenter,
+	   reverse = 0, and start from the first parameter.
+           If starts with a required parameter reverse = 0. 
+           If starts with an optional parameter and ends with a required parameter
+           reverse = 1 and start from the last parameter */
+	if (reverse) {
+		/* find the last parameter. */
+		while (node) {
+			/* Check if last element is also optional (is so,
+			   go to the begining again). */
+			if (strcasecmp((char *)node->AST_XML_NAME, "parameter")) {
+				node = GOTONEXT(reverse, node);
+				continue;
+			}
+			break;
+		}
+
+		if (!node) {
+			/* Huh? We must at least find one parameter! */
+			return NULL;
+		}
+
+		lastparam = node;
+		paramtype = ast_xml_get_attribute(node, "required");
+		reverse = 0;
+		node = firstparam;
+		if (paramtype) {
+			if (ast_true((char *)paramtype)) {
+				node = lastparam;
+				reverse = 1;
+			}
+			ast_xml_free_attr(paramtype);
+		}
+	}
+
+	/* init syntax string. */
+	if (!reverse) {
+		ast_xml_doc_reverse_helper(reverse, &len, &syntax, name, "%s(", "");
+	} else {
+		ast_xml_doc_reverse_helper(reverse, &len, &syntax, "", "", "%s)");
+	}
+
+	while (node) {
+		if (strcasecmp((char *)node->AST_XML_NAME, "parameter")) {
+			node = GOTONEXT(reverse, node);
+			continue;
+		}
+
+		paramname = ast_xml_get_attribute(node, "name");
+		if (!paramname) {
+			ast_log(LOG_WARNING, "Malformed XML %s/%s: no parameter name\n", type, name);
+			if (syntax) {
+				/* Free already allocated syntax */
+				ast_free(syntax);
+			}
+			/* to give up is ok? */
+			syntax = ast_malloc(strlen(name) + 3);
+			sprintf(syntax, "%s()", name);
+			return syntax;
+		}
+
+		required = 0;	/* Defaults to 'false'. */
+		paramtype = ast_xml_get_attribute(node, "required");
+		if (paramtype) {
+			if (ast_true((char *)paramtype)) {
+				required = 1;
+			}
+			ast_xml_free_attr(paramtype);
+		}
+
+		/* build syntax core. */
+
+		if (required) {
+			/* First parameter */
+			if (!paramcount) {
+				ast_xml_doc_reverse_helper(reverse, &len, &syntax, (const char *)paramname, "%s", "%s");
+			} else {
+				while (openbrackets > 0) {
+					ast_xml_doc_reverse_helper(reverse, &len, &syntax, "", "%s]", "[%s");
+					openbrackets--;
+				}
+				ast_xml_doc_reverse_helper(reverse, &len, &syntax, (const char *)paramname, ",%s", "%s,");
+			}
+		} else {
+			/* First parameter */
+			if (!paramcount) {
+				ast_xml_doc_reverse_helper(reverse, &len, &syntax, (const char *)paramname, "[%s]", "[%s]");
+			} else {
+				if (ISLAST(reverse, node)) {
+					ast_xml_doc_reverse_helper(reverse, &len, &syntax, (const char *)paramname, ",[%s]", "[%s],");
+				} else {
+					ast_xml_doc_reverse_helper(reverse, &len, &syntax, (const char *)paramname, "[,%s", "%s,]");
+					openbrackets++;
+				}
+			}
+		}
+
+		ast_xml_free_attr(paramname);
+
+		node = GOTONEXT(reverse, node);
+		paramcount++;
+	}
+
+	while (openbrackets > 0) {
+		ast_xml_doc_reverse_helper(reverse, &len, &syntax, "", "%s]", "%s[");
+		openbrackets--;
+	}
+
+	/* close syntax string. */
+	if (!reverse) {	
+		ast_xml_doc_reverse_helper(reverse, &len, &syntax, "", "%s)", "");
+	} else {
+		ast_xml_doc_reverse_helper(reverse, &len, &syntax, name, "", "%s(");
+	}
+
+	return syntax;
+#undef ISLAST
+#undef GOTONEXT
 }
 
 /*! \brief Parse a <para> element.




More information about the asterisk-commits mailing list