Fix xsd generation in ddsconf

Signed-off-by: Jeroen Koekkoek <jeroen@koekkoek.nl>
This commit is contained in:
Jeroen Koekkoek 2020-06-26 09:32:24 +02:00
parent 93c75186f0
commit f4e99f41f6
13 changed files with 132 additions and 101 deletions

View file

@ -192,7 +192,6 @@ script:
-DENABLE_LIFESPAN=${LIFESPAN}
-DENABLE_DEADLINE_MISSED=${DEADLINE}
-DBUILD_TESTING=on
-DBUILD_SCHEMA=on
-DWERROR=on
-G "${GENERATOR}" ..
- |
@ -219,8 +218,6 @@ script:
fi
- |
if [ "${SSL}" = "YES" ] && [ "${SECURITY}" = "YES" ]; then
cmake --build . --config ${BUILD_TYPE} --target schema && \
cmake --build . --config ${BUILD_TYPE} --target options_doc && \
diff --strip-trailing-cr ../etc/cyclonedds.rnc docs/cyclonedds.rnc && \
diff --strip-trailing-cr ../etc/cyclonedds.xsd docs/cyclonedds.xsd && \
diff --strip-trailing-cr ../docs/manual/options.md docs/manual/options.md

View file

@ -210,8 +210,12 @@ option(BUILD_TESTING "Build the testing tree." OFF)
include(CTest)
option(BUILD_DOCS "Build documentation." OFF)
option(BUILD_SCHEMA "Build generated schema for configuration options." OFF)
if(CMAKE_CROSSCOMPILING)
set(not_crosscompiling OFF)
else()
set(not_crosscompiling ON)
endif()
option(BUILD_SCHEMA "Build generated schema for configuration options." ${not_crosscompiling})
# Build all executables and libraries into the top-level /bin and /lib folders.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")

View file

