diff --git a/index.html b/index.html
index 690a1f6..ef05ac5 100644
--- a/index.html
+++ b/index.html
@@ -19,7 +19,8 @@ href="../index.html">Back to Home Page ]
Current Release: v0.93 [ Download Source (.tar.gz 40k) |
-View Change Log ]
+View Change Log |
+Rate/Make Comments ]
Introduction
diff --git a/mxml-file.c b/mxml-file.c
index 74907ae..108d309 100644
--- a/mxml-file.c
+++ b/mxml-file.c
@@ -1,5 +1,5 @@
/*
- * "$Id: mxml-file.c,v 1.7 2003/06/04 17:37:23 mike Exp $"
+ * "$Id: mxml-file.c,v 1.8 2003/06/04 21:18:59 mike Exp $"
*
* File loading code for mini-XML, a small XML-like file parsing library.
*
@@ -22,6 +22,7 @@
* mxml_parse_element() - Parse an element for any attributes...
* mxml_write_node() - Save an XML node to a file.
* mxml_write_string() - Write a string, escaping & and < as needed.
+ * mxml_write_ws() - Do whitespace callback...
*/
/*
@@ -39,6 +40,8 @@ static int mxml_parse_element(mxml_node_t *node, FILE *fp);
static int mxml_write_node(mxml_node_t *node, FILE *fp,
int (*cb)(mxml_node_t *, int), int col);
static int mxml_write_string(const char *s, FILE *fp);
+static int mxml_write_ws(mxml_node_t *node, FILE *fp,
+ int (*cb)(mxml_node_t *, int), int ws, int col);
/*
@@ -702,7 +705,6 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */
int col) /* I - Current column */
{
int i; /* Looping var */
- int ch; /* Whitespace character */
int n; /* Chars written */
mxml_attr_t *attr; /* Current attribute */
@@ -716,17 +718,7 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */
switch (node->type)
{
case MXML_ELEMENT :
- if (cb && (ch = (*cb)(node, MXML_SAVE_OPEN_TAG)) != 0)
- {
- if (putc(ch, fp) < 0)
- return (-1);
- else if (ch == '\n')
- col = 0;
- else if (ch == '\t')
- col += 8;
- else
- col ++;
- }
+ col = mxml_write_ws(node, fp, cb, MXML_WS_BEFORE_OPEN, col);
if ((n = fprintf(fp, "<%s", node->value.element.name)) < 0)
return (-1);
@@ -776,16 +768,22 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */
else
col ++;
+ col = mxml_write_ws(node, fp, cb, MXML_WS_AFTER_OPEN, col);
+
if ((col = mxml_write_node(node->child, fp, cb, col)) < 0)
return (-1);
if (node->value.element.name[0] != '?' &&
node->value.element.name[0] != '!')
{
+ col = mxml_write_ws(node, fp, cb, MXML_WS_BEFORE_CLOSE, col);
+
if ((n = fprintf(fp, "%s>", node->value.element.name)) < 0)
return (-1);
col += n;
+
+ col = mxml_write_ws(node, fp, cb, MXML_WS_AFTER_CLOSE, col);
}
}
else if (node->value.element.name[0] == '!')
@@ -794,22 +792,16 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */
return (-1);
else
col ++;
+
+ col = mxml_write_ws(node, fp, cb, MXML_WS_AFTER_OPEN, col);
}
else if (fputs("/>", fp) < 0)
return (-1);
else
+ {
col += 2;
- if (cb && (ch = (*cb)(node, MXML_SAVE_CLOSE_TAG)) != 0)
- {
- if (putc(ch, fp) < 0)
- return (-1);
- else if (ch == '\n')
- col = 0;
- else if (ch == '\t')
- col += 8;
- else
- col ++;
+ col = mxml_write_ws(node, fp, cb, MXML_WS_AFTER_OPEN, col);
}
break;
@@ -972,7 +964,40 @@ mxml_write_string(const char *s, /* I - String to write */
}
+/*
+ * 'mxml_write_ws()' - Do whitespace callback...
+ */
+
+static int /* O - New column */
+mxml_write_ws(mxml_node_t *node, /* I - Current node */
+ FILE *fp, /* I - File to write to */
+ int (*cb)(mxml_node_t *, int),
+ /* I - Callback function */
+ int ws, /* I - Where value */
+ int col) /* I - Current column */
+{
+ int ch; /* Whitespace character */
+
+
+ if (cb && (ch = (*cb)(node, MXML_WS_BEFORE_OPEN)) != 0)
+ {
+ if (putc(ch, fp) < 0)
+ return (-1);
+ else if (ch == '\n')
+ col = 0;
+ else if (ch == '\t')
+ {
+ col += MXML_TAB;
+ col = col - (col % MXML_TAB);
+ }
+ else
+ col ++;
+ }
+
+ return (col);
+}
+
/*
- * End of "$Id: mxml-file.c,v 1.7 2003/06/04 17:37:23 mike Exp $".
+ * End of "$Id: mxml-file.c,v 1.8 2003/06/04 21:18:59 mike Exp $".
*/
diff --git a/mxml-node.c b/mxml-node.c
index 3e9849c..935cd28 100644
--- a/mxml-node.c
+++ b/mxml-node.c
@@ -1,5 +1,5 @@
/*
- * "$Id: mxml-node.c,v 1.2 2003/06/04 17:37:23 mike Exp $"
+ * "$Id: mxml-node.c,v 1.3 2003/06/04 21:19:00 mike Exp $"
*
* Node support code for mini-XML, a small XML-like file parsing library.
*
@@ -52,12 +52,24 @@ mxmlAdd(mxml_node_t *parent, /* I - Parent node */
mxml_node_t *child, /* I - Child node for where */
mxml_node_t *node) /* I - Node to add */
{
- if (!parent)
+ /*
+ * Range check input...
+ */
+
+ if (!parent || !node)
return;
+ /*
+ * Remove the node from any existing parent...
+ */
+
if (node->parent)
mxmlRemove(node);
+ /*
+ * Reset pointers...
+ */
+
node->parent = parent;
switch (where)
@@ -430,5 +442,5 @@ mxml_new(mxml_node_t *parent, /* I - Parent node */
/*
- * End of "$Id: mxml-node.c,v 1.2 2003/06/04 17:37:23 mike Exp $".
+ * End of "$Id: mxml-node.c,v 1.3 2003/06/04 21:19:00 mike Exp $".
*/
diff --git a/mxml-search.c b/mxml-search.c
index 857472a..1372d72 100644
--- a/mxml-search.c
+++ b/mxml-search.c
@@ -1,5 +1,5 @@
/*
- * "$Id: mxml-search.c,v 1.3 2003/06/04 16:30:40 mike Exp $"
+ * "$Id: mxml-search.c,v 1.4 2003/06/04 21:19:00 mike Exp $"
*
* Search/navigation functions for mini-XML, a small XML-like file
* parsing library.
@@ -123,7 +123,7 @@ mxmlWalkNext(mxml_node_t *node, /* I - Current node */
return (node->child);
else if (node->next)
return (node->next);
- else if (node->parent != top)
+ else if (node->parent && node->parent != top)
{
node = node->parent;
@@ -177,5 +177,5 @@ mxmlWalkPrev(mxml_node_t *node, /* I - Current node */
/*
- * End of "$Id: mxml-search.c,v 1.3 2003/06/04 16:30:40 mike Exp $".
+ * End of "$Id: mxml-search.c,v 1.4 2003/06/04 21:19:00 mike Exp $".
*/
diff --git a/mxml.h b/mxml.h
index 8eef0fe..ba7c762 100644
--- a/mxml.h
+++ b/mxml.h
@@ -1,5 +1,5 @@
/*
- * "$Id: mxml.h,v 1.6 2003/06/04 17:37:23 mike Exp $"
+ * "$Id: mxml.h,v 1.7 2003/06/04 21:19:00 mike Exp $"
*
* Header file for mini-XML, a small XML-like file parsing library.
*
@@ -38,16 +38,20 @@
* Constants...
*/
-# define MXML_NO_CALLBACK 0 /* Don't use a type callback */
# define MXML_WRAP 72 /* Wrap XML output at this column position */
+# define MXML_TAB 8 /* Tabs every N columns */
+
+# define MXML_NO_CALLBACK 0 /* Don't use a type callback */
+# define MXML_NO_PARENT 0 /* No parent for the node */
# define MXML_DESCEND 1 /* Descend when finding/walking */
# define MXML_NO_DESCEND 0 /* Don't descend when finding/walking */
# define MXML_DESCEND_FIRST -1 /* Descend for first find */
-# define MXML_SAVE_OPEN_TAG 0 /* Callback for open tag */
-# define MXML_SAVE_CLOSE_TAG 1 /* Callback for close tag */
-
+# define MXML_WS_BEFORE_OPEN 0 /* Callback for before open tag */
+# define MXML_WS_AFTER_OPEN 1 /* Callback for after open tag */
+# define MXML_WS_BEFORE_CLOSE 2 /* Callback for before close tag */
+# define MXML_WS_AFTER_CLOSE 3 /* Callback for after close tag */
# define MXML_ADD_BEFORE 0 /* Add node before specified node */
# define MXML_ADD_AFTER 1 /* Add node after specified node */
@@ -154,5 +158,5 @@ extern mxml_node_t *mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top,
/*
- * End of "$Id: mxml.h,v 1.6 2003/06/04 17:37:23 mike Exp $".
+ * End of "$Id: mxml.h,v 1.7 2003/06/04 21:19:00 mike Exp $".
*/
diff --git a/mxmldoc.c b/mxmldoc.c
index 7651a5f..b75946a 100644
--- a/mxmldoc.c
+++ b/mxmldoc.c
@@ -1,5 +1,5 @@
/*
- * "$Id: mxmldoc.c,v 1.3 2003/06/04 17:37:23 mike Exp $"
+ * "$Id: mxmldoc.c,v 1.4 2003/06/04 21:19:00 mike Exp $"
*
* Documentation generator using mini-XML, a small XML-like file parsing
* library.
@@ -56,18 +56,10 @@
*
*
* descriptive text
- *
+ *
* descriptive text
* type string
- *
- *
- * descriptive text
- * type string
- *
- *
- * descriptive text
- * type string
- *
+ *
*
* descriptive text
* type string
@@ -222,6 +214,19 @@ main(int argc, /* I - Number of command-line args */
}
+/*
+ * Basic states for file parser...
+ */
+
+#define STATE_NONE 0 /* No state - whitespace, etc. */
+#define STATE_PREPROCESSOR 1 /* Preprocessor directive */
+#define STATE_C_COMMENT 2 /* Inside a C comment */
+#define STATE_CXX_COMMENT 3 /* Inside a C++ comment */
+#define STATE_STRING 4 /* Inside a string constant */
+#define STATE_CHARACTER 5 /* Inside a character constant */
+#define STATE_IDENTIFIER 6 /* Inside a keyword/identifier */
+
+
/*
* 'scan_file()' - Scan a source file.
*/
@@ -231,6 +236,339 @@ scan_file(const char *filename, /* I - Filename */
FILE *fp, /* I - File to scan */
mxml_node_t *tree) /* I - Function tree */
{
+ int state, /* Current parser state */
+ oldstate, /* Previous state */
+ oldch, /* Old character */
+ braces, /* Number of braces active */
+ parens; /* Number of active parenthesis */
+ int ch;
+ char buffer[16384],
+ *bufptr;
+ mxml_node_t *comment, /* node */
+ *function, /* node */
+ *variable, /* or node */
+ *returnvalue, /* node */
+ *type, /* node */
+ *description; /* node */
+ static const char *states[] =
+ {
+ "STATE_NONE",
+ "STATE_PREPROCESSOR",
+ "STATE_C_COMMENT",
+ "STATE_CXX_COMMENT",
+ "STATE_STRING",
+ "STATE_CHARACTER",
+ "STATE_IDENTIFIER"
+ };
+
+
+ /*
+ * Initialize the finite state machine...
+ */
+
+ state = STATE_NONE;
+ braces = 0;
+ parens = 0;
+ bufptr = buffer;
+
+ comment = NULL;
+ function = NULL;
+ variable = NULL;
+ returnvalue = NULL;
+ type = NULL;
+ description = NULL;
+
+ /*
+ * Read until end-of-file...
+ */
+
+ while ((ch = getc(fp)) != EOF)
+ {
+ oldstate = state;
+ oldch = ch;
+
+ 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);
+ break;
+
+ case '#' : /* Preprocessor */
+ state = STATE_PREPROCESSOR;
+ break;
+
+ case '\'' : /* Character constant */
+ state = STATE_CHARACTER;
+ break;
+
+ case '\"' : /* String constant */
+ state = STATE_STRING;
+ break;
+
+ case '{' :
+ braces ++;
+ break;
+
+ case '}' :
+ if (braces > 0)
+ braces --;
+ break;
+
+ case '(' :
+ parens ++;
+ break;
+
+ case ')' :
+ if (parens > 0)
+ parens --;
+ break;
+
+ default : /* Other */
+ if (isalpha(ch) || ch == '_')
+ {
+ state = STATE_IDENTIFIER;
+ bufptr = buffer;
+ *bufptr++ = ch;
+ }
+ else if (ch == '*')
+ {
+ puts("Identifier: <<< * >>>");
+
+ if (type)
+ mxmlNewText(type, 1, "*");
+ }
+ 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)
+ {
+ mxmlDelete(comment);
+ comment = NULL;
+ }
+
+ if (variable)
+ {
+ description = mxmlNewElement(variable, "description");
+ mxmlNewText(description, 0, buffer);
+ }
+ else
+ comment = mxmlNewText(MXML_NO_PARENT, 0, buffer);
+
+ printf("C comment: <<< %s >>>\n", buffer);
+
+ state = STATE_NONE;
+ break;
+ }
+ else
+ ungetc(ch, fp);
+ }
+ else if (ch == '\n' && bufptr < (buffer + sizeof(buffer) - 1))
+ *bufptr++ = ch;
+ else if (!isspace(ch))
+ break;
+
+ if (ch != EOF)
+ ungetc(ch, fp);
+
+ if (bufptr < (buffer + sizeof(buffer) - 1))
+ *bufptr++ = '\n';
+ break;
+
+ case '/' :
+ if (ch == '/' && bufptr > buffer && bufptr[-1] == '*')
+ {
+ while (bufptr > buffer &&
+ (bufptr[-1] == '*' || isspace(bufptr[-1])))
+ bufptr --;
+ *bufptr = '\0';
+
+ if (comment)
+ {
+ mxmlDelete(comment);
+ comment = NULL;
+ }
+
+ if (variable)
+ {
+ description = mxmlNewElement(variable, "description");
+ mxmlNewText(description, 0, buffer);
+ }
+ else
+ comment = mxmlNewText(MXML_NO_PARENT, 0, buffer);
+
+ printf("C comment: <<< %s >>>\n", buffer);
+
+ 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')
+ {
+ *bufptr = '\0';
+
+ if (comment)
+ {
+ mxmlDelete(comment);
+ comment = NULL;
+ }
+
+ if (variable)
+ {
+ description = mxmlNewElement(variable, "description");
+ mxmlNewText(description, 0, buffer);
+ }
+ else
+ comment = mxmlNewText(MXML_NO_PARENT, 0, buffer);
+
+ printf("C++ comment: <<< %s >>>\n", buffer);
+ }
+ else if (ch == ' ' && bufptr == buffer)
+ break;
+ else if (bufptr < (buffer + sizeof(buffer) - 1))
+ *bufptr++ = ch;
+ break;
+
+ case STATE_STRING : /* Inside a string constant */
+ if (ch == '\\')
+ getc(fp);
+ else if (ch == '\"')
+ state = STATE_NONE;
+ break;
+
+ case STATE_CHARACTER : /* Inside a character constant */
+ if (ch == '\\')
+ getc(fp);
+ else if (ch == '\'')
+ state = STATE_NONE;
+ break;
+
+ case STATE_IDENTIFIER : /* Inside a keyword or identifier */
+ if (isalnum(ch) || ch == '_' || ch == '[' || ch == ']')
+ {
+ if (bufptr < (buffer + sizeof(buffer) - 1))
+ *bufptr++ = ch;
+ }
+ else
+ {
+ ungetc(ch, fp);
+ *bufptr = '\0';
+ printf("Identifier: <<< %s >>>\n", buffer);
+
+ if (!braces)
+ {
+ if (!type)
+ type = mxmlNewElement(MXML_NO_PARENT, "type");
+
+ if (!function && ch == '(')
+ {
+ function = mxmlNewElement(MXML_NO_PARENT, "function");
+ mxmlElementSetAttr(function, "name", buffer);
+
+ sort_node(tree, function);
+
+ returnvalue = mxmlNewElement(function, "returnvalue");
+
+ mxmlAdd(returnvalue, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, comment);
+ mxmlAdd(returnvalue, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type);
+
+ comment = NULL;
+ type = NULL;
+ }
+ else if (function && (ch == ')' || ch == ','))
+ {
+ /*
+ * Argument definition...
+ */
+
+ variable = mxmlNewElement(function, "argument");
+ mxmlElementSetAttr(variable, "name", buffer);
+
+ mxmlAdd(variable, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type);
+ type = NULL;
+ }
+ else if (!function && (ch == ';' || ch == ','))
+ {
+ /*
+ * Variable definition...
+ */
+
+ variable = mxmlNewElement(MXML_NO_PARENT, "variable");
+ mxmlElementSetAttr(variable, "name", buffer);
+
+ sort_node(tree, variable);
+
+ mxmlAdd(variable, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type);
+ type = NULL;
+ }
+ else
+ mxmlNewText(type, type->child != NULL, buffer);
+ }
+ else if (type)
+ {
+ mxmlDelete(type);
+ type = NULL;
+ }
+
+ state = STATE_NONE;
+ }
+ break;
+ }
+
+#if 0
+ if (state != oldstate)
+ printf("changed states from %s to %s on receipt of character '%c'...\n",
+ states[oldstate], states[state], oldch);
+#endif /* 0 */
+ }
+
+ /*
+ * All done, return with no errors...
+ */
+
+ return (0);
}
@@ -279,5 +617,5 @@ sort_node(mxml_node_t *tree, /* I - Tree to sort into */
/*
- * End of "$Id: mxmldoc.c,v 1.3 2003/06/04 17:37:23 mike Exp $".
+ * End of "$Id: mxmldoc.c,v 1.4 2003/06/04 21:19:00 mike Exp $".
*/
diff --git a/testmxml.c b/testmxml.c
index ef15702..9a46e6b 100644
--- a/testmxml.c
+++ b/testmxml.c
@@ -1,5 +1,5 @@
/*
- * "$Id: testmxml.c,v 1.6 2003/06/04 17:37:23 mike Exp $"
+ * "$Id: testmxml.c,v 1.7 2003/06/04 21:19:00 mike Exp $"
*
* Test program for mini-XML, a small XML-like file parsing library.
*
@@ -175,23 +175,42 @@ whitespace_cb(mxml_node_t *node, /* I - Element node */
!strcmp(name, "pre") || !strcmp(name, "p") ||
!strcmp(name, "h1") || !strcmp(name, "h2") || !strcmp(name, "h3") ||
!strcmp(name, "h4") || !strcmp(name, "h5") || !strcmp(name, "h6"))
+ {
+ /*
+ * Newlines before open and after close...
+ */
+
+ if (where == MXML_WS_BEFORE_OPEN || where == MXML_WS_AFTER_CLOSE)
+ return ('\n');
+ }
+ else if (!strcmp(name, "dl") || !strcmp(name, "ol") || !strcmp(name, "ul"))
+ {
+ /*
+ * Put a newline before and after list elements...
+ */
+
return ('\n');
- else if (!strcmp(name, "li"))
+ }
+ else if (!strcmp(name, "dd") || !strcmp(name, "dt") || !strcmp(name, "li"))
{
/*
- * Put a tab before 's and a newline after 's...
+ * Put a tab before 's, 's, and 's, and a newline after them...
*/
- if (where == MXML_SAVE_OPEN_TAG)
+ if (where == MXML_WS_BEFORE_OPEN)
return ('\t');
- else
+ else if (where == MXML_WS_AFTER_CLOSE)
return ('\n');
}
- else
- return (0);
+
+ /*
+ * Return 0 for no added whitespace...
+ */
+
+ return (0);
}
/*
- * End of "$Id: testmxml.c,v 1.6 2003/06/04 17:37:23 mike Exp $".
+ * End of "$Id: testmxml.c,v 1.7 2003/06/04 21:19:00 mike Exp $".
*/