vty: Add xsd and a command that can generate the documentation.

When building the doxygen documentation do not remove the other
VTY documentation files in the doc/vty folder. Create a command
that can be installed to dump all nodes and commands as XML on
the given VTY. Create a schema for the XML file and a XSL-T script
that can merge the generated file with additional information.
jolly/7bit_ussd
Holger Hans Peter Freyther 11 years ago
parent aa5d0e8894
commit 8297c819e9
  1. 3
      .gitignore
  2. 3
      Makefile.am
  3. 22
      doc/vty/example.xml
  4. 37
      doc/vty/merge_doc.xsl
  5. 46
      doc/vty/vtydoc.xsd
  6. 148
      src/vty/command.c

3
.gitignore vendored

@ -61,7 +61,8 @@ utils/osmo-auc-gen
doc/codec
doc/core
doc/vty
doc/vty/latex
doc/vty/html
doc/gsm
doc/html.tar

@ -36,8 +36,7 @@ $(top_builddir)/doc/gsm/html/index.html: $(SOURCES) Doxyfile.gsm
$(DOXYGEN) Doxyfile.gsm
$(top_builddir)/doc/vty/html/index.html: $(SOURCES) Doxyfile.vty
@rm -rf doc/vty
mkdir -p doc/vty
@rm -rf doc/vty/{html,latex}
$(DOXYGEN) Doxyfile.vty
$(top_builddir)/doc/codec/html/index.html: $(SOURCES) Doxyfile.codec

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<vtydoc xmlns="urn:osmocom:xml:libosmocore:vty:doc:1.0">
<!-- test a nested hierachy -->
<node id="mgcp" name="MGCP Node">
<!-- define a command -->
<command id="foo_cmd">
<doc>General docs</doc>
<params>
<param name="do" doc="Explain do" />
<param name="fo" doc="Explain foo" />
</params>
</command>
<command id="foo_cmd">
<doc>General docs</doc>
<params>
<param name="do" doc="Explain do" />
<param name="fo" doc="Explain foo" />
</params>
</command>
</node>
</vtydoc>

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:vty="urn:osmocom:xml:libosmocore:vty:doc:1.0">
<xsl:output method="xml" version="1.0" encoding="ISO-8859-1" indent="yes" />
<xsl:variable name="with" select="'additions.xml'" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<!-- Copy the name of the node -->
<xsl:template match="vty:node">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
<xsl:variable name="info" select="document($with)/vty:vtydoc/vty:node[@id=current()/@id]/." />
<xsl:for-each select="$info/vty:name">
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:copy>
</xsl:template>
<!-- Copy command and add nodes -->
<xsl:template match="vty:command">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
<xsl:variable name="info" select="document($with)/vty:vtydoc/vty:node[@id=current()/../@id]/vty:command[@id=current()/@id]/." />
<xsl:for-each select="$info/*">
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:transform>

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns="urn:osmocom:xml:libosmocore:vty:doc:1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:osmocom:xml:libosmocore:vty:doc:1.0"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:complexType name="ParamType">
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="doc" type="xs:string" use="required" />
</xs:complexType>
<xs:complexType name="ParamsType">
<xs:sequence>
<xs:element name="param" type="ParamType" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="CommandType">
<xs:sequence>
<xs:element name="doc" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="params" type="ParamsType" minOccurs="1" maxOccurs="1"/>
<xs:element name="enter" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required" />
</xs:complexType>
<xs:complexType name="NodeType">
<xs:sequence>
<xs:element name="command" type="CommandType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="id" type="xs:anyURI"/>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
<!-- the main entry -->
<xs:element name="vtydoc">
<xs:complexType>
<xs:sequence>
<xs:element name="node" type="NodeType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