@ -18,18 +18,14 @@ set(options_md "${CMAKE_CURRENT_BINARY_DIR}/manual/options.md")
if(BUILD_SCHEMA OR BUILD_DOCS)
add_custom_command(
OUTPUT "${cyclonedds_rnc}" "${cyclonedds_xsd}"
OUTPUT "${cyclonedds_rnc}" "${cyclonedds_xsd}" "${options_md}"
COMMAND ddsconf ARGS -f rnc -o "${cyclonedds_rnc}"
COMMAND ddsconf ARGS -f xsd -o "${cyclonedds_xsd}"
DEPENDS ddsconf)
add_custom_target(schema DEPENDS "${cyclonedds_rnc}" "${cyclonedds_xsd}")
add_custom_command(
OUTPUT "${options_md}"
COMMAND ${CMAKE_COMMAND} -E make_directory manual
COMMAND ddsconf ARGS -f md -o "${options_md}"
DEPENDS ddsconf)
add_custom_target(options_doc DEPENDS "${options_md}")
add_custom_target(
schema ALL DEPENDS "${cyclonedds_rnc}" "${cyclonedds_xsd}" "${options_md}")
endif()
if(BUILD_DOCS)
@ -39,7 +35,7 @@ if(BUILD_DOCS)
BREATHE_PROJECTS ddsc_api_docs
BUILDER html
SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/manual")
add_dependencies(docs options_doc)
add_dependencies(docs schema)
install(
DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/docs"

View file

@ -1695,4 +1695,4 @@ While none prevents any message from being written to a DDSI2 log file.
The categorisation of tracing output is incomplete and hence most of the verbosity levels and categories are not of much use in the current release. This is an ongoing process and here we describe the target situation rather than the current situation. Currently, the most useful verbosity levels are config, fine and finest.
The default value is: "none".
The default value is: "none".

View file

@ -101,7 +101,7 @@ CycloneDDS configuration""" ] ]
text
}
}*
}?
}*
& [ a:documentation [ xml:lang="en" """
<p>This element statically configures an addresses for discovery.</p>""" ] ]
element Peer {
@ -983,7 +983,7 @@ MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==<br>
}?
}?
}?
}*
}?
& [ a:documentation [ xml:lang="en" """
<p>The Sizing element specifies a variety of configuration settings dealing with expected system sizes, buffer sizes, &c.</p>""" ] ]
element Sizing {
@ -1180,4 +1180,4 @@ MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==<br>
duration = xsd:token { pattern = "0|(\d+(\.\d*)?([Ee][\-+]?\d+)?|\.\d+([Ee][\-+]?\d+)?) *([num]?s|min|hr|day)" }
duration_inf = xsd:token { pattern = "inf|0|(\d+(\.\d*)?([Ee][\-+]?\d+)?|\.\d+([Ee][\-+]?\d+)?) *([num]?s|min|hr|day)" }
memsize = xsd:token { pattern = "0|(\d+(\.\d*)?([Ee][\-+]?\d+)?|\.\d+([Ee][\-+]?\d+)?) *([kMG]i?)?B" }
}
}

View file

@ -17,17 +17,17 @@ CycloneDDS configuration</xs:documentation>
&lt;p&gt;The General element specifying Domain related settings.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0">
<xs:element ref="config:Compatibility"/>
<xs:element ref="config:Discovery"/>
<xs:element ref="config:General"/>
<xs:element ref="config:Internal"/>
<xs:element ref="config:Partitioning"/>
<xs:element ref="config:SSL"/>
<xs:element maxOccurs="unbounded" ref="config:Security"/>
<xs:element ref="config:Sizing"/>
<xs:element ref="config:TCP"/>
<xs:element ref="config:ThreadPool"/>
<xs:all>
<xs:element minOccurs="0" ref="config:Compatibility"/>
<xs:element minOccurs="0" ref="config:Discovery"/>
<xs:element minOccurs="0" ref="config:General"/>
<xs:element minOccurs="0" ref="config:Internal"/>
<xs:element minOccurs="0" ref="config:Partitioning"/>
<xs:element minOccurs="0" ref="config:SSL"/>
<xs:element minOccurs="0" ref="config:Security"/>
<xs:element minOccurs="0" ref="config:Sizing"/>
<xs:element minOccurs="0" ref="config:TCP"/>
<xs:element minOccurs="0" ref="config:ThreadPool"/>
<xs:element minOccurs="0" name="Threads">
<xs:annotation>
<xs:documentation>
@ -39,8 +39,8 @@ CycloneDDS configuration</xs:documentation>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element ref="config:Tracing"/>
</xs:choice>
<xs:element minOccurs="0" ref="config:Tracing"/>
</xs:all>
<xs:attribute name="Id">
<xs:annotation>
<xs:documentation>
@ -179,9 +179,9 @@ CycloneDDS configuration</xs:documentation>
&lt;p&gt;This element statically configures addresses for discovery.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="config:Group"/>
<xs:element maxOccurs="unbounded" ref="config:Peer"/>
<xs:element ref="config:Peer"/>
</xs:choice>
</xs:complexType>
</xs:element>
@ -1779,4 +1779,4 @@ MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==&lt;br&gt;
<xs:pattern value="0|(\d+(\.\d*)?([Ee][\-+]?\d+)?|\.\d+([Ee][\-+]?\d+)?) *([kMG]i?)?B"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
</xs:schema>

View file

@ -1626,7 +1626,9 @@ static struct cfgelem discovery_peers_cfgelems[] = {
"<p>This element statically configures a fault tolerant group of "
"addresses for discovery. Each member of the group is tried in "
"sequence until one succeeds.</p>"
)),
),
MAXIMUM(0)), /* Group element can occur more than once, but 1 is required
because of the way its processed (for now) */
END_MARKER
};
@ -1849,7 +1851,9 @@ static struct cfgelem domain_cfgelems[] = {
DESCRIPTION(
"<p>This element is used to configure Cyclone DDS with the DDS Security "
"specification plugins and settings.</p>"
)),
),
MAXIMUM(1)), /* Security must occur at most once, but INT_MAX is required
because of the way its processed (for now) */
#endif
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
GROUP("Partitioning", partitioning_cfgelems, NULL, 1,

View file

@ -230,6 +230,8 @@ DI(if_omg_security);
#define RANGE(...) /* drop */
#define UNIT(...) /* drop */
#define VALUES(...) /* drop */
#define MAXIMUM(...) /* drop */
#define MINIMUM(...) /* drop */
#define NOMEMBER 0, 0
#define NOFUNCTIONS 0, 0, 0, 0
@ -269,6 +271,12 @@ static const struct cfgelem root_cfgelem = {
#undef MEMBER
#undef MEMBEROF
#undef FUNCTIONS
#undef DESCRIPTION
#undef RANGE
#undef UNIT
#undef VALUES
#undef MAXIMUM
#undef MINIMUM
#undef NOMEMBER
#undef NOFUNCTIONS
#undef NODATA

View file

@ -50,10 +50,12 @@
#define RANGE(str) .range = str
#define UNIT(str) .unit = str
#define VALUES(...) .values = (const char *[]){ __VA_ARGS__, NULL }
#define MAXIMUM(num) .force_maximum = 1, .maximum = num
#define MINIMUM(num) .force_minimum = 1, .minimum = num
#define NOMEMBER /* drop */
#define NOFUNCTIONS /* drop */
#define NOMETADATA { NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL }
#define NOMETADATA { NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
#define END_MARKER { NULL, NULL, NULL, 0, NULL, NULL, NOMETADATA }
#define ELEMENT(name, elems, attrs, multip, dflt, desc, ...) \
@ -76,8 +78,8 @@
EXPAND(ELEMENT, (name, NULL, attrs, multip, dflt, desc, .type = "string", __VA_ARGS__))
#define LIST(name, attrs, multip, dflt, ofst, funcs, desc, ...) \
EXPAND(ELEMENT, (name, NULL, attrs, multip, dflt, desc, .type = "list", __VA_ARGS__))
#define GROUP(name, elems, attrs, multip, ofst, funcs, desc) \
EXPAND(ELEMENT, (name, elems, attrs, multip, NULL, desc, .type = "group"))
#define GROUP(name, elems, attrs, multip, ofst, funcs, desc, ...) \
EXPAND(ELEMENT, (name, elems, attrs, multip, NULL, desc, .type = "group", __VA_ARGS__))
#include "dds/ddsi/ddsi_cfgelems.h"
/* undefine element macros */
@ -89,6 +91,8 @@
#undef RANGE
#undef UNIT
#undef VALUES
#undef MAXIMUM
#undef MINIMUM
#undef NOMEMBER
#undef NOFUNCTIONS
#undef NOMETADATA
@ -228,27 +232,35 @@ int islist(const struct cfgelem *elem)
int minimum(const struct cfgelem *elem)
{
switch (elem->multiplicity) {
case 0: /* special case, treat as-if 1 */
case 1: /* required if there is no default */
if (isgroup(elem))
if (elem->meta.force_minimum) {
return elem->meta.minimum;
} else {
switch (elem->multiplicity) {
case 0: /* special case, treat as-if 1 */
case 1: /* required if there is no default */
if (isgroup(elem))
return 0;
return (!elem->value);
default:
return 0;
return (!elem->value);
default:
return 0;
}
}
}
int maximum(const struct cfgelem *elem)
{
switch (elem->multiplicity) {
case INT_MAX:
return 0;
case 0:
case 1:
return 1;
default:
return elem->multiplicity;
if (elem->meta.force_maximum) {
return elem->meta.maximum;
} else {
switch (elem->multiplicity) {
case INT_MAX:
return 0;
case 0:
case 1:
return 1;
default:
return elem->multiplicity;
}
}
}

View file

@ -31,6 +31,8 @@ struct cfgmeta {
char *pattern;
char *description;
unsigned int flags;
const int force_maximum, maximum;
const int force_minimum, minimum;
const char *type;
const char *unit;
const char *range;

View file

@ -103,32 +103,32 @@ static void printtype(
(void)units;
assert(!isgroup(elem));
if (isbool(elem)) {
fprintf(out, "Boolean\n");
fputs("Boolean\n", out);
} else if (islist(elem)) {
assert(elem->meta.values);
fprintf(out, "One of:\n");
fputs("One of:\n", out);
if (elem->value && strlen(elem->value))
fprintf(out, "* Keyword: %s\n", elem->value);
fprintf(out, "* Comma-separated list of: ");
fputs("* Comma-separated list of: ", out);
for (const char **v = elem->meta.values; *v; v++) {
fprintf(out, "%s%s", v == elem->meta.values ? "" : ", ", *v);
}
fprintf(out, "\n");
fputs("\n", out);
if (!elem->value || !strlen(elem->value))
fprintf(out, "* Or empty\n");
fputs("* Or empty\n", out);
} else if (isenum(elem)) {
assert(elem->meta.values);
fprintf(out, "One of: ");
fputs("One of: ", out);
for (const char **v = elem->meta.values; *v; v++) {
fprintf(out, "%s%s", v == elem->meta.values ? "" : ", ", *v);
}
fprintf(out, "\n");
fputs("\n", out);
} else if (isint(elem)) {
fprintf(out, "Integer\n");
fputs("Integer\n", out);
} else if (elem->meta.unit) {
fprintf(out, "Number-with-unit\n");
fputs("Number-with-unit\n", out);
} else if (isstring(elem)) {
fprintf(out, "Text\n");
fputs("Text\n", out);
}
}
@ -142,12 +142,14 @@ static void printattr(
const struct cfgunit *units)
{
if (flags & FLAG_LF)
fputs("\n\n\n", out);
fputs("\n\n", out);
printhead(out, level, flags, elem, units);
printtype(out, level, flags, elem, units);
fputs("\n", out);
if (elem->description)
if (elem->description) {
fputs(elem->meta.description, out);
fputs("\n", out);
}
}
static void printelem(
@ -158,7 +160,7 @@ static void printelem(
const struct cfgunit *units)
{
if (flags & FLAG_LF)
fprintf(out, "\n\n\n");
fputs("\n\n", out);
printhead(out, level, flags, elem, units);
flags &= ~FLAG_LF;
if (hasattributes(elem)) {
@ -176,7 +178,7 @@ static void printelem(
ce = nextelem(elem->attributes, ce);
}
if (cnt != 0) {
fprintf(out, "\n");
fputs("\n", out);
flags |= FLAG_LF;
}
}
@ -190,18 +192,19 @@ static void printelem(
sep = ", ";
ce = nextelem(elem->children, ce);
}
fprintf(out, "\n");
fputs("\n", out);
flags |= FLAG_LF;
} else if (!isgroup(elem)) {
if (flags & FLAG_LF)
fprintf(out, "\n");
fputs("\n", out);
printtype(out, level+1, flags, elem, units);
flags |= FLAG_LF;
}
if (elem->description) {
if (flags & FLAG_LF)
fprintf(out, "\n");
fputs("\n", out);
fputs(elem->meta.description, out);
fputs("\n", out);
}
if (hasattributes(elem)) {
struct cfgelem *ce = firstelem(elem->attributes);

View file

@ -158,6 +158,6 @@ int printrnc(FILE *out, struct cfgelem *elem, const struct cfgunit *units)
static const char *fmt = " %s = xsd:token { pattern = \"%s\" }\n";
print(out, 0, fmt, cu->name, cu->pattern);
}
print(out, 0, "}");
print(out, 0, "}\n");
return 0;
}

View file

@ -165,7 +165,7 @@ printref(
snprintf(minattr, sizeof(minattr), "minOccurs=\"%d\" ", minimum(elem));
if (!(flags & FLAG_NOMAX) && maximum(elem) == 0)
snprintf(maxattr, sizeof(maxattr), "maxOccurs=\"unbounded\" ");
else if (!(FLAG_NOMAX) && maximum(elem) != 1)
else if (!(flags & FLAG_NOMAX) && maximum(elem) != 1)
snprintf(maxattr, sizeof(maxattr), "maxOccurs=\"%d\" ", maximum(elem));
print(out, cols, fmt, minattr, maxattr, schema(), name(elem));
}
@ -185,11 +185,11 @@ printcomplextype(
assert(!ismoved(elem) && !isdeprecated(elem));
if (flags & FLAG_REFERENCE) {
if (minimum(elem) != 1)
if (!(flags & FLAG_NOMIN) && minimum(elem) != 1)
snprintf(minattr, sizeof(minattr), "minOccurs=\"%d\" ", minimum(elem));
if (maximum(elem) == 0)
if (!(flags & FLAG_NOMAX) && maximum(elem) == 0)
snprintf(maxattr, sizeof(maxattr), "maxOccurs=\"unbounded\" ");
else if (maximum(elem) != 1)
else if (!(flags & FLAG_NOMAX) && maximum(elem) != 1)
snprintf(maxattr, sizeof(maxattr), "maxOccurs=\"%d\" ", maximum(elem));
}
@ -208,58 +208,63 @@ printcomplextype(
if ((cnt = haschildren(elem))) {
const char *cont = NULL;
struct cfgelem *ce;
int min[2], max[2], eq[2] = { 1, 1 };
int min[3], max[3];
int mineq, maxeq;
assert(isgroup(elem));
minattr[0] = '\0';
maxattr[0] = '\0';
if (cnt == 1) {
/* minOccurs and maxOccurs placed in element */
cont = "sequence";
} else {
assert(cnt > 1);
ce = firstelem(elem->children);
assert(ce);
min[0] = min[1] = minimum(ce);
max[0] = max[1] = maximum(ce);
min[0] = min[1] = min[2] = minimum(ce);
max[0] = max[1] = max[2] = maximum(ce);
assert(min[1] <= max[1] || max[1] == 0);
mineq = maxeq = 1;
ce = nextelem(elem->children, ce);
assert(ce);
while (ce) {
min[1] = minimum(ce);
max[1] = maximum(ce);
assert(min[1] <= max[1] || max[1] == 0);
min[2] += minimum(ce);
max[2] += maximum(ce);
if (min[1] != min[0]) {
eq[0] = 0;
if (min[1] < min[0])
mineq = 0;
if (min[1] > min[0])
min[0] = min[1];
}
if (max[1] != max[0]) {
eq[1] = 0;
maxeq = 0;
if ((max[0] != 0 && max[1] > max[0]) || max[1] == 0)
max[0] = max[1];
}
ce = nextelem(elem->children, ce);
}
if (min[0] > 1 || max[0] != 1 /* unbounded or >1 */) {
cont = "choice";
if (eq[0]) {
if (min[0] != 1)
snprintf(minattr, sizeof(minattr), " minOccurs=\"%d\"", min[0]);
flags |= FLAG_NOMIN;
}
if (eq[1]) {
if (max[0] == 0)
snprintf(maxattr, sizeof(maxattr), " maxOccurs=\"unbounded\"");
else if (max[0] != 1)
snprintf(maxattr, sizeof(maxattr), " maxOccurs=\"%d\"", max[0]);
flags |= FLAG_NOMAX;
}
} else {
/* xsd generation becomes significantly more difficult if the minimum
number of occurences for an element is more non-zero and the
maximum number of occurences of it (or one of its siblings) is more
than one, but that is not likely to occur */
if (min[0] <= 1 && max[0] == 1) {
/* any order, each zero or one time */
/* minOccurs placed in element maxOccurs always one */
cont = "all";
} else {
cont = "choice";
if (min[0] == 0)
snprintf(minattr, sizeof(minattr), " minOccurs=\"0\"");
else if (min[0] != 1) /* incorrect, but make the most of it */
snprintf(minattr, sizeof(minattr), " minOccurs=\"%d\"", min[2]);
if (max[0] == 0)
snprintf(maxattr, sizeof(maxattr), " maxOccurs=\"unbounded\"");
else if (max[0] != 1)
snprintf(maxattr, sizeof(maxattr), " maxOccurs=\"%d\"", max[2]);
if (mineq)
flags |= FLAG_NOMIN;
if (maxeq)
flags |= FLAG_NOMAX;
}
}
@ -270,7 +275,6 @@ printcomplextype(
ce = nextelem(elem->children, ce);
}
print(out, cols+4, "</xs:%s>\n", cont);
flags &= ~(FLAG_NOMIN | FLAG_NOMAX);
} else if (!isgroup(elem) && (!isstring(elem) || elem->meta.unit)) {
ofst = 4;
print(out, cols+4, "<xs:simpleContent>\n");
@ -288,6 +292,7 @@ printcomplextype(
print(out, cols+6, extfmt, "xs", isbuiltintype(elem));
}
}
flags &= ~(FLAG_NOMIN | FLAG_NOMAX);
if (hasattributes(elem)) {
struct cfgelem *ce;
ce = firstelem(elem->attributes);
@ -417,6 +422,6 @@ int printxsd(FILE *out, struct cfgelem *elem, const struct cfgunit *units)
print(out, 4, "</xs:restriction>\n");
print(out, 2, "</xs:simpleType>\n");
}
print(out, 0, "</xs:schema>");
print(out, 0, "</xs:schema>\n");
return 0;
}