node */
*node, /* Current node */
*next; /* Next node */
#if DEBUG > 1
mxml_node_t *temp; /* Temporary node */
int oldstate, /* Previous state */
oldch; /* Old character */
static const char *states[] = /* State strings */
{
"STATE_NONE",
"STATE_PREPROCESSOR",
"STATE_C_COMMENT",
"STATE_CXX_COMMENT",
"STATE_STRING",
"STATE_CHARACTER",
"STATE_IDENTIFIER"
};
#endif /* DEBUG > 1 */
#ifdef DEBUG
fprintf(stderr, "scan_file(filename=\"%s\", fp=%p, tree=%p)\n", filename,
fp, tree);
#endif /* DEBUG */
/*
* Initialize the finite state machine...
*/
state = STATE_NONE;
braces = 0;
parens = 0;
bufptr = buffer;
comment = mxmlNewElement(MXML_NO_PARENT, "temp");
constant = NULL;
enumeration = NULL;
function = NULL;
variable = NULL;
returnvalue = NULL;
type = NULL;
description = NULL;
typedefnode = NULL;
structclass = NULL;
fstructclass = NULL;
if (!strcmp(tree->value.element.name, "class"))
scope = "private";
else
scope = NULL;
/*
* Read until end-of-file...
*/
while ((ch = getc(fp)) != EOF)
{
#if DEBUG > 1
oldstate = state;
oldch = ch;
#endif /* DEBUG > 1 */
switch (state)
{
case STATE_NONE : /* No state - whitespace, etc. */
switch (ch)
{
case '/' : /* Possible C/C++ comment */
ch = getc(fp);
bufptr = buffer;
if (ch == '*')
state = STATE_C_COMMENT;
else if (ch == '/')
state = STATE_CXX_COMMENT;
else
{
ungetc(ch, fp);
if (type)
{
#ifdef DEBUG
fputs("Identifier: <<<< / >>>\n", stderr);
#endif /* DEBUG */
ch = type->last_child->value.text.string[0];
mxmlNewText(type, isalnum(ch) || ch == '_', "/");
}
}
break;
case '#' : /* Preprocessor */
#ifdef DEBUG
fputs(" #preprocessor...\n", stderr);
#endif /* DEBUG */
state = STATE_PREPROCESSOR;
break;
case '\'' : /* Character constant */
state = STATE_CHARACTER;
bufptr = buffer;
*bufptr++ = ch;
break;
case '\"' : /* String constant */
state = STATE_STRING;
bufptr = buffer;
*bufptr++ = ch;
break;
case '{' :
#ifdef DEBUG
fprintf(stderr, " open brace, function=%p, type=%p...\n",
function, type);
if (type)
fprintf(stderr, " type->child=\"%s\"...\n",
type->child->value.text.string);
#endif /* DEBUG */
if (function)
{
if (fstructclass)
{
sort_node(fstructclass, function);
fstructclass = NULL;
}
else
sort_node(tree, function);
function = NULL;
}
else if (type && type->child &&
((!strcmp(type->child->value.text.string, "typedef") &&
type->child->next &&
(!strcmp(type->child->next->value.text.string, "struct") ||
!strcmp(type->child->next->value.text.string, "union") ||
!strcmp(type->child->next->value.text.string, "class"))) ||
!strcmp(type->child->value.text.string, "union") ||
!strcmp(type->child->value.text.string, "struct") ||
!strcmp(type->child->value.text.string, "class")))
{
/*
* Start of a class or structure...
*/
if (!strcmp(type->child->value.text.string, "typedef"))
{
#ifdef DEBUG
fputs(" starting typedef...\n", stderr);
#endif /* DEBUG */
typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef");
mxmlDelete(type->child);
}
else
typedefnode = NULL;
structclass = mxmlNewElement(MXML_NO_PARENT,
type->child->value.text.string);
#ifdef DEBUG
fprintf(stderr, "%c%s: <<<< %s >>>\n",
toupper(type->child->value.text.string[0]),
type->child->value.text.string + 1,
type->child->next ?
type->child->next->value.text.string : "(noname)");
fputs(" type =", stderr);
for (node = type->child; node; node = node->next)
fprintf(stderr, " \"%s\"", node->value.text.string);
putc('\n', stderr);
fprintf(stderr, " scope = %s\n", scope ? scope : "(null)");
#endif /* DEBUG */
if (type->child->next)
{
mxmlElementSetAttr(structclass, "name",
type->child->next->value.text.string);
sort_node(tree, structclass);
}
if (typedefnode && type->child)
type->child->value.text.whitespace = 0;
else if (structclass && type->child &&
type->child->next && type->child->next->next)
{
for (bufptr = buffer, node = type->child->next->next;
node;
bufptr += strlen(bufptr))
{
if (node->value.text.whitespace && bufptr > buffer)
*bufptr++ = ' ';
strcpy(bufptr, node->value.text.string);
next = node->next;
mxmlDelete(node);
node = next;
}
mxmlElementSetAttr(structclass, "parent", buffer);
mxmlDelete(type);
type = NULL;
}
else
{
mxmlDelete(type);
type = NULL;
}
if (typedefnode && comment->last_child)
{
/*
* Copy comment for typedef as well as class/struct/union...
*/
mxmlNewText(comment, 0,
comment->last_child->value.text.string);
description = mxmlNewElement(typedefnode, "description");
#ifdef DEBUG
fputs(" duplicating comment for typedef...\n", stderr);
#endif /* DEBUG */
update_comment(typedefnode, comment->last_child);
mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
comment->last_child);
}
description = mxmlNewElement(structclass, "description");
#ifdef DEBUG
fprintf(stderr, " adding comment to %s...\n",
structclass->value.element.name);
#endif /* DEBUG */
update_comment(structclass, comment->last_child);
mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
comment->last_child);
if (scan_file(filename, fp, structclass))
{
mxmlDelete(comment);
return (-1);
}
#ifdef DEBUG
fputs(" ended typedef...\n", stderr);
#endif /* DEBUG */
structclass = NULL;
break;
}
else if (type && type->child && type->child->next &&
(!strcmp(type->child->value.text.string, "enum") ||
(!strcmp(type->child->value.text.string, "typedef") &&
!strcmp(type->child->next->value.text.string, "enum"))))
{
/*
* Enumeration type...
*/
if (!strcmp(type->child->value.text.string, "typedef"))
{
#ifdef DEBUG
fputs(" starting typedef...\n", stderr);
#endif /* DEBUG */
typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef");
mxmlDelete(type->child);
}
else
typedefnode = NULL;
enumeration = mxmlNewElement(MXML_NO_PARENT, "enumeration");
#ifdef DEBUG
fprintf(stderr, "Enumeration: <<<< %s >>>\n",
type->child->next ?
type->child->next->value.text.string : "(noname)");
#endif /* DEBUG */
if (type->child->next)
{
mxmlElementSetAttr(enumeration, "name",
type->child->next->value.text.string);
sort_node(tree, enumeration);
}
if (typedefnode && type->child)
type->child->value.text.whitespace = 0;
else
{
mxmlDelete(type);
type = NULL;
}
if (typedefnode && comment->last_child)
{
/*
* Copy comment for typedef as well as class/struct/union...
*/
mxmlNewText(comment, 0,
comment->last_child->value.text.string);
description = mxmlNewElement(typedefnode, "description");
#ifdef DEBUG
fputs(" duplicating comment for typedef...\n", stderr);
#endif /* DEBUG */
update_comment(typedefnode, comment->last_child);
mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
comment->last_child);
}
description = mxmlNewElement(enumeration, "description");
#ifdef DEBUG
fputs(" adding comment to enumeration...\n", stderr);
#endif /* DEBUG */
update_comment(enumeration, comment->last_child);
mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
comment->last_child);
}
else if (type && type->child &&
!strcmp(type->child->value.text.string, "extern"))
{
if (scan_file(filename, fp, tree))
{
mxmlDelete(comment);
return (-1);
}
}
else if (type)
{
mxmlDelete(type);
type = NULL;
}
braces ++;
function = NULL;
variable = NULL;
break;
case '}' :
#ifdef DEBUG
fputs(" close brace...\n", stderr);
#endif /* DEBUG */
if (structclass)
scope = NULL;
enumeration = NULL;
constant = NULL;
structclass = NULL;
if (braces > 0)
braces --;
else
{
mxmlDelete(comment);
return (0);
}
break;
case '(' :
if (type)
{
#ifdef DEBUG
fputs("Identifier: <<<< ( >>>\n", stderr);
#endif /* DEBUG */
mxmlNewText(type, 0, "(");
}
parens ++;
break;
case ')' :
if (type && parens)
{
#ifdef DEBUG
fputs("Identifier: <<<< ) >>>\n", stderr);
#endif /* DEBUG */
mxmlNewText(type, 0, ")");
}
if (function && type && !parens)
{
/*
* Check for "void" argument...
*/
if (type->child && type->child->next)
variable = add_variable(function, "argument", type);
else
mxmlDelete(type);
type = NULL;
}
if (parens > 0)
parens --;
break;
case ';' :
#ifdef DEBUG
fputs("Identifier: <<<< ; >>>\n", stderr);
fprintf(stderr, " function=%p, type=%p\n", function, type);
#endif /* DEBUG */
if (function)
{
if (!strcmp(tree->value.element.name, "class"))
{
#ifdef DEBUG
fputs(" ADDING FUNCTION TO CLASS\n", stderr);
#endif /* DEBUG */
sort_node(tree, function);
}
else
mxmlDelete(function);
function = NULL;
variable = NULL;
}
if (type)
{
/*
* See if we have a function typedef...
*/
if (type->child &&
!strcmp(type->child->value.text.string, "typedef"))
{
/*
* Yes, add it!
*/
typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef");
for (node = type->child->next; node; node = node->next)
if (!strcmp(node->value.text.string, "("))
break;
for (node = node->next; node; node = node->next)
if (strcmp(node->value.text.string, "*"))
break;
if (node)
{
mxmlElementSetAttr(typedefnode, "name",
node->value.text.string);
sort_node(tree, typedefnode);
mxmlDelete(type->child);
mxmlDelete(node);
if (type->child)
type->child->value.text.whitespace = 0;
mxmlAdd(typedefnode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
type);
type = NULL;
break;
}
}
mxmlDelete(type);
type = NULL;
}
break;
case ':' :
if (type)
{
#ifdef DEBUG
fputs("Identifier: <<<< : >>>\n", stderr);
#endif /* DEBUG */
mxmlNewText(type, 1, ":");
}
break;
case '*' :
if (type)
{
#ifdef DEBUG
fputs("Identifier: <<<< * >>>\n", stderr);
#endif /* DEBUG */
ch = type->last_child->value.text.string[0];
mxmlNewText(type, isalnum(ch) || ch == '_', "*");
}
break;
case ',' :
if (type && !enumeration)
{
#ifdef DEBUG
fputs("Identifier: <<<< , >>>\n", stderr);
#endif /* DEBUG */
ch = type->last_child->value.text.string[0];
mxmlNewText(type, 0, ",");
}
break;
case '&' :
if (type)
{
#ifdef DEBUG
fputs("Identifier: <<<< & >>>\n", stderr);
#endif /* DEBUG */
mxmlNewText(type, 1, "&");
}
break;
case '+' :
if (type)
{
#ifdef DEBUG
fputs("Identifier: <<<< + >>>\n", stderr);
#endif /* DEBUG */
ch = type->last_child->value.text.string[0];
mxmlNewText(type, isalnum(ch) || ch == '_', "+");
}
break;
case '-' :
if (type)
{
#ifdef DEBUG
fputs("Identifier: <<<< - >>>\n", stderr);
#endif /* DEBUG */
ch = type->last_child->value.text.string[0];
mxmlNewText(type, isalnum(ch) || ch == '_', "-");
}
break;
case '=' :
if (type)
{
#ifdef DEBUG
fputs("Identifier: <<<< = >>>\n", stderr);
#endif /* DEBUG */
ch = type->last_child->value.text.string[0];
mxmlNewText(type, isalnum(ch) || ch == '_', "=");
}
break;
default : /* Other */
if (isalnum(ch) || ch == '_' || ch == '.' || ch == ':' || ch == '~')
{
state = STATE_IDENTIFIER;
bufptr = buffer;
*bufptr++ = ch;
}
break;
}
break;
case STATE_PREPROCESSOR : /* Preprocessor directive */
if (ch == '\n')
state = STATE_NONE;
else if (ch == '\\')
getc(fp);
break;
case STATE_C_COMMENT : /* Inside a C comment */
switch (ch)
{
case '\n' :
while ((ch = getc(fp)) != EOF)
if (ch == '*')
{
ch = getc(fp);
if (ch == '/')
{
*bufptr = '\0';
if (comment->child != comment->last_child)
{
#ifdef DEBUG
fprintf(stderr, " removing comment %p, last comment %p...\n",
comment->child, comment->last_child);
#endif /* DEBUG */
mxmlDelete(comment->child);
#ifdef DEBUG
fprintf(stderr, " new comment %p, last comment %p...\n",
comment->child, comment->last_child);
#endif /* DEBUG */
}
#ifdef DEBUG
fprintf(stderr,
" processing comment, variable=%p, "
"constant=%p, typedefnode=%p, tree=\"%s\"\n",
variable, constant, typedefnode,
tree->value.element.name);
#endif /* DEBUG */
if (variable)
{
description = mxmlNewElement(variable, "description");
#ifdef DEBUG
fputs(" adding comment to variable...\n", stderr);
#endif /* DEBUG */
update_comment(variable,
mxmlNewText(description, 0, buffer));
variable = NULL;
}
else if (constant)
{
description = mxmlNewElement(constant, "description");
#ifdef DEBUG
fputs(" adding comment to constant...\n", stderr);
#endif /* DEBUG */
update_comment(constant,
mxmlNewText(description, 0, buffer));
constant = NULL;
}
else if (typedefnode)
{
description = mxmlNewElement(typedefnode, "description");
#ifdef DEBUG
fprintf(stderr, " adding comment to typedef %s...\n",
mxmlElementGetAttr(typedefnode, "name"));
#endif /* DEBUG */
update_comment(typedefnode,
mxmlNewText(description, 0, buffer));
if (structclass)
{
description = mxmlNewElement(structclass, "description");
update_comment(structclass,
mxmlNewText(description, 0, buffer));
}
else if (enumeration)
{
description = mxmlNewElement(enumeration, "description");
update_comment(enumeration,
mxmlNewText(description, 0, buffer));
}
// typedefnode = NULL;
}
else if (strcmp(tree->value.element.name, "mxmldoc") &&
!mxmlFindElement(tree, tree, "description",
NULL, NULL, MXML_DESCEND_FIRST))
{
description = mxmlNewElement(tree, "description");
#ifdef DEBUG
fputs(" adding comment to parent...\n", stderr);
#endif /* DEBUG */
update_comment(tree,
mxmlNewText(description, 0, buffer));
}
else
{
#ifdef DEBUG
fprintf(stderr, " before adding comment, child=%p, last_child=%p\n",
comment->child, comment->last_child);
#endif /* DEBUG */
mxmlNewText(comment, 0, buffer);
#ifdef DEBUG
fprintf(stderr, " after adding comment, child=%p, last_child=%p\n",
comment->child, comment->last_child);
#endif /* DEBUG */
}
#ifdef DEBUG
fprintf(stderr, "C comment: <<<< %s >>>\n", buffer);
#endif /* DEBUG */
state = STATE_NONE;
break;
}
else
ungetc(ch, fp);
}
else if (ch == '\n' && bufptr > buffer &&
bufptr < (buffer + sizeof(buffer) - 1))
*bufptr++ = ch;
else if (!isspace(ch))
break;
if (ch != EOF)
ungetc(ch, fp);
if (bufptr > buffer && bufptr < (buffer + sizeof(buffer) - 1))
*bufptr++ = '\n';
break;
case '/' :
if (ch == '/' && bufptr > buffer && bufptr[-1] == '*')
{
while (bufptr > buffer &&
(bufptr[-1] == '*' || isspace(bufptr[-1] & 255)))
bufptr --;
*bufptr = '\0';
if (comment->child != comment->last_child)
{
#ifdef DEBUG
fprintf(stderr, " removing comment %p, last comment %p...\n",
comment->child, comment->last_child);
#endif /* DEBUG */
mxmlDelete(comment->child);
#ifdef DEBUG
fprintf(stderr, " new comment %p, last comment %p...\n",
comment->child, comment->last_child);
#endif /* DEBUG */
}
#ifdef DEBUG
fprintf(stderr,
" processing comment, variable=%p, "
"constant=%p, typedefnode=%p, tree=\"%s\"\n",
variable, constant, typedefnode,
tree->value.element.name);
#endif /* DEBUG */
if (variable)
{
description = mxmlNewElement(variable, "description");
#ifdef DEBUG
fputs(" adding comment to variable...\n", stderr);
#endif /* DEBUG */
update_comment(variable,
mxmlNewText(description, 0, buffer));
variable = NULL;
}
else if (constant)
{
description = mxmlNewElement(constant, "description");
#ifdef DEBUG
fputs(" adding comment to constant...\n", stderr);
#endif /* DEBUG */
update_comment(constant,
mxmlNewText(description, 0, buffer));
constant = NULL;
}
else if (typedefnode)
{
description = mxmlNewElement(typedefnode, "description");
#ifdef DEBUG
fprintf(stderr, " adding comment to typedef %s...\n",
mxmlElementGetAttr(typedefnode, "name"));
#endif /* DEBUG */
update_comment(typedefnode,
mxmlNewText(description, 0, buffer));
if (structclass)
{
description = mxmlNewElement(structclass, "description");
update_comment(structclass,
mxmlNewText(description, 0, buffer));
}
else if (enumeration)
{
description = mxmlNewElement(enumeration, "description");
update_comment(enumeration,
mxmlNewText(description, 0, buffer));
}
// typedefnode = NULL;
}
else if (strcmp(tree->value.element.name, "mxmldoc") &&
!mxmlFindElement(tree, tree, "description",
NULL, NULL, MXML_DESCEND_FIRST))
{
description = mxmlNewElement(tree, "description");
#ifdef DEBUG
fputs(" adding comment to parent...\n", stderr);
#endif /* DEBUG */
update_comment(tree,
mxmlNewText(description, 0, buffer));
}
else
mxmlNewText(comment, 0, buffer);
#ifdef DEBUG
fprintf(stderr, "C comment: <<<< %s >>>\n", buffer);
#endif /* DEBUG */
state = STATE_NONE;
break;
}
default :
if (ch == ' ' && bufptr == buffer)
break;
if (bufptr < (buffer + sizeof(buffer) - 1))
*bufptr++ = ch;
break;
}
break;
case STATE_CXX_COMMENT : /* Inside a C++ comment */
if (ch == '\n')
{
state = STATE_NONE;
*bufptr = '\0';
if (comment->child != comment->last_child)
{
#ifdef DEBUG
fprintf(stderr, " removing comment %p, last comment %p...\n",
comment->child, comment->last_child);
#endif /* DEBUG */
mxmlDelete(comment->child);
#ifdef DEBUG
fprintf(stderr, " new comment %p, last comment %p...\n",
comment->child, comment->last_child);
#endif /* DEBUG */
}
if (variable)
{
description = mxmlNewElement(variable, "description");
#ifdef DEBUG
fputs(" adding comment to variable...\n", stderr);
#endif /* DEBUG */
update_comment(variable,
mxmlNewText(description, 0, buffer));
variable = NULL;
}
else if (constant)
{
description = mxmlNewElement(constant, "description");
#ifdef DEBUG
fputs(" adding comment to constant...\n", stderr);
#endif /* DEBUG */
update_comment(constant,
mxmlNewText(description, 0, buffer));
constant = NULL;
}
else if (typedefnode)
{
description = mxmlNewElement(typedefnode, "description");
#ifdef DEBUG
fprintf(stderr, " adding comment to typedef %s...\n",
mxmlElementGetAttr(typedefnode, "name"));
#endif /* DEBUG */
update_comment(typedefnode,
mxmlNewText(description, 0, buffer));
if (structclass)
{
description = mxmlNewElement(structclass, "description");
update_comment(structclass,
mxmlNewText(description, 0, buffer));
}
else if (enumeration)
{
description = mxmlNewElement(enumeration, "description");
update_comment(enumeration,
mxmlNewText(description, 0, buffer));
}
}
else if (strcmp(tree->value.element.name, "mxmldoc") &&
!mxmlFindElement(tree, tree, "description",
NULL, NULL, MXML_DESCEND_FIRST))
{
description = mxmlNewElement(tree, "description");
#ifdef DEBUG
fputs(" adding comment to parent...\n", stderr);
#endif /* DEBUG */
update_comment(tree,
mxmlNewText(description, 0, buffer));
}
else
mxmlNewText(comment, 0, buffer);
#ifdef DEBUG
fprintf(stderr, "C++ comment: <<<< %s >>>\n", buffer);
#endif /* DEBUG */
}
else if (ch == ' ' && bufptr == buffer)
break;
else if (bufptr < (buffer + sizeof(buffer) - 1))
*bufptr++ = ch;
break;
case STATE_STRING : /* Inside a string constant */
*bufptr++ = ch;
if (ch == '\\')
*bufptr++ = getc(fp);
else if (ch == '\"')
{
*bufptr = '\0';
if (type)
mxmlNewText(type, type->child != NULL, buffer);
state = STATE_NONE;
}
break;
case STATE_CHARACTER : /* Inside a character constant */
*bufptr++ = ch;
if (ch == '\\')
*bufptr++ = getc(fp);
else if (ch == '\'')
{
*bufptr = '\0';
if (type)
mxmlNewText(type, type->child != NULL, buffer);
state = STATE_NONE;
}
break;
case STATE_IDENTIFIER : /* Inside a keyword or identifier */
if (isalnum(ch) || ch == '_' || ch == '[' || ch == ']' ||
(ch == ',' && (parens > 1 || (type && !enumeration && !function))) ||
ch == ':' || ch == '.' || ch == '~')
{
if (bufptr < (buffer + sizeof(buffer) - 1))
*bufptr++ = ch;
}
else
{
ungetc(ch, fp);
*bufptr = '\0';
state = STATE_NONE;
#ifdef DEBUG
fprintf(stderr, " braces=%d, type=%p, type->child=%p, buffer=\"%s\"\n",
braces, type, type ? type->child : NULL, buffer);
#endif /* DEBUG */
if (!braces)
{
if (!type || !type->child)
{
if (!strcmp(tree->value.element.name, "class"))
{
if (!strcmp(buffer, "public") ||
!strcmp(buffer, "public:"))
{
scope = "public";
#ifdef DEBUG
fputs(" scope = public\n", stderr);
#endif /* DEBUG */
break;
}
else if (!strcmp(buffer, "private") ||
!strcmp(buffer, "private:"))
{
scope = "private";
#ifdef DEBUG
fputs(" scope = private\n", stderr);
#endif /* DEBUG */
break;
}
else if (!strcmp(buffer, "protected") ||
!strcmp(buffer, "protected:"))
{
scope = "protected";
#ifdef DEBUG
fputs(" scope = protected\n", stderr);
#endif /* DEBUG */
break;
}
}
}
if (!type)
type = mxmlNewElement(MXML_NO_PARENT, "type");
#ifdef DEBUG
fprintf(stderr, " function=%p (%s), type->child=%p, ch='%c', parens=%d\n",
function,
function ? mxmlElementGetAttr(function, "name") : "null",
type->child, ch, parens);
#endif /* DEBUG */
if (!function && ch == '(')
{
if (type->child &&
!strcmp(type->child->value.text.string, "extern"))
{
/*
* Remove external declarations...
*/
mxmlDelete(type);
type = NULL;
break;
}
if (type->child &&
!strcmp(type->child->value.text.string, "static") &&
!strcmp(tree->value.element.name, "mxmldoc"))
{
/*
* Remove static functions...
*/
mxmlDelete(type);
type = NULL;
break;
}
function = mxmlNewElement(MXML_NO_PARENT, "function");
if ((bufptr = strchr(buffer, ':')) != NULL && bufptr[1] == ':')
{
*bufptr = '\0';
bufptr += 2;
if ((fstructclass =
mxmlFindElement(tree, tree, "class", "name", buffer,
MXML_DESCEND_FIRST)) == NULL)
fstructclass =
mxmlFindElement(tree, tree, "struct", "name", buffer,
MXML_DESCEND_FIRST);
}
else
bufptr = buffer;
mxmlElementSetAttr(function, "name", bufptr);
if (scope)
mxmlElementSetAttr(function, "scope", scope);
#ifdef DEBUG
fprintf(stderr, "function: %s\n", buffer);
fprintf(stderr, " scope = %s\n", scope ? scope : "(null)");
fprintf(stderr, " comment = %p\n", comment);
fprintf(stderr, " child = (%p) %s\n",
comment->child,
comment->child ?
comment->child->value.text.string : "(null)");
fprintf(stderr, " last_child = (%p) %s\n",
comment->last_child,
comment->last_child ?
comment->last_child->value.text.string : "(null)");
#endif /* DEBUG */
if (type->last_child &&
strcmp(type->last_child->value.text.string, "void"))
{
returnvalue = mxmlNewElement(function, "returnvalue");
mxmlAdd(returnvalue, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type);
description = mxmlNewElement(returnvalue, "description");
#ifdef DEBUG
fputs(" adding comment to returnvalue...\n", stderr);
#endif /* DEBUG */
update_comment(returnvalue, comment->last_child);
mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
comment->last_child);
}
else
mxmlDelete(type);
description = mxmlNewElement(function, "description");
#ifdef DEBUG
fputs(" adding comment to function...\n", stderr);
#endif /* DEBUG */
update_comment(function, comment->last_child);
mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
comment->last_child);
type = NULL;
}
else if (function && ((ch == ')' && parens == 1) || ch == ','))
{
/*
* Argument definition...
*/
if (strcmp(buffer, "void"))
{
mxmlNewText(type, type->child != NULL &&
type->last_child->value.text.string[0] != '(' &&
type->last_child->value.text.string[0] != '*',
buffer);
#ifdef DEBUG
fprintf(stderr, "Argument: <<<< %s >>>\n", buffer);
#endif /* DEBUG */
variable = add_variable(function, "argument", type);
}
else
mxmlDelete(type);
type = NULL;
}
else if (type->child && !function && (ch == ';' || ch == ','))
{
#ifdef DEBUG
fprintf(stderr, " got semicolon, typedefnode=%p, structclass=%p\n",
typedefnode, structclass);
#endif /* DEBUG */
if (typedefnode || structclass)
{
#ifdef DEBUG
fprintf(stderr, "Typedef/struct/class: <<<< %s >>>>\n", buffer);
#endif /* DEBUG */
if (typedefnode)
{
mxmlElementSetAttr(typedefnode, "name", buffer);
sort_node(tree, typedefnode);
}
if (structclass && !mxmlElementGetAttr(structclass, "name"))
{
#ifdef DEBUG
fprintf(stderr, "setting struct/class name to %s!\n",
type->last_child->value.text.string);
#endif /* DEBUG */
mxmlElementSetAttr(structclass, "name", buffer);
sort_node(tree, structclass);
structclass = NULL;
}
if (typedefnode)
mxmlAdd(typedefnode, MXML_ADD_BEFORE, MXML_ADD_TO_PARENT,
type);
else
mxmlDelete(type);
type = NULL;
typedefnode = NULL;
}
else if (type->child &&
!strcmp(type->child->value.text.string, "typedef"))
{
/*
* Simple typedef...
*/
#ifdef DEBUG
fprintf(stderr, "Typedef: <<<< %s >>>\n", buffer);
#endif /* DEBUG */
typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef");
mxmlElementSetAttr(typedefnode, "name", buffer);
mxmlDelete(type->child);
sort_node(tree, typedefnode);
if (type->child)
type->child->value.text.whitespace = 0;
mxmlAdd(typedefnode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type);
type = NULL;
}
else if (!parens)
{
/*
* Variable definition...
*/
if (type->child &&
!strcmp(type->child->value.text.string, "static") &&
!strcmp(tree->value.element.name, "mxmldoc"))
{
/*
* Remove static functions...
*/
mxmlDelete(type);
type = NULL;
break;
}
mxmlNewText(type, type->child != NULL &&
type->last_child->value.text.string[0] != '(' &&
type->last_child->value.text.string[0] != '*',
buffer);
#ifdef DEBUG
fprintf(stderr, "Variable: <<<< %s >>>>\n", buffer);
fprintf(stderr, " scope = %s\n", scope ? scope : "(null)");
#endif /* DEBUG */
variable = add_variable(MXML_NO_PARENT, "variable", type);
type = NULL;
sort_node(tree, variable);
if (scope)
mxmlElementSetAttr(variable, "scope", scope);
}
}
else
{
#ifdef DEBUG
fprintf(stderr, "Identifier: <<<< %s >>>>\n", buffer);
#endif /* DEBUG */
mxmlNewText(type, type->child != NULL &&
type->last_child->value.text.string[0] != '(' &&
type->last_child->value.text.string[0] != '*',
buffer);
}
}
else if (enumeration && !isdigit(buffer[0] & 255))
{
#ifdef DEBUG
fprintf(stderr, "Constant: <<<< %s >>>\n", buffer);
#endif /* DEBUG */
constant = mxmlNewElement(MXML_NO_PARENT, "constant");
mxmlElementSetAttr(constant, "name", buffer);
sort_node(enumeration, constant);
}
else if (type)
{
mxmlDelete(type);
type = NULL;
}
}
break;
}
#if DEBUG > 1
if (state != oldstate)
{
fprintf(stderr, " changed states from %s to %s on receipt of character '%c'...\n",
states[oldstate], states[state], oldch);
fprintf(stderr, " variable = %p\n", variable);
if (type)
{
fputs(" type =", stderr);
for (temp = type->child; temp; temp = temp->next)
fprintf(stderr, " \"%s\"", temp->value.text.string);
fputs("\n", stderr);
}
}
#endif /* DEBUG > 1 */
}
mxmlDelete(comment);
/*
* All done, return with no errors...
*/
return (0);
}
/*
* 'sort_node()' - Insert a node sorted into a tree.
*/
static void
sort_node(mxml_node_t *tree, /* I - Tree to sort into */
mxml_node_t *node) /* I - Node to add */
{
mxml_node_t *temp; /* Current node */
const char *tempname, /* Name of current node */
*nodename, /* Name of node */
*scope; /* Scope */
#if DEBUG > 1
fprintf(stderr, " sort_node(tree=%p, node=%p)\n", tree, node);
#endif /* DEBUG > 1 */
/*
* Range check input...
*/
if (!tree || !node || node->parent == tree)
return;
/*
* Get the node name...
*/
if ((nodename = mxmlElementGetAttr(node, "name")) == NULL)
return;
if (nodename[0] == '_')
return; /* Hide private names */
#if DEBUG > 1
fprintf(stderr, " nodename=%p (\"%s\")\n", nodename, nodename);
#endif /* DEBUG > 1 */
/*
* Delete any existing definition at this level, if one exists...
*/
if ((temp = mxmlFindElement(tree, tree, node->value.element.name,
"name", nodename, MXML_DESCEND_FIRST)) != NULL)
{
/*
* Copy the scope if needed...
*/
if ((scope = mxmlElementGetAttr(temp, "scope")) != NULL &&
mxmlElementGetAttr(node, "scope") == NULL)
{
#ifdef DEBUG
fprintf(stderr, " copying scope %s for %s\n", scope, nodename);
#endif /* DEBUG */
mxmlElementSetAttr(node, "scope", scope);
}
mxmlDelete(temp);
}
/*
* Add the node into the tree at the proper place...
*/
for (temp = tree->child; temp; temp = temp->next)
{
#if DEBUG > 1
fprintf(stderr, " temp=%p\n", temp);
#endif /* DEBUG > 1 */
if ((tempname = mxmlElementGetAttr(temp, "name")) == NULL)
continue;
#if DEBUG > 1
fprintf(stderr, " tempname=%p (\"%s\")\n", tempname, tempname);
#endif /* DEBUG > 1 */
if (strcmp(nodename, tempname) < 0)
break;
}
if (temp)
mxmlAdd(tree, MXML_ADD_BEFORE, temp, node);
else
mxmlAdd(tree, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
}
/*
* 'update_comment()' - Update a comment node.
*/
static void
update_comment(mxml_node_t *parent, /* I - Parent node */
mxml_node_t *comment) /* I - Comment node */
{
char *ptr; /* Pointer into comment */
#ifdef DEBUG
fprintf(stderr, "update_comment(parent=%p, comment=%p)\n",
parent, comment);
#endif /* DEBUG */
/*
* Range check the input...
*/
if (!parent || !comment)
return;
/*
* Update the comment...
*/
ptr = comment->value.text.string;
if (*ptr == '\'')
{
/*
* Convert "'name()' - description" to "description".
*/
for (ptr ++; *ptr && *ptr != '\''; ptr ++);
if (*ptr == '\'')
{
ptr ++;
while (isspace(*ptr & 255))
ptr ++;
if (*ptr == '-')
ptr ++;
while (isspace(*ptr & 255))
ptr ++;
safe_strcpy(comment->value.text.string, ptr);
}
}
else if (!strncmp(ptr, "I ", 2) || !strncmp(ptr, "O ", 2) ||
!strncmp(ptr, "IO ", 3))
{
/*
* 'Convert "I - description", "IO - description", or "O - description"
* to description + directory attribute.
*/
ptr = strchr(ptr, ' ');
*ptr++ = '\0';
if (!strcmp(parent->value.element.name, "argument"))
mxmlElementSetAttr(parent, "direction", comment->value.text.string);
while (isspace(*ptr & 255))
ptr ++;
if (*ptr == '-')
ptr ++;
while (isspace(*ptr & 255))
ptr ++;
safe_strcpy(comment->value.text.string, ptr);
}
/*
* Eliminate leading and trailing *'s...
*/
for (ptr = comment->value.text.string; *ptr == '*'; ptr ++);
for (; isspace(*ptr & 255); ptr ++);
if (ptr > comment->value.text.string)
safe_strcpy(comment->value.text.string, ptr);
for (ptr = comment->value.text.string + strlen(comment->value.text.string) - 1;
ptr > comment->value.text.string && *ptr == '*';
ptr --)
*ptr = '\0';
for (; ptr > comment->value.text.string && isspace(*ptr & 255); ptr --)
*ptr = '\0';
#ifdef DEBUG
fprintf(stderr, " updated comment = %s\n", comment->value.text.string);
#endif /* DEBUG */
}
/*
* 'usage()' - Show program usage...
*/
static void
usage(const char *option) /* I - Unknown option */
{
if (option)
printf("mxmldoc: Bad option \"%s\"!\n\n", option);
puts("Usage: mxmldoc [options] [filename.xml] [source files] >filename.html");
puts("Options:");
puts(" --title title Set documentation title");
puts(" --intro introfile.html Set introduction file");
exit(1);
}
/*
* 'write_description()' - Write the description text.
*/
static void
write_description(
mxml_node_t *description) /* I - Description node */
{
char text[10240], /* Text for description */
*ptr; /* Pointer into text */
if (!description)
return;
get_text(description, text, sizeof(text));
for (ptr = text; *ptr; ptr ++)
{
if (*ptr == '@' &&
(!strncmp(ptr + 1, "deprecated@", 11) ||
!strncmp(ptr + 1, "since ", 6)))
{
ptr ++;
while (*ptr && *ptr != '@')
ptr ++;
if (!*ptr)
return;
}
else if (*ptr == '&')
fputs("&", stdout);
else if (*ptr == '<')
fputs("<", stdout);
else if (*ptr == '>')
fputs(">", stdout);
else if (*ptr == '\"')
fputs(""", stdout);
else if (*ptr & 128)
{
/*
* Convert UTF-8 to Unicode constant...
*/
int ch; /* Unicode character */
ch = *ptr & 255;
if ((ch & 0xe0) == 0xc0)
{
ch = ((ch & 0x1f) << 6) | (ptr[1] & 0x3f);
ptr ++;
}
else if ((ch & 0xf0) == 0xe0)
{
ch = ((((ch * 0x0f) << 6) | (ptr[1] & 0x3f)) << 6) | (ptr[2] & 0x3f);
ptr += 2;
}
if (ch == 0xa0)
{
/*
* Handle non-breaking space as-is...
*/
fputs(" ", stdout);
}
else
printf("%x;", ch);
}
else
putchar(*ptr);
}
}
/*
* 'write_documentation()' - Write HTML documentation.
*/
static void
write_documentation(
const char *section, /* I - Section */
const char *title, /* I - Title */
const char *introfile, /* I - Intro file */
mxml_node_t *doc) /* I - XML documentation */
{
int i; /* Looping var */
FILE *fp; /* File */
char line[8192]; /* Line from file */
mxml_node_t *function, /* Current function */
*scut, /* Struct/class/union/typedef */
*arg, /* Current argument */
*description, /* Description of function/var */
*type; /* Type for argument */
const char *name, /* Name of function/type */
*cname, /* Class name */
*defval, /* Default value */
*parent; /* Parent class */
int inscope; /* Variable/method scope */
char prefix; /* Prefix character */
static const char * const scopes[] = /* Scope strings */
{
"private",
"protected",
"public"
};
/*
* Standard header...
*/
puts("\n"
"");
if (section)
printf("\n", section);
printf("\n"
"\t%s\n", title);
if (section)
printf("\t\n", section);
puts("\t\n"
"\t\n"
"\n"
"");
/*
* Intro...
*/
if (introfile && (fp = fopen(introfile, "r")) != NULL)
{
/*
* Insert intro file before contents...
*/
while (fgets(line, sizeof(line), fp))
fputs(line, stdout);
fclose(fp);
}
/*
* Table of contents...
*/
puts("Contents
");
puts("");
if (find_public(doc, doc, "class"))
puts("\t- Classes
");
if (find_public(doc, doc, "enumeration"))
puts("\t- Enumerations
");
if (find_public(doc, doc, "function"))
puts("\t- Functions
");
if (find_public(doc, doc, "struct"))
puts("\t- Structures
");
if (find_public(doc, doc, "typedef"))
puts("\t- Types
");
if (find_public(doc, doc, "union"))
puts("\t- Unions
");
if (find_public(doc, doc, "variable"))
puts("\t- Variables
");
puts("
");
/*
* List of classes...
*/
if (find_public(doc, doc, "class"))
{
puts("\n"
"\n"
"");
for (scut = find_public(doc, doc, "class");
scut;
scut = find_public(scut, doc, "class"))
{
name = mxmlElementGetAttr(scut, "name");
printf("\t- %s %s
\n", name, name,
get_comment_info(mxmlFindElement(scut, scut, "description",
NULL, NULL, MXML_DESCEND_FIRST)));
}
puts("
");
for (scut = find_public(doc, doc, "class");
scut;
scut = find_public(scut, doc, "class"))
{
cname = mxmlElementGetAttr(scut, "name");
description = mxmlFindElement(scut, scut, "description", NULL,
NULL, MXML_DESCEND_FIRST);
printf("\n"
"\n",
get_comment_info(description), cname, cname);
if (description)
{
fputs("Description
\n"
"", stdout);
write_description(description);
puts("
");
}
printf("Definition
\n"
"\n"
"class %s", cname);
if ((parent = mxmlElementGetAttr(scut, "parent")) != NULL)
printf(" %s", parent);
puts("\n{");
for (i = 0; i < 3; i ++)
{
inscope = 0;
for (arg = mxmlFindElement(scut, scut, "variable", "scope", scopes[i],
MXML_DESCEND_FIRST);
arg;
arg = mxmlFindElement(arg, scut, "variable", "scope", scopes[i],
MXML_NO_DESCEND))
{
if (!inscope)
{
inscope = 1;
printf(" %s:\n", scopes[i]);
}
printf(" ");
write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
NULL, MXML_DESCEND_FIRST));
printf(" %s;\n", mxmlElementGetAttr(arg, "name"));
}
for (function = mxmlFindElement(scut, scut, "function", "scope",
scopes[i], MXML_DESCEND_FIRST);
function;
function = mxmlFindElement(function, scut, "function", "scope",
scopes[i], MXML_NO_DESCEND))
{
if (!inscope)
{
inscope = 1;
printf(" %s:\n", scopes[i]);
}
name = mxmlElementGetAttr(function, "name");
printf(" ");
arg = mxmlFindElement(function, function, "returnvalue", NULL,
NULL, MXML_DESCEND_FIRST);
if (arg)
{
write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
NULL, MXML_DESCEND_FIRST));
putchar(' ');
}
else if (strcmp(cname, name) && strcmp(cname, name + 1))
fputs("void ", stdout);
printf("%s", cname, name, name);
for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
MXML_DESCEND_FIRST), prefix = '(';
arg;
arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
MXML_NO_DESCEND), prefix = ',')
{
type = mxmlFindElement(arg, arg, "type", NULL, NULL,
MXML_DESCEND_FIRST);
putchar(prefix);
if (prefix == ',')
putchar(' ');
if (type->child)
{
write_element(doc, type);
putchar(' ');
}
fputs(mxmlElementGetAttr(arg, "name"), stdout);
if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
printf(" %s", defval);
}
if (prefix == '(')
puts("(void);");
else
puts(");");
}
}
puts("};\n
\n"
"Members
\n"
"\n"
"Name | Description |
\n"
"");
for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
MXML_DESCEND_FIRST);
arg;
arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
MXML_NO_DESCEND))
{
description = mxmlFindElement(arg, arg, "description", NULL,
NULL, MXML_DESCEND_FIRST);
printf("%s %s | ",
mxmlElementGetAttr(arg, "name"), get_comment_info(description));
write_description(description);
puts(" |
");
}
for (function = mxmlFindElement(scut, scut, "function", NULL, NULL,
MXML_DESCEND_FIRST);
function;
function = mxmlFindElement(function, scut, "function", NULL, NULL,
MXML_NO_DESCEND))
{
name = mxmlElementGetAttr(function, "name");
description = mxmlFindElement(function, function, "description", NULL,
NULL, MXML_DESCEND_FIRST);
printf("%s() %s | ",
cname, name, name, get_comment_info(description));
write_description(description);
arg = mxmlFindElement(function, function, "returnvalue", NULL,
NULL, MXML_DESCEND_FIRST);
if (arg)
{
fputs("\nReturns: ", stdout);
write_element(NULL, mxmlFindElement(arg, arg, "description", NULL,
NULL, MXML_DESCEND_FIRST));
}
puts(" |
");
}
puts("
");
}
}
/*
* List of enumerations...
*/
if (find_public(doc, doc, "enumeration"))
{
puts("\n"
"\n"
"");
for (scut = find_public(doc, doc, "enumeration");
scut;
scut = find_public(scut, doc, "enumeration"))
{
name = mxmlElementGetAttr(scut, "name");
printf("\t- %s %s
\n", name, name,
get_comment_info(mxmlFindElement(scut, scut, "description",
NULL, NULL, MXML_DESCEND_FIRST)));
}
puts("
");
for (scut = find_public(doc, doc, "enumeration");
scut;
scut = find_public(scut, doc, "enumeration"))
{
name = mxmlElementGetAttr(scut, "name");
description = mxmlFindElement(scut, scut, "description", NULL,
NULL, MXML_DESCEND_FIRST);
printf("\n"
"\n",
get_comment_info(description), name, name);
if (description)
{
fputs("Description
\n"
"", stdout);
write_description(description);
puts("
");
}
puts("Values
\n"
"\n"
"Name | Description |
\n"
"");
for (arg = mxmlFindElement(scut, scut, "constant", NULL, NULL,
MXML_DESCEND_FIRST);
arg;
arg = mxmlFindElement(arg, scut, "constant", NULL, NULL,
MXML_NO_DESCEND))
{
description = mxmlFindElement(arg, arg, "description", NULL,
NULL, MXML_DESCEND_FIRST);
printf("%s %s | ",
mxmlElementGetAttr(arg, "name"), get_comment_info(description));
write_description(description);
puts(" |
");
}
puts("
");
}
}
/*
* List of functions...
*/
if (find_public(doc, doc, "function"))
{
puts("\n"
"\n"
"");
for (function = find_public(doc, doc, "function");
function;
function = find_public(function, doc, "function"))
{
name = mxmlElementGetAttr(function, "name");
printf("\t- %s() %s
\n", name, name,
get_comment_info(mxmlFindElement(function, function, "description",
NULL, NULL, MXML_DESCEND_FIRST)));
}
puts("
");
for (function = find_public(doc, doc, "function");
function;
function = find_public(function, doc, "function"))
{
name = mxmlElementGetAttr(function, "name");
description = mxmlFindElement(function, function, "description", NULL,
NULL, MXML_DESCEND_FIRST);
printf("\n"
"\n",
get_comment_info(description), name, name);
if (description)
{
fputs("Description
\n"
"", stdout);
write_description(description);
puts("
");
}
puts("Syntax
\n"
"");
arg = mxmlFindElement(function, function, "returnvalue", NULL,
NULL, MXML_DESCEND_FIRST);
if (arg)
write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
NULL, MXML_DESCEND_FIRST));
else
fputs("void", stdout);
printf("\n%s", name);
for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
MXML_DESCEND_FIRST), prefix = '(';
arg;
arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
MXML_NO_DESCEND), prefix = ',')
{
type = mxmlFindElement(arg, arg, "type", NULL, NULL,
MXML_DESCEND_FIRST);
printf("%c\n ", prefix);
if (type->child)
{
write_element(doc, type);
putchar(' ');
}
fputs(mxmlElementGetAttr(arg, "name"), stdout);
if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
printf(" %s", defval);
}
if (prefix == '(')
puts("(void);\n
");
else
puts(");\n");
puts("Arguments
");
if (prefix == '(')
puts("None.
");
else
{
puts("\n"
"Name | Description |
\n"
"");
for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
MXML_DESCEND_FIRST);
arg;
arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
MXML_NO_DESCEND))
{
printf("%s | ", mxmlElementGetAttr(arg, "name"));
write_element(NULL, mxmlFindElement(arg, arg, "description", NULL,
NULL, MXML_DESCEND_FIRST));
puts(" |
");
}
puts("
");
}
puts("Returns
");
arg = mxmlFindElement(function, function, "returnvalue", NULL,
NULL, MXML_DESCEND_FIRST);
if (!arg)
puts("Nothing.
");
else
{
fputs("", stdout);
write_element(NULL, mxmlFindElement(arg, arg, "description", NULL,
NULL, MXML_DESCEND_FIRST));
puts("
");
}
}
}
/*
* List of structures...
*/
if (find_public(doc, doc, "struct"))
{
puts("\n"
"\n"
"");
for (scut = find_public(doc, doc, "struct");
scut;
scut = find_public(scut, doc, "struct"))
{
name = mxmlElementGetAttr(scut, "name");
printf("\t- %s %s
\n", name, name,
get_comment_info(mxmlFindElement(scut, scut, "description",
NULL, NULL, MXML_DESCEND_FIRST)));
}
puts("
");
for (scut = find_public(doc, doc, "struct");
scut;
scut = find_public(scut, doc, "struct"))
{
cname = mxmlElementGetAttr(scut, "name");
description = mxmlFindElement(scut, scut, "description", NULL,
NULL, MXML_DESCEND_FIRST);
printf("\n"
"\n",
get_comment_info(description), cname, cname);
if (description)
{
fputs("Description
\n"
"", stdout);
write_description(description);
puts("
");
}
printf("Definition
\n"
"\n"
"struct %s\n{\n", cname);
for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
MXML_DESCEND_FIRST);
arg;
arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
MXML_NO_DESCEND))
{
printf(" ");
write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
NULL, MXML_DESCEND_FIRST));
printf(" %s;\n", mxmlElementGetAttr(arg, "name"));
}
for (function = mxmlFindElement(scut, scut, "function", NULL, NULL,
MXML_DESCEND_FIRST);
function;
function = mxmlFindElement(function, scut, "function", NULL, NULL,
MXML_NO_DESCEND))
{
name = mxmlElementGetAttr(function, "name");
printf(" ");
arg = mxmlFindElement(function, function, "returnvalue", NULL,
NULL, MXML_DESCEND_FIRST);
if (arg)
{
write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
NULL, MXML_DESCEND_FIRST));
putchar(' ');
}
else if (strcmp(cname, name) && strcmp(cname, name + 1))
fputs("void ", stdout);
printf("%s", cname, name, name);
for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
MXML_DESCEND_FIRST), prefix = '(';
arg;
arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
MXML_NO_DESCEND), prefix = ',')
{
type = mxmlFindElement(arg, arg, "type", NULL, NULL,
MXML_DESCEND_FIRST);
putchar(prefix);
if (prefix == ',')
putchar(' ');
if (type->child)
{
write_element(doc, type);
putchar(' ');
}
fputs(mxmlElementGetAttr(arg, "name"), stdout);
if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
printf(" %s", defval);
}
if (prefix == '(')
puts("(void);");
else
puts(");");
}
puts("};\n
\n"
"Members
\n"
"\n"
"Name | Description |
\n"
"");
for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
MXML_DESCEND_FIRST);
arg;
arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
MXML_NO_DESCEND))
{
description = mxmlFindElement(arg, arg, "description", NULL,
NULL, MXML_DESCEND_FIRST);
printf("%s %s | ",
mxmlElementGetAttr(arg, "name"), get_comment_info(description));
write_description(description);
puts(" |
");
}
for (function = mxmlFindElement(scut, scut, "function", NULL, NULL,
MXML_DESCEND_FIRST);
function;
function = mxmlFindElement(function, scut, "function", NULL, NULL,
MXML_NO_DESCEND))
{
name = mxmlElementGetAttr(function, "name");
description = mxmlFindElement(function, function, "description", NULL,
NULL, MXML_DESCEND_FIRST);
printf("%s() %s | ",
cname, name, name, get_comment_info(description));
write_description(description);
arg = mxmlFindElement(function, function, "returnvalue", NULL,
NULL, MXML_DESCEND_FIRST);
if (arg)
{
fputs("\nReturns: ", stdout);
write_element(NULL, mxmlFindElement(arg, arg, "description", NULL,
NULL, MXML_DESCEND_FIRST));
}
puts(" |
");
}
puts("
");
}
}
/*
* List of types...
*/
if (find_public(doc, doc, "typedef"))
{
puts("\n"
"\n"
"");
for (scut = find_public(doc, doc, "typedef");
scut;
scut = find_public(scut, doc, "typedef"))
{
name = mxmlElementGetAttr(scut, "name");
printf("\t- %s %s
\n", name, name,
get_comment_info(mxmlFindElement(scut, scut, "description",
NULL, NULL, MXML_DESCEND_FIRST)));
}
puts("
");
for (scut = find_public(doc, doc, "typedef");
scut;
scut = find_public(scut, doc, "typedef"))
{
name = mxmlElementGetAttr(scut, "name");
description = mxmlFindElement(scut, scut, "description", NULL,
NULL, MXML_DESCEND_FIRST);
printf("\n"
"\n",
get_comment_info(description), name, name);
if (description)
{
fputs("Description
\n"
"", stdout);
write_description(description);
puts("
");
}
fputs("Definition
\n"
"\n"
"typedef ", stdout);
type = mxmlFindElement(scut, scut, "type", NULL, NULL,
MXML_DESCEND_FIRST);
for (type = type->child; type; type = type->next)
if (!strcmp(type->value.text.string, "("))
break;
else
{
if (type->value.text.whitespace)
putchar(' ');
if (mxmlFindElement(doc, doc, "class", "name",
type->value.text.string, MXML_DESCEND) ||
mxmlFindElement(doc, doc, "enumeration", "name",
type->value.text.string, MXML_DESCEND) ||
mxmlFindElement(doc, doc, "struct", "name",
type->value.text.string, MXML_DESCEND) ||
mxmlFindElement(doc, doc, "typedef", "name",
type->value.text.string, MXML_DESCEND) ||
mxmlFindElement(doc, doc, "union", "name",
type->value.text.string, MXML_DESCEND))
{
printf("");
write_string(type->value.text.string);
printf("");
}
else
write_string(type->value.text.string);
}
if (type)
{
/*
* Output function type...
*/
printf(" (*%s", name);
for (type = type->next->next; type; type = type->next)
{
if (type->value.text.whitespace)
putchar(' ');
if (mxmlFindElement(doc, doc, "class", "name",
type->value.text.string, MXML_DESCEND) ||
mxmlFindElement(doc, doc, "enumeration", "name",
type->value.text.string, MXML_DESCEND) ||
mxmlFindElement(doc, doc, "struct", "name",
type->value.text.string, MXML_DESCEND) ||
mxmlFindElement(doc, doc, "typedef", "name",
type->value.text.string, MXML_DESCEND) ||
mxmlFindElement(doc, doc, "union", "name",
type->value.text.string, MXML_DESCEND))
{
printf("");
write_string(type->value.text.string);
printf("");
}
else
write_string(type->value.text.string);
}
puts(";");
}
else
printf(" %s;\n", name);
puts("
");
}
}
/*
* List of unions...
*/
if (find_public(doc, doc, "union"))
{
puts("\n"
"\n"
"");
for (scut = find_public(doc, doc, "union");
scut;
scut = find_public(scut, doc, "union"))
{
name = mxmlElementGetAttr(scut, "name");
printf("\t- %s %s
\n", name, name,
get_comment_info(mxmlFindElement(scut, scut, "description",
NULL, NULL, MXML_DESCEND_FIRST)));
}
puts("
");
for (scut = find_public(doc, doc, "union");
scut;
scut = find_public(scut, doc, "union"))
{
name = mxmlElementGetAttr(scut, "name");
description = mxmlFindElement(scut, scut, "description", NULL,
NULL, MXML_DESCEND_FIRST);
printf("\n"
"\n",
get_comment_info(description), name, name);
if (description)
{
fputs("Description
\n"
"", stdout);
write_description(description);
puts("
");
}
printf("Definition
\n"
"\n"
"union %s\n{\n", name);
for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
MXML_DESCEND_FIRST);
arg;
arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
MXML_NO_DESCEND))
{
printf(" ");
write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
NULL, MXML_DESCEND_FIRST));
printf(" %s;\n", mxmlElementGetAttr(arg, "name"));
}
puts("};\n
\n"
"Members
\n"
"\n"
"Name | Description |
\n"
"");
for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
MXML_DESCEND_FIRST);
arg;
arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
MXML_NO_DESCEND))
{
description = mxmlFindElement(arg, arg, "description", NULL,
NULL, MXML_DESCEND_FIRST);
printf("%s %s | ",
mxmlElementGetAttr(arg, "name"), get_comment_info(description));
write_description(description);
puts(" |
");
}
puts("
");
}
}
/*
* Variables...
*/
if (find_public(doc, doc, "variable"))
{
puts("\n"
"\n"
"");
for (arg = find_public(doc, doc, "variable");
arg;
arg = find_public(arg, doc, "variable"))
{
name = mxmlElementGetAttr(arg, "name");
printf("\t- %s %s
\n", name, name,
get_comment_info(mxmlFindElement(arg, arg, "description",
NULL, NULL, MXML_DESCEND_FIRST)));
}
puts("
");
for (arg = find_public(doc, doc, "variable");
arg;
arg = find_public(arg, doc, "variable"))
{
name = mxmlElementGetAttr(arg, "name");
description = mxmlFindElement(arg, arg, "description", NULL,
NULL, MXML_DESCEND_FIRST);
printf("\n"
"\n",
get_comment_info(description), name, name);
if (description)
{
fputs("Description
\n"
"", stdout);
write_description(description);
puts("
");
}
puts("Definition
\n"
"");
write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
NULL, MXML_DESCEND_FIRST));
printf(" %s", mxmlElementGetAttr(arg, "name"));
if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
printf(" %s", defval);
puts(";\n
");
}
}
/*
* Standard footer...
*/
puts("\n"
"");
}
/*
* 'write_element()' - Write an element's text nodes.
*/
static void
write_element(mxml_node_t *doc, /* I - Document tree */
mxml_node_t *element) /* I - Element to write */
{
mxml_node_t *node; /* Current node */
if (!element)
return;
for (node = element->child;
node;
node = mxmlWalkNext(node, element, MXML_NO_DESCEND))
if (node->type == MXML_TEXT)
{
if (node->value.text.whitespace)
putchar(' ');
if (mxmlFindElement(doc, doc, "class", "name", node->value.text.string,
MXML_DESCEND) ||
mxmlFindElement(doc, doc, "enumeration", "name",
node->value.text.string, MXML_DESCEND) ||
mxmlFindElement(doc, doc, "struct", "name", node->value.text.string,
MXML_DESCEND) ||
mxmlFindElement(doc, doc, "typedef", "name", node->value.text.string,
MXML_DESCEND) ||
mxmlFindElement(doc, doc, "union", "name", node->value.text.string,
MXML_DESCEND))
{
printf("");
write_string(node->value.text.string);
printf("");
}
else
write_string(node->value.text.string);
}
}
/*
* 'write_string()' - Write a string, quoting XHTML special chars as needed...
*/
static void
write_string(const char *s) /* I - String to write */
{
while (*s)
{
if (*s == '&')
fputs("&", stdout);
else if (*s == '<')
fputs("<", stdout);
else if (*s == '>')
fputs(">", stdout);
else if (*s == '\"')
fputs(""", stdout);
else if (*s & 128)
{
/*
* Convert UTF-8 to Unicode constant...
*/
int ch; /* Unicode character */
ch = *s & 255;
if ((ch & 0xe0) == 0xc0)
{
ch = ((ch & 0x1f) << 6) | (s[1] & 0x3f);
s ++;
}
else if ((ch & 0xf0) == 0xe0)
{
ch = ((((ch * 0x0f) << 6) | (s[1] & 0x3f)) << 6) | (s[2] & 0x3f);
s += 2;
}
if (ch == 0xa0)
{
/*
* Handle non-breaking space as-is...
*/
fputs(" ", stdout);
}
else
printf("%x;", ch);
}
else
putchar(*s);
s ++;
}
}
/*
* 'ws_cb()' - Whitespace callback for saving.
*/
static const char * /* O - Whitespace string or NULL for none */
ws_cb(mxml_node_t *node, /* I - Element node */
int where) /* I - Where value */
{
const char *name; /* Name of element */
int depth; /* Depth of node */
static const char *spaces = " ";
/* Whitespace (40 spaces) for indent */
name = node->value.element.name;
switch (where)
{
case MXML_WS_BEFORE_CLOSE :
if (strcmp(name, "argument") &&
strcmp(name, "class") &&
strcmp(name, "constant") &&
strcmp(name, "enumeration") &&
strcmp(name, "function") &&
strcmp(name, "mxmldoc") &&
strcmp(name, "namespace") &&
strcmp(name, "returnvalue") &&
strcmp(name, "struct") &&
strcmp(name, "typedef") &&
strcmp(name, "union") &&
strcmp(name, "variable"))
return (NULL);
for (depth = -4; node; node = node->parent, depth += 2);
if (depth > 40)
return (spaces);
else if (depth < 2)
return (NULL);
else
return (spaces + 40 - depth);
case MXML_WS_AFTER_CLOSE :
return ("\n");
case MXML_WS_BEFORE_OPEN :
for (depth = -4; node; node = node->parent, depth += 2);
if (depth > 40)
return (spaces);
else if (depth < 2)
return (NULL);
else
return (spaces + 40 - depth);
default :
case MXML_WS_AFTER_OPEN :
if (strcmp(name, "argument") &&
strcmp(name, "class") &&
strcmp(name, "constant") &&
strcmp(name, "enumeration") &&
strcmp(name, "function") &&
strcmp(name, "mxmldoc") &&
strcmp(name, "namespace") &&
strcmp(name, "returnvalue") &&
strcmp(name, "struct") &&
strcmp(name, "typedef") &&
strcmp(name, "union") &&
strcmp(name, "variable"))
return (NULL);
else
return ("\n");
}
}
/*
* End of "$Id$".
*/