@ -405,6 +405,145 @@ const char *cmd_prompt(enum node_type node)
return cnode->prompt;
}
static char *xml_escape(const char *inp)
{
int _strlen;
char *out, *out_ptr;
int len = 0, i, j;
if (!inp)
return NULL;
_strlen = strlen(inp);
for (i = 0; i < _strlen; ++i) {
switch (inp[i]) {
case '"':
len += 6;
break;
case '\'':
len += 6;
break;
case '<':
len += 4;
break;
case '>':
len += 4;
break;
case '&':
len += 5;
break;
default:
len += 1;
break;
}
}
out = talloc_size(NULL, len + 1);
if (!out)
return NULL;
out_ptr = out;
#define ADD(out, str) \
for (j = 0; j < strlen(str); ++j) \
*(out++) = str[j];
for (i = 0; i < _strlen; ++i) {
switch (inp[i]) {
case '"':
ADD(out_ptr, "&quot;");
break;
case '\'':
ADD(out_ptr, "&apos;");
break;
case '<':
ADD(out_ptr, "&lt;");
break;
case '>':
ADD(out_ptr, "&gt;");
break;
case '&':
ADD(out_ptr, "&amp;");
break;
default:
*(out_ptr++) = inp[i];
break;
}
}
#undef ADD
out_ptr[0] = '\0';
return out;
}
/*
* Write one cmd_element as XML to the given VTY.
*/
static int vty_dump_element(struct cmd_element *cmd, struct vty *vty)
{
char *xml_string = xml_escape(cmd->string);
vty_out(vty, " <command id='%s'>%s", xml_string, VTY_NEWLINE);
vty_out(vty, " <params>%s", VTY_NEWLINE);
int j;
for (j = 0; j < vector_count(cmd->strvec); ++j) {
vector descvec = vector_slot(cmd->strvec, j);
int i;
for (i = 0; i < vector_active(descvec); ++i) {
char *xml_param, *xml_doc;
struct desc *desc = vector_slot(descvec, i);
if (desc == NULL)
continue;
xml_param = xml_escape(desc->cmd);
xml_doc = xml_escape(desc->str);
vty_out(vty, " <param name='%s' doc='%s' />%s",
xml_param, xml_doc, VTY_NEWLINE);
talloc_free(xml_param);
talloc_free(xml_doc);
}
}
vty_out(vty, " </params>%s", VTY_NEWLINE);
vty_out(vty, " </command>%s", VTY_NEWLINE);
talloc_free(xml_string);
return 0;
}
/*
* Dump all nodes and commands associated with a given node as XML to the VTY.
*/
static int vty_dump_nodes(struct vty *vty)
{
int i, j;
vty_out(vty, "<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>%s", VTY_NEWLINE);
for (i = 0; i < vector_active(cmdvec); ++i) {
struct cmd_node *cnode;
cnode = vector_slot(cmdvec, i);
if (!cnode)
continue;
vty_out(vty, " <node id='%d'>%s", i, VTY_NEWLINE);
for (j = 0; j < vector_active(cnode->cmd_vector); ++j) {
struct cmd_element *elem;
elem = vector_slot(cnode->cmd_vector, j);
vty_dump_element(elem, vty);
}
vty_out(vty, " </node>%s", VTY_NEWLINE);
}
vty_out(vty, "</vtydoc>%s", VTY_NEWLINE);
return 0;
}
/*! \brief Install a command into a node
* \param[in] ntype Node Type
* \param[cmd] element to be installed
@ -2232,6 +2371,13 @@ DEFUN(show_version,
return CMD_SUCCESS;
}
DEFUN(show_online_help,
show_online_help_cmd, "show online-help", SHOW_STR "Online help\n")
{
vty_dump_nodes(vty);
return CMD_SUCCESS;
}
/* Help display function for all node. */
gDEFUN(config_help,
config_help_cmd, "help", "Description of the interactive help system\n")
@ -3269,6 +3415,7 @@ void cmd_init(int terminal)
/* Each node's basic commands. */
install_element(VIEW_NODE, &show_version_cmd);
install_element(VIEW_NODE, &show_online_help_cmd);
if (terminal) {
install_element(VIEW_NODE, &config_list_cmd);
install_element(VIEW_NODE, &config_exit_cmd);
@ -3288,6 +3435,7 @@ void cmd_init(int terminal)
}
install_element (ENABLE_NODE, &show_startup_config_cmd);
install_element(ENABLE_NODE, &show_version_cmd);
install_element(ENABLE_NODE, &show_online_help_cmd);
if (terminal) {
install_element(ENABLE_NODE, &config_terminal_length_cmd);

Loading…
Cancel
Save