#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "_confgen.h"
#include "dds/ddsrt/heap.h"
static const char *xlatmd(const char *str, const char **end)
{
static struct { const char *search; const char *replace; } tr[] = {
{ "<p>", "" }, { "</p>", "" },
{ "<b>", "" }, { "</b>", "" },
{ "<i>", "" }, { "</i>", "" },
{ "<li>", " * " }, { "</li>", "\n" },
{ "<ul>", "" }, { "</ul>", "\n" },
{ "<sup>", "^" }, { "</sup>", "" },
{ "<code>", "``" }, { "</code>", "``" },
{ "<empty>", "<empty>" },
{ "*", "\\*" }, { "_", "\\_" },
{ NULL, NULL }
};
if (strncmp(str, "</p>", 4) == 0) {
const char *ptr = str + 4;
while (*ptr == '\n' || *ptr == ' ') ptr++;
if (strncmp(ptr, "<p>", 3) == 0) {
*end = ptr;
return "\n\n";
}
}
for (size_t cnt = 0; tr[cnt].search; cnt++) {
size_t len = strlen(tr[cnt].search);
if (strncmp(str, tr[cnt].search, len) == 0) {
*end = str + len;
return tr[cnt].replace;
}
}
return NULL;
}
static char headerchars[] = {'#', '*', '=', '-', '^', '"', '_', '+', ':', '~'};
static void printhead(
FILE *out,
unsigned int level,
unsigned int flags,
struct cfgelem *elem,
const struct cfgunit *units)
{
(void)level;
(void)flags;
(void)units;
assert(level < (sizeof(headerchars)));
fprintf(out, ".. _`%s`:\n\n%s\n", elem->meta.title, elem->meta.title);
for(size_t i = strlen(elem->meta.title); i > 0; --i)
fputc(headerchars[level], out);
fputs("\n\n", out);
}
static void printlink(
FILE *out,
unsigned int level,
unsigned int flags,
struct cfgelem *elem,
const struct cfgunit *units)
{
(void)level;
(void)flags;
(void)units;
assert(elem->meta.title);
fprintf(out, ":ref:`%s<%s>`", elem->name, elem->meta.title);
}
static void printtype(
FILE *out,
unsigned int level,
unsigned int flags,
struct cfgelem *elem,
const struct cfgunit *units)
{
(void)level;
(void)flags;
(void)units;
assert(!isgroup(elem));
if (isbool(elem)) {
fputs("Boolean\n", out);
} else if (islist(elem)) {
assert(elem->meta.values);
fputs("One of:\n", out);
if (elem->value && strlen(elem->value))
fprintf(out, "* Keyword: %s\n", elem->value);
fputs("* Comma-separated list of: ", out);
for (const char **v = elem->meta.values; *v; v++) {
fprintf(out, "%s%s", v == elem->meta.values ? "" : ", ", *v);
}
fputs("\n", out);
if (!elem->value || !strlen(elem->value))
fputs("* Or empty\n", out);
} else if (isenum(elem)) {
assert(elem->meta.values);
fputs("One of: ", out);
for (const char **v = elem->meta.values; *v; v++) {
fprintf(out, "%s%s", v == elem->meta.values ? "" : ", ", *v);
}
fputs("\n", out);
} else if (isint(elem)) {
fputs("Integer\n", out);
} else if (elem->meta.unit) {
fputs("Number-with-unit\n", out);
} else if (isstring(elem)) {
fputs("Text\n", out);
}
}
#define FLAG_LF (1u<<0)
static void printattr(
FILE *out,
unsigned int level,
unsigned int flags,
struct cfgelem *elem,
const struct cfgunit *units)
{
if (flags & FLAG_LF)
fputs("\n\n", out);
printhead(out, level, flags, elem, units);
printtype(out, level, flags, elem, units);
fputs("\n", out);
if (elem->description) {
fputs(elem->meta.description, out);
fputs("\n", out);
}
}
static void printelem(
FILE *out,
unsigned int level,
unsigned int flags,
struct cfgelem *elem,
const struct cfgunit *units)
{
if (flags & FLAG_LF)
fputs("\n\n", out);
printhead(out, level, flags, elem, units);
flags &= ~FLAG_LF;
if (hasattributes(elem)) {
int cnt = 0;
const char *sep = "Attributes: ";
struct cfgelem *ce = firstelem(elem->attributes);
while (ce) {
if (!isnop(ce)) {
fputs(sep, out);
printlink(out, level, flags, ce, units);
sep = ", ";
cnt++;
}
ce = nextelem(elem->attributes, ce);
}
if (cnt != 0) {
fputs("\n", out);
flags |= FLAG_LF;
}
}
if (haschildren(elem)) {
const char *sep = "Children: ";
struct cfgelem *ce = firstelem(elem->children);
while (ce) {
fputs(sep, out);
printlink(out, level, flags, ce, units);
sep = ", ";
ce = nextelem(elem->children, ce);
}
fputs("\n", out);
flags |= FLAG_LF;
} else if (!isgroup(elem)) {
if (flags & FLAG_LF)
fputs("\n", out);
printtype(out, level+1, flags, elem, units);
flags |= FLAG_LF;
}
if (elem->description) {
if (flags & FLAG_LF)
fputs("\n", out);
fputs(elem->meta.description, out);
fputs("\n", out);
}
if (hasattributes(elem)) {
struct cfgelem *ce = firstelem(elem->attributes);
while (ce) {
if (!isnop(ce))
printattr(out, level, flags, ce, units);
ce = nextelem(elem->attributes, ce);
}
}
if (isgroup(elem)) {
struct cfgelem *ce = firstelem(elem->children);
while (ce) {
printelem(out, level+1, flags, ce, units);
ce = nextelem(elem->children, ce);
}
}
}
static int maketitles(
struct cfgelem *elem, int attr, const char *path, size_t pathlen)
{
char *str;
size_t namelen = 0, len = 0;
struct cfgelem *ce;
if (ismoved(elem) || isdeprecated(elem) || elem->meta.title)
return 0;
namelen = strlen(name(elem));
if (!(str = ddsrt_malloc(pathlen + namelen + (attr ? 4 : 2))))
return -1;
memcpy(str, path, pathlen);
len += pathlen;
if (attr) {
str[len++] = '[';
str[len++] = '@';
} else {
str[len++] = '/';
}
memcpy(str+len, name(elem), namelen);
len += namelen;
if (attr) {
str[len++] = ']';
}
str[len] = '\0';
elem->meta.title = str;
ce = firstelem(elem->children);
while (ce) {
if (maketitles(ce, 0, str, len) == -1)
return -1;
ce = nextelem(elem->children, ce);
}
ce = firstelem(elem->attributes);
while (ce) {
if (maketitles(ce, 1, str, len) == -1)
return -1;
ce = nextelem(elem->attributes, ce);
}
return 0;
}
static int initrst(struct cfgelem *elem, const struct cfgunit *units)
{
if (ismoved(elem) || isdeprecated(elem))
return 0;
if (makedescription(elem, units, xlatmd) == -1)
return -1;
for (struct cfgelem *ce = elem->children; ce && ce->name; ce++) {
if (initrst(ce, units) == -1)
return -1;
}
for (struct cfgelem *ce = elem->attributes; ce && ce->name; ce++) {
if (initrst(ce, units) == - 1)
return -1;
}
return 0;
}
int printrst(FILE *out, struct cfgelem *elem, const struct cfgunit *units)
{
if (initrst(elem, units) == -1)
return -1;
if (maketitles(elem, 0, "/", 1) == -1)
return -1;
fputs(
".. _`configuration_reference`:\n\n"
"****************************\n"
"Configuration File Reference\n"
"****************************\n\n"
"Below is the full (generated) reference of XML you can use to configure |var-project|. "
"The title of each section is the XML XPath notation to the relevant option.\n\n", out);
printelem(out, 0u, 0u, elem, units);
return 0;
}