[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