aboutsummaryrefslogtreecommitdiff
path: root/pathologist/src/minixml
diff options
context:
space:
mode:
Diffstat (limited to 'pathologist/src/minixml')
-rw-r--r--pathologist/src/minixml/Makefile.am27
-rw-r--r--pathologist/src/minixml/config.h95
-rw-r--r--pathologist/src/minixml/mxml-attr.c319
-rw-r--r--pathologist/src/minixml/mxml-entity.c460
-rw-r--r--pathologist/src/minixml/mxml-file.c3080
-rw-r--r--pathologist/src/minixml/mxml-get.c471
-rw-r--r--pathologist/src/minixml/mxml-index.c662
-rw-r--r--pathologist/src/minixml/mxml-node.c807
-rw-r--r--pathologist/src/minixml/mxml-private.c331
-rw-r--r--pathologist/src/minixml/mxml-private.h50
-rw-r--r--pathologist/src/minixml/mxml-search.c287
-rw-r--r--pathologist/src/minixml/mxml-set.c349
-rw-r--r--pathologist/src/minixml/mxml-string.c476
-rw-r--r--pathologist/src/minixml/mxmldoc.c5809
14 files changed, 13223 insertions, 0 deletions
diff --git a/pathologist/src/minixml/Makefile.am b/pathologist/src/minixml/Makefile.am
new file mode 100644
index 0000000..423fbdc
--- /dev/null
+++ b/pathologist/src/minixml/Makefile.am
@@ -0,0 +1,27 @@
1INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include
2
3if MINGW
4 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
5endif
6
7if USE_COVERAGE
8 AM_CFLAGS = --coverage -O0
9 XLIB = -lgcov
10endif
11
12lib_LTLIBRARIES = libminixml.la
13
14libminixml_la_SOURCES = \
15 mxml-attr.c \
16 mxmldoc.c \
17 mxml-entity.c \
18 mxml-file.c \
19 mxml-get.c \
20 mxml-index.c \
21 mxml-node.c \
22 mxml-private.c \
23 mxml-private.h \
24 mxml-search.c \
25 mxml-set.c \
26 mxml-string.c \
27 config.h \ No newline at end of file
diff --git a/pathologist/src/minixml/config.h b/pathologist/src/minixml/config.h
new file mode 100644
index 0000000..8bae4bf
--- /dev/null
+++ b/pathologist/src/minixml/config.h
@@ -0,0 +1,95 @@
1/*
2 * "$Id: config.h.in 408 2010-09-19 05:26:46Z mike $"
3 *
4 * Configuration file for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2010 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 */
16
17/*
18 * Include necessary headers...
19 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <stdarg.h>
25#include <ctype.h>
26
27
28/*
29 * Version number...
30 */
31
32#define MXML_VERSION ""
33
34
35/*
36 * Inline function support...
37 */
38
39#define inline
40
41
42/*
43 * Long long support...
44 */
45
46#undef HAVE_LONG_LONG
47
48
49/*
50 * Do we have the snprintf() and vsnprintf() functions?
51 */
52
53#undef HAVE_SNPRINTF
54#undef HAVE_VSNPRINTF
55
56
57/*
58 * Do we have the strXXX() functions?
59 */
60
61#undef HAVE_STRDUP
62
63
64/*
65 * Do we have threading support?
66 */
67
68#undef HAVE_PTHREAD_H
69
70
71/*
72 * Define prototypes for string functions as needed...
73 */
74
75# ifndef HAVE_STRDUP
76extern char *_mxml_strdup(const char *);
77# define strdup _mxml_strdup
78# endif /* !HAVE_STRDUP */
79
80extern char *_mxml_strdupf(const char *, ...);
81extern char *_mxml_vstrdupf(const char *, va_list);
82
83# ifndef HAVE_SNPRINTF
84extern int _mxml_snprintf(char *, size_t, const char *, ...);
85# define snprintf _mxml_snprintf
86# endif /* !HAVE_SNPRINTF */
87
88# ifndef HAVE_VSNPRINTF
89extern int _mxml_vsnprintf(char *, size_t, const char *, va_list);
90# define vsnprintf _mxml_vsnprintf
91# endif /* !HAVE_VSNPRINTF */
92
93/*
94 * End of "$Id: config.h.in 408 2010-09-19 05:26:46Z mike $".
95 */
diff --git a/pathologist/src/minixml/mxml-attr.c b/pathologist/src/minixml/mxml-attr.c
new file mode 100644
index 0000000..c9950f5
--- /dev/null
+++ b/pathologist/src/minixml/mxml-attr.c
@@ -0,0 +1,319 @@
1/*
2 * "$Id: mxml-attr.c 408 2010-09-19 05:26:46Z mike $"
3 *
4 * Attribute support code for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2010 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * mxmlElementDeleteAttr() - Delete an attribute.
19 * mxmlElementGetAttr() - Get an attribute.
20 * mxmlElementSetAttr() - Set an attribute.
21 * mxmlElementSetAttrf() - Set an attribute with a formatted value.
22 * mxml_set_attr() - Set or add an attribute name/value pair.
23 */
24
25/*
26 * Include necessary headers...
27 */
28
29#include "config.h"
30#include "mxml.h"
31
32
33/*
34 * Local functions...
35 */
36
37static int mxml_set_attr(mxml_node_t *node, const char *name,
38 char *value);
39
40
41/*
42 * 'mxmlElementDeleteAttr()' - Delete an attribute.
43 *
44 * @since Mini-XML 2.4@
45 */
46
47void
48mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */
49 const char *name)/* I - Attribute name */
50{
51 int i; /* Looping var */
52 mxml_attr_t *attr; /* Cirrent attribute */
53
54
55#ifdef DEBUG
56 fprintf(stderr, "mxmlElementDeleteAttr(node=%p, name=\"%s\")\n",
57 node, name ? name : "(null)");
58#endif /* DEBUG */
59
60 /*
61 * Range check input...
62 */
63
64 if (!node || node->type != MXML_ELEMENT || !name)
65 return;
66
67 /*
68 * Look for the attribute...
69 */
70
71 for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
72 i > 0;
73 i --, attr ++)
74 {
75#ifdef DEBUG
76 printf(" %s=\"%s\"\n", attr->name, attr->value);
77#endif /* DEBUG */
78
79 if (!strcmp(attr->name, name))
80 {
81 /*
82 * Delete this attribute...
83 */
84
85 free(attr->name);
86 free(attr->value);
87
88 i --;
89 if (i > 0)
90 memmove(attr, attr + 1, i * sizeof(mxml_attr_t));
91
92 node->value.element.num_attrs --;
93 return;
94 }
95 }
96}
97
98
99/*
100 * 'mxmlElementGetAttr()' - Get an attribute.
101 *
102 * This function returns NULL if the node is not an element or the
103 * named attribute does not exist.
104 */
105
106const char * /* O - Attribute value or NULL */
107mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */
108 const char *name) /* I - Name of attribute */
109{
110 int i; /* Looping var */
111 mxml_attr_t *attr; /* Cirrent attribute */
112
113
114#ifdef DEBUG
115 fprintf(stderr, "mxmlElementGetAttr(node=%p, name=\"%s\")\n",
116 node, name ? name : "(null)");
117#endif /* DEBUG */
118
119 /*
120 * Range check input...
121 */
122
123 if (!node || node->type != MXML_ELEMENT || !name)
124 return (NULL);
125
126 /*
127 * Look for the attribute...
128 */
129
130 for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
131 i > 0;
132 i --, attr ++)
133 {
134#ifdef DEBUG
135 printf(" %s=\"%s\"\n", attr->name, attr->value);
136#endif /* DEBUG */
137
138 if (!strcmp(attr->name, name))
139 {
140#ifdef DEBUG
141 printf(" Returning \"%s\"!\n", attr->value);
142#endif /* DEBUG */
143 return (attr->value);
144 }
145 }
146
147 /*
148 * Didn't find attribute, so return NULL...
149 */
150
151#ifdef DEBUG
152 puts(" Returning NULL!\n");
153#endif /* DEBUG */
154
155 return (NULL);
156}
157
158
159/*
160 * 'mxmlElementSetAttr()' - Set an attribute.
161 *
162 * If the named attribute already exists, the value of the attribute
163 * is replaced by the new string value. The string value is copied
164 * into the element node. This function does nothing if the node is
165 * not an element.
166 */
167
168void
169mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */
170 const char *name, /* I - Name of attribute */
171 const char *value) /* I - Attribute value */
172{
173 char *valuec; /* Copy of value */
174
175
176#ifdef DEBUG
177 fprintf(stderr, "mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n",
178 node, name ? name : "(null)", value ? value : "(null)");
179#endif /* DEBUG */
180
181 /*
182 * Range check input...
183 */
184
185 if (!node || node->type != MXML_ELEMENT || !name)
186 return;
187
188 if (value)
189 valuec = strdup(value);
190 else
191 valuec = NULL;
192
193 if (mxml_set_attr(node, name, valuec))
194 free(valuec);
195}
196
197
198/*
199 * 'mxmlElementSetAttrf()' - Set an attribute with a formatted value.
200 *
201 * If the named attribute already exists, the value of the attribute
202 * is replaced by the new formatted string. The formatted string value is
203 * copied into the element node. This function does nothing if the node
204 * is not an element.
205 *
206 * @since Mini-XML 2.3@
207 */
208
209void
210mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */
211 const char *name, /* I - Name of attribute */
212 const char *format,/* I - Printf-style attribute value */
213 ...) /* I - Additional arguments as needed */
214{
215 va_list ap; /* Argument pointer */
216 char *value; /* Value */
217
218
219#ifdef DEBUG
220 fprintf(stderr,
221 "mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n",
222 node, name ? name : "(null)", format ? format : "(null)");
223#endif /* DEBUG */
224
225 /*
226 * Range check input...
227 */
228
229 if (!node || node->type != MXML_ELEMENT || !name || !format)
230 return;
231
232 /*
233 * Format the value...
234 */
235
236 va_start(ap, format);
237 value = _mxml_vstrdupf(format, ap);
238 va_end(ap);
239
240 if (!value)
241 mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
242 name, node->value.element.name);
243 else if (mxml_set_attr(node, name, value))
244 free(value);
245}
246
247
248/*
249 * 'mxml_set_attr()' - Set or add an attribute name/value pair.
250 */
251
252static int /* O - 0 on success, -1 on failure */
253mxml_set_attr(mxml_node_t *node, /* I - Element node */
254 const char *name, /* I - Attribute name */
255 char *value) /* I - Attribute value */
256{
257 int i; /* Looping var */
258 mxml_attr_t *attr; /* New attribute */
259
260
261 /*
262 * Look for the attribute...
263 */
264
265 for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
266 i > 0;
267 i --, attr ++)
268 if (!strcmp(attr->name, name))
269 {
270 /*
271 * Free the old value as needed...
272 */
273
274 if (attr->value)
275 free(attr->value);
276
277 attr->value = value;
278
279 return (0);
280 }
281
282 /*
283 * Add a new attribute...
284 */
285
286 if (node->value.element.num_attrs == 0)
287 attr = malloc(sizeof(mxml_attr_t));
288 else
289 attr = realloc(node->value.element.attrs,
290 (node->value.element.num_attrs + 1) * sizeof(mxml_attr_t));
291
292 if (!attr)
293 {
294 mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
295 name, node->value.element.name);
296 return (-1);
297 }
298
299 node->value.element.attrs = attr;
300 attr += node->value.element.num_attrs;
301
302 if ((attr->name = strdup(name)) == NULL)
303 {
304 mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
305 name, node->value.element.name);
306 return (-1);
307 }
308
309 attr->value = value;
310
311 node->value.element.num_attrs ++;
312
313 return (0);
314}
315
316
317/*
318 * End of "$Id: mxml-attr.c 408 2010-09-19 05:26:46Z mike $".
319 */
diff --git a/pathologist/src/minixml/mxml-entity.c b/pathologist/src/minixml/mxml-entity.c
new file mode 100644
index 0000000..c5c9f61
--- /dev/null
+++ b/pathologist/src/minixml/mxml-entity.c
@@ -0,0 +1,460 @@
1/*
2 * "$Id: mxml-entity.c 408 2010-09-19 05:26:46Z mike $"
3 *
4 * Character entity support code for Mini-XML, a small XML-like
5 * file parsing library.
6 *
7 * Copyright 2003-2010 by Michael R Sweet.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Michael R Sweet and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "COPYING"
12 * which should have been included with this file. If this file is
13 * missing or damaged, see the license at:
14 *
15 * http://www.minixml.org/
16 *
17 * Contents:
18 *
19 * mxmlEntityAddCallback() - Add a callback to convert entities to
20 * Unicode.
21 * mxmlEntityGetName() - Get the name that corresponds to the
22 * character value.
23 * mxmlEntityGetValue() - Get the character corresponding to a named
24 * entity.
25 * mxmlEntityRemoveCallback() - Remove a callback.
26 * _mxml_entity_cb() - Lookup standard (X)HTML entities.
27 */
28
29/*
30 * Include necessary headers...
31 */
32
33#include "mxml-private.h"
34
35
36/*
37 * 'mxmlEntityAddCallback()' - Add a callback to convert entities to Unicode.
38 */
39
40int /* O - 0 on success, -1 on failure */
41mxmlEntityAddCallback(
42 mxml_entity_cb_t cb) /* I - Callback function to add */
43{
44 _mxml_global_t *global = _mxml_global();
45 /* Global data */
46
47
48 if (global->num_entity_cbs < (int)(sizeof(global->entity_cbs) / sizeof(global->entity_cbs[0])))
49 {
50 global->entity_cbs[global->num_entity_cbs] = cb;
51 global->num_entity_cbs ++;
52
53 return (0);
54 }
55 else
56 {
57 mxml_error("Unable to add entity callback!");
58
59 return (-1);
60 }
61}
62
63
64/*
65 * 'mxmlEntityGetName()' - Get the name that corresponds to the character value.
66 *
67 * If val does not need to be represented by a named entity, NULL is returned.
68 */
69
70const char * /* O - Entity name or NULL */
71mxmlEntityGetName(int val) /* I - Character value */
72{
73 switch (val)
74 {
75 case '&' :
76 return ("amp");
77
78 case '<' :
79 return ("lt");
80
81 case '>' :
82 return ("gt");
83
84 case '\"' :
85 return ("quot");
86
87 default :
88 return (NULL);
89 }
90}
91
92
93/*
94 * 'mxmlEntityGetValue()' - Get the character corresponding to a named entity.
95 *
96 * The entity name can also be a numeric constant. -1 is returned if the
97 * name is not known.
98 */
99
100int /* O - Character value or -1 on error */
101mxmlEntityGetValue(const char *name) /* I - Entity name */
102{
103 int i; /* Looping var */
104 int ch; /* Character value */
105 _mxml_global_t *global = _mxml_global();
106 /* Global data */
107
108
109 for (i = 0; i < global->num_entity_cbs; i ++)
110 if ((ch = (global->entity_cbs[i])(name)) >= 0)
111 return (ch);
112
113 return (-1);
114}
115
116
117/*
118 * 'mxmlEntityRemoveCallback()' - Remove a callback.
119 */
120
121void
122mxmlEntityRemoveCallback(
123 mxml_entity_cb_t cb) /* I - Callback function to remove */
124{
125 int i; /* Looping var */
126 _mxml_global_t *global = _mxml_global();
127 /* Global data */
128
129
130 for (i = 0; i < global->num_entity_cbs; i ++)
131 if (cb == global->entity_cbs[i])
132 {
133 /*
134 * Remove the callback...
135 */
136
137 global->num_entity_cbs --;
138
139 if (i < global->num_entity_cbs)
140 memmove(global->entity_cbs + i, global->entity_cbs + i + 1,
141 (global->num_entity_cbs - i) * sizeof(global->entity_cbs[0]));
142
143 return;
144 }
145}
146
147
148/*
149 * '_mxml_entity_cb()' - Lookup standard (X)HTML entities.
150 */
151
152int /* O - Unicode value or -1 */
153_mxml_entity_cb(const char *name) /* I - Entity name */
154{
155 int diff, /* Difference between names */
156 current, /* Current entity in search */
157 first, /* First entity in search */
158 last; /* Last entity in search */
159 static const struct
160 {
161 const char *name; /* Entity name */
162 int val; /* Character value */
163 } entities[] =
164 {
165 { "AElig", 198 },
166 { "Aacute", 193 },
167 { "Acirc", 194 },
168 { "Agrave", 192 },
169 { "Alpha", 913 },
170 { "Aring", 197 },
171 { "Atilde", 195 },
172 { "Auml", 196 },
173 { "Beta", 914 },
174 { "Ccedil", 199 },
175 { "Chi", 935 },
176 { "Dagger", 8225 },
177 { "Delta", 916 },
178 { "Dstrok", 208 },
179 { "ETH", 208 },
180 { "Eacute", 201 },
181 { "Ecirc", 202 },
182 { "Egrave", 200 },
183 { "Epsilon", 917 },
184 { "Eta", 919 },
185 { "Euml", 203 },
186 { "Gamma", 915 },
187 { "Iacute", 205 },
188 { "Icirc", 206 },
189 { "Igrave", 204 },
190 { "Iota", 921 },
191 { "Iuml", 207 },
192 { "Kappa", 922 },
193 { "Lambda", 923 },
194 { "Mu", 924 },
195 { "Ntilde", 209 },
196 { "Nu", 925 },
197 { "OElig", 338 },
198 { "Oacute", 211 },
199 { "Ocirc", 212 },
200 { "Ograve", 210 },
201 { "Omega", 937 },
202 { "Omicron", 927 },
203 { "Oslash", 216 },
204 { "Otilde", 213 },
205 { "Ouml", 214 },
206 { "Phi", 934 },
207 { "Pi", 928 },
208 { "Prime", 8243 },
209 { "Psi", 936 },
210 { "Rho", 929 },
211 { "Scaron", 352 },
212 { "Sigma", 931 },
213 { "THORN", 222 },
214 { "Tau", 932 },
215 { "Theta", 920 },
216 { "Uacute", 218 },
217 { "Ucirc", 219 },
218 { "Ugrave", 217 },
219 { "Upsilon", 933 },
220 { "Uuml", 220 },
221 { "Xi", 926 },
222 { "Yacute", 221 },
223 { "Yuml", 376 },
224 { "Zeta", 918 },
225 { "aacute", 225 },
226 { "acirc", 226 },
227 { "acute", 180 },
228 { "aelig", 230 },
229 { "agrave", 224 },
230 { "alefsym", 8501 },
231 { "alpha", 945 },
232 { "amp", '&' },
233 { "and", 8743 },
234 { "ang", 8736 },
235 { "apos", '\'' },
236 { "aring", 229 },
237 { "asymp", 8776 },
238 { "atilde", 227 },
239 { "auml", 228 },
240 { "bdquo", 8222 },
241 { "beta", 946 },
242 { "brkbar", 166 },
243 { "brvbar", 166 },
244 { "bull", 8226 },
245 { "cap", 8745 },
246 { "ccedil", 231 },
247 { "cedil", 184 },
248 { "cent", 162 },
249 { "chi", 967 },
250 { "circ", 710 },
251 { "clubs", 9827 },
252 { "cong", 8773 },
253 { "copy", 169 },
254 { "crarr", 8629 },
255 { "cup", 8746 },
256 { "curren", 164 },
257 { "dArr", 8659 },
258 { "dagger", 8224 },
259 { "darr", 8595 },
260 { "deg", 176 },
261 { "delta", 948 },
262 { "diams", 9830 },
263 { "die", 168 },
264 { "divide", 247 },
265 { "eacute", 233 },
266 { "ecirc", 234 },
267 { "egrave", 232 },
268 { "empty", 8709 },
269 { "emsp", 8195 },
270 { "ensp", 8194 },
271 { "epsilon", 949 },
272 { "equiv", 8801 },
273 { "eta", 951 },
274 { "eth", 240 },
275 { "euml", 235 },
276 { "euro", 8364 },
277 { "exist", 8707 },
278 { "fnof", 402 },
279 { "forall", 8704 },
280 { "frac12", 189 },
281 { "frac14", 188 },
282 { "frac34", 190 },
283 { "frasl", 8260 },
284 { "gamma", 947 },
285 { "ge", 8805 },
286 { "gt", '>' },
287 { "hArr", 8660 },
288 { "harr", 8596 },
289 { "hearts", 9829 },
290 { "hellip", 8230 },
291 { "hibar", 175 },
292 { "iacute", 237 },
293 { "icirc", 238 },
294 { "iexcl", 161 },
295 { "igrave", 236 },
296 { "image", 8465 },
297 { "infin", 8734 },
298 { "int", 8747 },
299 { "iota", 953 },
300 { "iquest", 191 },
301 { "isin", 8712 },
302 { "iuml", 239 },
303 { "kappa", 954 },
304 { "lArr", 8656 },
305 { "lambda", 955 },
306 { "lang", 9001 },
307 { "laquo", 171 },
308 { "larr", 8592 },
309 { "lceil", 8968 },
310 { "ldquo", 8220 },
311 { "le", 8804 },
312 { "lfloor", 8970 },
313 { "lowast", 8727 },
314 { "loz", 9674 },
315 { "lrm", 8206 },
316 { "lsaquo", 8249 },
317 { "lsquo", 8216 },
318 { "lt", '<' },
319 { "macr", 175 },
320 { "mdash", 8212 },
321 { "micro", 181 },
322 { "middot", 183 },
323 { "minus", 8722 },
324 { "mu", 956 },
325 { "nabla", 8711 },
326 { "nbsp", 160 },
327 { "ndash", 8211 },
328 { "ne", 8800 },
329 { "ni", 8715 },
330 { "not", 172 },
331 { "notin", 8713 },
332 { "nsub", 8836 },
333 { "ntilde", 241 },
334 { "nu", 957 },
335 { "oacute", 243 },
336 { "ocirc", 244 },
337 { "oelig", 339 },
338 { "ograve", 242 },
339 { "oline", 8254 },
340 { "omega", 969 },
341 { "omicron", 959 },
342 { "oplus", 8853 },
343 { "or", 8744 },
344 { "ordf", 170 },
345 { "ordm", 186 },
346 { "oslash", 248 },
347 { "otilde", 245 },
348 { "otimes", 8855 },
349 { "ouml", 246 },
350 { "para", 182 },
351 { "part", 8706 },
352 { "permil", 8240 },
353 { "perp", 8869 },
354 { "phi", 966 },
355 { "pi", 960 },
356 { "piv", 982 },
357 { "plusmn", 177 },
358 { "pound", 163 },
359 { "prime", 8242 },
360 { "prod", 8719 },
361 { "prop", 8733 },
362 { "psi", 968 },
363 { "quot", '\"' },
364 { "rArr", 8658 },
365 { "radic", 8730 },
366 { "rang", 9002 },
367 { "raquo", 187 },
368 { "rarr", 8594 },
369 { "rceil", 8969 },
370 { "rdquo", 8221 },
371 { "real", 8476 },
372 { "reg", 174 },
373 { "rfloor", 8971 },
374 { "rho", 961 },
375 { "rlm", 8207 },
376 { "rsaquo", 8250 },
377 { "rsquo", 8217 },
378 { "sbquo", 8218 },
379 { "scaron", 353 },
380 { "sdot", 8901 },
381 { "sect", 167 },
382 { "shy", 173 },
383 { "sigma", 963 },
384 { "sigmaf", 962 },
385 { "sim", 8764 },
386 { "spades", 9824 },
387 { "sub", 8834 },
388 { "sube", 8838 },
389 { "sum", 8721 },
390 { "sup", 8835 },
391 { "sup1", 185 },
392 { "sup2", 178 },
393 { "sup3", 179 },
394 { "supe", 8839 },
395 { "szlig", 223 },
396 { "tau", 964 },
397 { "there4", 8756 },
398 { "theta", 952 },
399 { "thetasym", 977 },
400 { "thinsp", 8201 },
401 { "thorn", 254 },
402 { "tilde", 732 },
403 { "times", 215 },
404 { "trade", 8482 },
405 { "uArr", 8657 },
406 { "uacute", 250 },
407 { "uarr", 8593 },
408 { "ucirc", 251 },
409 { "ugrave", 249 },
410 { "uml", 168 },
411 { "upsih", 978 },
412 { "upsilon", 965 },
413 { "uuml", 252 },
414 { "weierp", 8472 },
415 { "xi", 958 },
416 { "yacute", 253 },
417 { "yen", 165 },
418 { "yuml", 255 },
419 { "zeta", 950 },
420 { "zwj", 8205 },
421 { "zwnj", 8204 }
422 };
423
424
425 /*
426 * Do a binary search for the named entity...
427 */
428
429 first = 0;
430 last = (int)(sizeof(entities) / sizeof(entities[0]) - 1);
431
432 while ((last - first) > 1)
433 {
434 current = (first + last) / 2;
435
436 if ((diff = strcmp(name, entities[current].name)) == 0)
437 return (entities[current].val);
438 else if (diff < 0)
439 last = current;
440 else
441 first = current;
442 }
443
444 /*
445 * If we get here, there is a small chance that there is still
446 * a match; check first and last...
447 */
448
449 if (!strcmp(name, entities[first].name))
450 return (entities[first].val);
451 else if (!strcmp(name, entities[last].name))
452 return (entities[last].val);
453 else
454 return (-1);
455}
456
457
458/*
459 * End of "$Id: mxml-entity.c 408 2010-09-19 05:26:46Z mike $".
460 */
diff --git a/pathologist/src/minixml/mxml-file.c b/pathologist/src/minixml/mxml-file.c
new file mode 100644
index 0000000..9927040
--- /dev/null
+++ b/pathologist/src/minixml/mxml-file.c
@@ -0,0 +1,3080 @@
1/*
2 * "$Id: mxml-file.c 438 2011-03-24 05:47:51Z mike $"
3 *
4 * File loading code for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2011 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * mxmlLoadFd() - Load a file descriptor into an XML node tree.
19 * mxmlLoadFile() - Load a file into an XML node tree.
20 * mxmlLoadString() - Load a string into an XML node tree.
21 * mxmlSaveAllocString() - Save an XML tree to an allocated string.
22 * mxmlSaveFd() - Save an XML tree to a file descriptor.
23 * mxmlSaveFile() - Save an XML tree to a file.
24 * mxmlSaveString() - Save an XML node tree to a string.
25 * mxmlSAXLoadFd() - Load a file descriptor into an XML node tree
26 * using a SAX callback.
27 * mxmlSAXLoadFile() - Load a file into an XML node tree
28 * using a SAX callback.
29 * mxmlSAXLoadString() - Load a string into an XML node tree
30 * using a SAX callback.
31 * mxmlSetCustomHandlers() - Set the handling functions for custom data.
32 * mxmlSetErrorCallback() - Set the error message callback.
33 * mxmlSetWrapMargin() - Set the wrap margin when saving XML data.
34 * mxml_add_char() - Add a character to a buffer, expanding as needed.
35 * mxml_fd_getc() - Read a character from a file descriptor.
36 * mxml_fd_putc() - Write a character to a file descriptor.
37 * mxml_fd_read() - Read a buffer of data from a file descriptor.
38 * mxml_fd_write() - Write a buffer of data to a file descriptor.
39 * mxml_file_getc() - Get a character from a file.
40 * mxml_file_putc() - Write a character to a file.
41 * mxml_get_entity() - Get the character corresponding to an entity...
42 * mxml_load_data() - Load data into an XML node tree.
43 * mxml_parse_element() - Parse an element for any attributes...
44 * mxml_string_getc() - Get a character from a string.
45 * mxml_string_putc() - Write a character to a string.
46 * mxml_write_name() - Write a name string.
47 * mxml_write_node() - Save an XML node to a file.
48 * mxml_write_string() - Write a string, escaping & and < as needed.
49 * mxml_write_ws() - Do whitespace callback...
50 */
51
52/*
53 * Include necessary headers...
54 */
55
56#ifndef WIN32
57# include <unistd.h>
58#endif /* !WIN32 */
59#include "mxml-private.h"
60
61
62/*
63 * Character encoding...
64 */
65
66#define ENCODE_UTF8 0 /* UTF-8 */
67#define ENCODE_UTF16BE 1 /* UTF-16 Big-Endian */
68#define ENCODE_UTF16LE 2 /* UTF-16 Little-Endian */
69
70
71/*
72 * Macro to test for a bad XML character...
73 */
74
75#define mxml_bad_char(ch) ((ch) < ' ' && (ch) != '\n' && (ch) != '\r' && (ch) != '\t')
76
77
78/*
79 * Types and structures...
80 */
81
82typedef int (*_mxml_getc_cb_t)(void *, int *);
83typedef int (*_mxml_putc_cb_t)(int, void *);
84
85typedef struct _mxml_fdbuf_s /**** File descriptor buffer ****/
86{
87 int fd; /* File descriptor */
88 unsigned char *current, /* Current position in buffer */
89 *end, /* End of buffer */
90 buffer[8192]; /* Character buffer */
91} _mxml_fdbuf_t;
92
93
94/*
95 * Local functions...
96 */
97
98static int mxml_add_char(int ch, char **ptr, char **buffer,
99 int *bufsize);
100static int mxml_fd_getc(void *p, int *encoding);
101static int mxml_fd_putc(int ch, void *p);
102static int mxml_fd_read(_mxml_fdbuf_t *buf);
103static int mxml_fd_write(_mxml_fdbuf_t *buf);
104static int mxml_file_getc(void *p, int *encoding);
105static int mxml_file_putc(int ch, void *p);
106static int mxml_get_entity(mxml_node_t *parent, void *p,
107 int *encoding,
108 _mxml_getc_cb_t getc_cb);
109static inline int mxml_isspace(int ch)
110 {
111 return (ch == ' ' || ch == '\t' || ch == '\r' ||
112 ch == '\n');
113 }
114static mxml_node_t *mxml_load_data(mxml_node_t *top, void *p,
115 mxml_load_cb_t cb,
116 _mxml_getc_cb_t getc_cb,
117 mxml_sax_cb_t sax_cb, void *sax_data);
118static int mxml_parse_element(mxml_node_t *node, void *p,
119 int *encoding,
120 _mxml_getc_cb_t getc_cb);
121static int mxml_string_getc(void *p, int *encoding);
122static int mxml_string_putc(int ch, void *p);
123static int mxml_write_name(const char *s, void *p,
124 _mxml_putc_cb_t putc_cb);
125static int mxml_write_node(mxml_node_t *node, void *p,
126 mxml_save_cb_t cb, int col,
127 _mxml_putc_cb_t putc_cb,
128 _mxml_global_t *global);
129static int mxml_write_string(const char *s, void *p,
130 _mxml_putc_cb_t putc_cb);
131static int mxml_write_ws(mxml_node_t *node, void *p,
132 mxml_save_cb_t cb, int ws,
133 int col, _mxml_putc_cb_t putc_cb);
134
135
136/*
137 * 'mxmlLoadFd()' - Load a file descriptor into an XML node tree.
138 *
139 * The nodes in the specified file are added to the specified top node.
140 * If no top node is provided, the XML file MUST be well-formed with a
141 * single parent node like <?xml> for the entire file. The callback
142 * function returns the value type that should be used for child nodes.
143 * If MXML_NO_CALLBACK is specified then all child nodes will be either
144 * MXML_ELEMENT or MXML_TEXT nodes.
145 *
146 * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
147 * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
148 * child nodes of the specified type.
149 */
150
151mxml_node_t * /* O - First node or NULL if the file could not be read. */
152mxmlLoadFd(mxml_node_t *top, /* I - Top node */
153 int fd, /* I - File descriptor to read from */
154 mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */
155{
156 _mxml_fdbuf_t buf; /* File descriptor buffer */
157
158
159 /*
160 * Initialize the file descriptor buffer...
161 */
162
163 buf.fd = fd;
164 buf.current = buf.buffer;
165 buf.end = buf.buffer;
166
167 /*
168 * Read the XML data...
169 */
170
171 return (mxml_load_data(top, &buf, cb, mxml_fd_getc, MXML_NO_CALLBACK, NULL));
172}
173
174
175/*
176 * 'mxmlLoadFile()' - Load a file into an XML node tree.
177 *
178 * The nodes in the specified file are added to the specified top node.
179 * If no top node is provided, the XML file MUST be well-formed with a
180 * single parent node like <?xml> for the entire file. The callback
181 * function returns the value type that should be used for child nodes.
182 * If MXML_NO_CALLBACK is specified then all child nodes will be either
183 * MXML_ELEMENT or MXML_TEXT nodes.
184 *
185 * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
186 * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
187 * child nodes of the specified type.
188 */
189
190mxml_node_t * /* O - First node or NULL if the file could not be read. */
191mxmlLoadFile(mxml_node_t *top, /* I - Top node */
192 FILE *fp, /* I - File to read from */
193 mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */
194{
195 /*
196 * Read the XML data...
197 */
198
199 return (mxml_load_data(top, fp, cb, mxml_file_getc, MXML_NO_CALLBACK, NULL));
200}
201
202
203/*
204 * 'mxmlLoadString()' - Load a string into an XML node tree.
205 *
206 * The nodes in the specified string are added to the specified top node.
207 * If no top node is provided, the XML string MUST be well-formed with a
208 * single parent node like <?xml> for the entire string. The callback
209 * function returns the value type that should be used for child nodes.
210 * If MXML_NO_CALLBACK is specified then all child nodes will be either
211 * MXML_ELEMENT or MXML_TEXT nodes.
212 *
213 * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
214 * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
215 * child nodes of the specified type.
216 */
217
218mxml_node_t * /* O - First node or NULL if the string has errors. */
219mxmlLoadString(mxml_node_t *top, /* I - Top node */
220 const char *s, /* I - String to load */
221 mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */
222{
223 /*
224 * Read the XML data...
225 */
226
227 return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, MXML_NO_CALLBACK,
228 NULL));
229}
230
231
232/*
233 * 'mxmlSaveAllocString()' - Save an XML tree to an allocated string.
234 *
235 * This function returns a pointer to a string containing the textual
236 * representation of the XML node tree. The string should be freed
237 * using the free() function when you are done with it. NULL is returned
238 * if the node would produce an empty string or if the string cannot be
239 * allocated.
240 *
241 * The callback argument specifies a function that returns a whitespace
242 * string or NULL before and after each element. If MXML_NO_CALLBACK
243 * is specified, whitespace will only be added before MXML_TEXT nodes
244 * with leading whitespace and before attribute names inside opening
245 * element tags.
246 */
247
248char * /* O - Allocated string or NULL */
249mxmlSaveAllocString(
250 mxml_node_t *node, /* I - Node to write */
251 mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
252{
253 int bytes; /* Required bytes */
254 char buffer[8192]; /* Temporary buffer */
255 char *s; /* Allocated string */
256
257
258 /*
259 * Write the node to the temporary buffer...
260 */
261
262 bytes = mxmlSaveString(node, buffer, sizeof(buffer), cb);
263
264 if (bytes <= 0)
265 return (NULL);
266
267 if (bytes < (int)(sizeof(buffer) - 1))
268 {
269 /*
270 * Node fit inside the buffer, so just duplicate that string and
271 * return...
272 */
273
274 return (strdup(buffer));
275 }
276
277 /*
278 * Allocate a buffer of the required size and save the node to the
279 * new buffer...
280 */
281
282 if ((s = malloc(bytes + 1)) == NULL)
283 return (NULL);
284
285 mxmlSaveString(node, s, bytes + 1, cb);
286
287 /*
288 * Return the allocated string...
289 */
290
291 return (s);
292}
293
294
295/*
296 * 'mxmlSaveFd()' - Save an XML tree to a file descriptor.
297 *
298 * The callback argument specifies a function that returns a whitespace
299 * string or NULL before and after each element. If MXML_NO_CALLBACK
300 * is specified, whitespace will only be added before MXML_TEXT nodes
301 * with leading whitespace and before attribute names inside opening
302 * element tags.
303 */
304
305int /* O - 0 on success, -1 on error. */
306mxmlSaveFd(mxml_node_t *node, /* I - Node to write */
307 int fd, /* I - File descriptor to write to */
308 mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
309{
310 int col; /* Final column */
311 _mxml_fdbuf_t buf; /* File descriptor buffer */
312 _mxml_global_t *global = _mxml_global();
313 /* Global data */
314
315
316 /*
317 * Initialize the file descriptor buffer...
318 */
319
320 buf.fd = fd;
321 buf.current = buf.buffer;
322 buf.end = buf.buffer + sizeof(buf.buffer);
323
324 /*
325 * Write the node...
326 */
327
328 if ((col = mxml_write_node(node, &buf, cb, 0, mxml_fd_putc, global)) < 0)
329 return (-1);
330
331 if (col > 0)
332 if (mxml_fd_putc('\n', &buf) < 0)
333 return (-1);
334
335 /*
336 * Flush and return...
337 */
338
339 return (mxml_fd_write(&buf));
340}
341
342
343/*
344 * 'mxmlSaveFile()' - Save an XML tree to a file.
345 *
346 * The callback argument specifies a function that returns a whitespace
347 * string or NULL before and after each element. If MXML_NO_CALLBACK
348 * is specified, whitespace will only be added before MXML_TEXT nodes
349 * with leading whitespace and before attribute names inside opening
350 * element tags.
351 */
352
353int /* O - 0 on success, -1 on error. */
354mxmlSaveFile(mxml_node_t *node, /* I - Node to write */
355 FILE *fp, /* I - File to write to */
356 mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
357{
358 int col; /* Final column */
359 _mxml_global_t *global = _mxml_global();
360 /* Global data */
361
362
363 /*
364 * Write the node...
365 */
366
367 if ((col = mxml_write_node(node, fp, cb, 0, mxml_file_putc, global)) < 0)
368 return (-1);
369
370 if (col > 0)
371 if (putc('\n', fp) < 0)
372 return (-1);
373
374 /*
375 * Return 0 (success)...
376 */
377
378 return (0);
379}
380
381
382/*
383 * 'mxmlSaveString()' - Save an XML node tree to a string.
384 *
385 * This function returns the total number of bytes that would be
386 * required for the string but only copies (bufsize - 1) characters
387 * into the specified buffer.
388 *
389 * The callback argument specifies a function that returns a whitespace
390 * string or NULL before and after each element. If MXML_NO_CALLBACK
391 * is specified, whitespace will only be added before MXML_TEXT nodes
392 * with leading whitespace and before attribute names inside opening
393 * element tags.
394 */
395
396int /* O - Size of string */
397mxmlSaveString(mxml_node_t *node, /* I - Node to write */
398 char *buffer, /* I - String buffer */
399 int bufsize, /* I - Size of string buffer */
400 mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
401{
402 int col; /* Final column */
403 char *ptr[2]; /* Pointers for putc_cb */
404 _mxml_global_t *global = _mxml_global();
405 /* Global data */
406
407
408 /*
409 * Write the node...
410 */
411
412 ptr[0] = buffer;
413 ptr[1] = buffer + bufsize;
414
415 if ((col = mxml_write_node(node, ptr, cb, 0, mxml_string_putc, global)) < 0)
416 return (-1);
417
418 if (col > 0)
419 mxml_string_putc('\n', ptr);
420
421 /*
422 * Nul-terminate the buffer...
423 */
424
425 if (ptr[0] >= ptr[1])
426 buffer[bufsize - 1] = '\0';
427 else
428 ptr[0][0] = '\0';
429
430 /*
431 * Return the number of characters...
432 */
433
434 return (ptr[0] - buffer);
435}
436
437
438/*
439 * 'mxmlSAXLoadFd()' - Load a file descriptor into an XML node tree
440 * using a SAX callback.
441 *
442 * The nodes in the specified file are added to the specified top node.
443 * If no top node is provided, the XML file MUST be well-formed with a
444 * single parent node like <?xml> for the entire file. The callback
445 * function returns the value type that should be used for child nodes.
446 * If MXML_NO_CALLBACK is specified then all child nodes will be either
447 * MXML_ELEMENT or MXML_TEXT nodes.
448 *
449 * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
450 * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
451 * child nodes of the specified type.
452 *
453 * The SAX callback must call mxmlRetain() for any nodes that need to
454 * be kept for later use. Otherwise, nodes are deleted when the parent
455 * node is closed or after each data, comment, CDATA, or directive node.
456 *
457 * @since Mini-XML 2.3@
458 */
459
460mxml_node_t * /* O - First node or NULL if the file could not be read. */
461mxmlSAXLoadFd(mxml_node_t *top, /* I - Top node */
462 int fd, /* I - File descriptor to read from */
463 mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
464 mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
465 void *sax_data) /* I - SAX user data */
466{
467 _mxml_fdbuf_t buf; /* File descriptor buffer */
468
469
470 /*
471 * Initialize the file descriptor buffer...
472 */
473
474 buf.fd = fd;
475 buf.current = buf.buffer;
476 buf.end = buf.buffer;
477
478 /*
479 * Read the XML data...
480 */
481
482 return (mxml_load_data(top, &buf, cb, mxml_fd_getc, sax_cb, sax_data));
483}
484
485
486/*
487 * 'mxmlSAXLoadFile()' - Load a file into an XML node tree
488 * using a SAX callback.
489 *
490 * The nodes in the specified file are added to the specified top node.
491 * If no top node is provided, the XML file MUST be well-formed with a
492 * single parent node like <?xml> for the entire file. The callback
493 * function returns the value type that should be used for child nodes.
494 * If MXML_NO_CALLBACK is specified then all child nodes will be either
495 * MXML_ELEMENT or MXML_TEXT nodes.
496 *
497 * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
498 * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
499 * child nodes of the specified type.
500 *
501 * The SAX callback must call mxmlRetain() for any nodes that need to
502 * be kept for later use. Otherwise, nodes are deleted when the parent
503 * node is closed or after each data, comment, CDATA, or directive node.
504 *
505 * @since Mini-XML 2.3@
506 */
507
508mxml_node_t * /* O - First node or NULL if the file could not be read. */
509mxmlSAXLoadFile(
510 mxml_node_t *top, /* I - Top node */
511 FILE *fp, /* I - File to read from */
512 mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
513 mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
514 void *sax_data) /* I - SAX user data */
515{
516 /*
517 * Read the XML data...
518 */
519
520 return (mxml_load_data(top, fp, cb, mxml_file_getc, sax_cb, sax_data));
521}
522
523
524/*
525 * 'mxmlSAXLoadString()' - Load a string into an XML node tree
526 * using a SAX callback.
527 *
528 * The nodes in the specified string are added to the specified top node.
529 * If no top node is provided, the XML string MUST be well-formed with a
530 * single parent node like <?xml> for the entire string. The callback
531 * function returns the value type that should be used for child nodes.
532 * If MXML_NO_CALLBACK is specified then all child nodes will be either
533 * MXML_ELEMENT or MXML_TEXT nodes.
534 *
535 * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
536 * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
537 * child nodes of the specified type.
538 *
539 * The SAX callback must call mxmlRetain() for any nodes that need to
540 * be kept for later use. Otherwise, nodes are deleted when the parent
541 * node is closed or after each data, comment, CDATA, or directive node.
542 *
543 * @since Mini-XML 2.3@
544 */
545
546mxml_node_t * /* O - First node or NULL if the string has errors. */
547mxmlSAXLoadString(
548 mxml_node_t *top, /* I - Top node */
549 const char *s, /* I - String to load */
550 mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
551 mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
552 void *sax_data) /* I - SAX user data */
553{
554 /*
555 * Read the XML data...
556 */
557
558 return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, sax_cb, sax_data));
559}
560
561
562/*
563 * 'mxmlSetCustomHandlers()' - Set the handling functions for custom data.
564 *
565 * The load function accepts a node pointer and a data string and must
566 * return 0 on success and non-zero on error.
567 *
568 * The save function accepts a node pointer and must return a malloc'd
569 * string on success and NULL on error.
570 *
571 */
572
573void
574mxmlSetCustomHandlers(
575 mxml_custom_load_cb_t load, /* I - Load function */
576 mxml_custom_save_cb_t save) /* I - Save function */
577{
578 _mxml_global_t *global = _mxml_global();
579 /* Global data */
580
581
582 global->custom_load_cb = load;
583 global->custom_save_cb = save;
584}
585
586
587/*
588 * 'mxmlSetErrorCallback()' - Set the error message callback.
589 */
590
591void
592mxmlSetErrorCallback(mxml_error_cb_t cb)/* I - Error callback function */
593{
594 _mxml_global_t *global = _mxml_global();
595 /* Global data */
596
597
598 global->error_cb = cb;
599}
600
601
602/*
603 * 'mxmlSetWrapMargin()' - Set the wrap margin when saving XML data.
604 *
605 * Wrapping is disabled when "column" is 0.
606 *
607 * @since Mini-XML 2.3@
608 */
609
610void
611mxmlSetWrapMargin(int column) /* I - Column for wrapping, 0 to disable wrapping */
612{
613 _mxml_global_t *global = _mxml_global();
614 /* Global data */
615
616
617 global->wrap = column;
618}
619
620
621/*
622 * 'mxml_add_char()' - Add a character to a buffer, expanding as needed.
623 */
624
625static int /* O - 0 on success, -1 on error */
626mxml_add_char(int ch, /* I - Character to add */
627 char **bufptr, /* IO - Current position in buffer */
628 char **buffer, /* IO - Current buffer */
629 int *bufsize) /* IO - Current buffer size */
630{
631 char *newbuffer; /* New buffer value */
632
633
634 if (*bufptr >= (*buffer + *bufsize - 4))
635 {
636 /*
637 * Increase the size of the buffer...
638 */
639
640 if (*bufsize < 1024)
641 (*bufsize) *= 2;
642 else
643 (*bufsize) += 1024;
644
645 if ((newbuffer = realloc(*buffer, *bufsize)) == NULL)
646 {
647 free(*buffer);
648
649 mxml_error("Unable to expand string buffer to %d bytes!", *bufsize);
650
651 return (-1);
652 }
653
654 *bufptr = newbuffer + (*bufptr - *buffer);
655 *buffer = newbuffer;
656 }
657
658 if (ch < 0x80)
659 {
660 /*
661 * Single byte ASCII...
662 */
663
664 *(*bufptr)++ = ch;
665 }
666 else if (ch < 0x800)
667 {
668 /*
669 * Two-byte UTF-8...
670 */
671
672 *(*bufptr)++ = 0xc0 | (ch >> 6);
673 *(*bufptr)++ = 0x80 | (ch & 0x3f);
674 }
675 else if (ch < 0x10000)
676 {
677 /*
678 * Three-byte UTF-8...
679 */
680
681 *(*bufptr)++ = 0xe0 | (ch >> 12);
682 *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
683 *(*bufptr)++ = 0x80 | (ch & 0x3f);
684 }
685 else
686 {
687 /*
688 * Four-byte UTF-8...
689 */
690
691 *(*bufptr)++ = 0xf0 | (ch >> 18);
692 *(*bufptr)++ = 0x80 | ((ch >> 12) & 0x3f);
693 *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
694 *(*bufptr)++ = 0x80 | (ch & 0x3f);
695 }
696
697 return (0);
698}
699
700
701/*
702 * 'mxml_fd_getc()' - Read a character from a file descriptor.
703 */
704
705static int /* O - Character or EOF */
706mxml_fd_getc(void *p, /* I - File descriptor buffer */
707 int *encoding) /* IO - Encoding */
708{
709 _mxml_fdbuf_t *buf; /* File descriptor buffer */
710 int ch, /* Current character */
711 temp; /* Temporary character */
712
713
714 /*
715 * Grab the next character in the buffer...
716 */
717
718 buf = (_mxml_fdbuf_t *)p;
719
720 if (buf->current >= buf->end)
721 if (mxml_fd_read(buf) < 0)
722 return (EOF);
723
724 ch = *(buf->current)++;
725
726 switch (*encoding)
727 {
728 case ENCODE_UTF8 :
729 /*
730 * Got a UTF-8 character; convert UTF-8 to Unicode and return...
731 */
732
733 if (!(ch & 0x80))
734 {
735#if DEBUG > 1
736 printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
737#endif /* DEBUG > 1 */
738
739 if (mxml_bad_char(ch))
740 {
741 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
742 ch);
743 return (EOF);
744 }
745
746 return (ch);
747 }
748 else if (ch == 0xfe)
749 {
750 /*
751 * UTF-16 big-endian BOM?
752 */
753
754 if (buf->current >= buf->end)
755 if (mxml_fd_read(buf) < 0)
756 return (EOF);
757
758 ch = *(buf->current)++;
759
760 if (ch != 0xff)
761 return (EOF);
762
763 *encoding = ENCODE_UTF16BE;
764
765 return (mxml_fd_getc(p, encoding));
766 }
767 else if (ch == 0xff)
768 {
769 /*
770 * UTF-16 little-endian BOM?
771 */
772
773 if (buf->current >= buf->end)
774 if (mxml_fd_read(buf) < 0)
775 return (EOF);
776
777 ch = *(buf->current)++;
778
779 if (ch != 0xfe)
780 return (EOF);
781
782 *encoding = ENCODE_UTF16LE;
783
784 return (mxml_fd_getc(p, encoding));
785 }
786 else if ((ch & 0xe0) == 0xc0)
787 {
788 /*
789 * Two-byte value...
790 */
791
792 if (buf->current >= buf->end)
793 if (mxml_fd_read(buf) < 0)
794 return (EOF);
795
796 temp = *(buf->current)++;
797
798 if ((temp & 0xc0) != 0x80)
799 return (EOF);
800
801 ch = ((ch & 0x1f) << 6) | (temp & 0x3f);
802
803 if (ch < 0x80)
804 {
805 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
806 return (EOF);
807 }
808 }
809 else if ((ch & 0xf0) == 0xe0)
810 {
811 /*
812 * Three-byte value...
813 */
814
815 if (buf->current >= buf->end)
816 if (mxml_fd_read(buf) < 0)
817 return (EOF);
818
819 temp = *(buf->current)++;
820
821 if ((temp & 0xc0) != 0x80)
822 return (EOF);
823
824 ch = ((ch & 0x0f) << 6) | (temp & 0x3f);
825
826 if (buf->current >= buf->end)
827 if (mxml_fd_read(buf) < 0)
828 return (EOF);
829
830 temp = *(buf->current)++;
831
832 if ((temp & 0xc0) != 0x80)
833 return (EOF);
834
835 ch = (ch << 6) | (temp & 0x3f);
836
837 if (ch < 0x800)
838 {
839 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
840 return (EOF);
841 }
842
843 /*
844 * Ignore (strip) Byte Order Mark (BOM)...
845 */
846
847 if (ch == 0xfeff)
848 return (mxml_fd_getc(p, encoding));
849 }
850 else if ((ch & 0xf8) == 0xf0)
851 {
852 /*
853 * Four-byte value...
854 */
855
856 if (buf->current >= buf->end)
857 if (mxml_fd_read(buf) < 0)
858 return (EOF);
859
860 temp = *(buf->current)++;
861
862 if ((temp & 0xc0) != 0x80)
863 return (EOF);
864
865 ch = ((ch & 0x07) << 6) | (temp & 0x3f);
866
867 if (buf->current >= buf->end)
868 if (mxml_fd_read(buf) < 0)
869 return (EOF);
870
871 temp = *(buf->current)++;
872
873 if ((temp & 0xc0) != 0x80)
874 return (EOF);
875
876 ch = (ch << 6) | (temp & 0x3f);
877
878 if (buf->current >= buf->end)
879 if (mxml_fd_read(buf) < 0)
880 return (EOF);
881
882 temp = *(buf->current)++;
883
884 if ((temp & 0xc0) != 0x80)
885 return (EOF);
886
887 ch = (ch << 6) | (temp & 0x3f);
888
889 if (ch < 0x10000)
890 {
891 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
892 return (EOF);
893 }
894 }
895 else
896 return (EOF);
897 break;
898
899 case ENCODE_UTF16BE :
900 /*
901 * Read UTF-16 big-endian char...
902 */
903
904 if (buf->current >= buf->end)
905 if (mxml_fd_read(buf) < 0)
906 return (EOF);
907
908 temp = *(buf->current)++;
909
910 ch = (ch << 8) | temp;
911
912 if (mxml_bad_char(ch))
913 {
914 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
915 ch);
916 return (EOF);
917 }
918 else if (ch >= 0xd800 && ch <= 0xdbff)
919 {
920 /*
921 * Multi-word UTF-16 char...
922 */
923
924 int lch;
925
926 if (buf->current >= buf->end)
927 if (mxml_fd_read(buf) < 0)
928 return (EOF);
929
930 lch = *(buf->current)++;
931
932 if (buf->current >= buf->end)
933 if (mxml_fd_read(buf) < 0)
934 return (EOF);
935
936 temp = *(buf->current)++;
937
938 lch = (lch << 8) | temp;
939
940 if (lch < 0xdc00 || lch >= 0xdfff)
941 return (EOF);
942
943 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
944 }
945 break;
946
947 case ENCODE_UTF16LE :
948 /*
949 * Read UTF-16 little-endian char...
950 */
951
952 if (buf->current >= buf->end)
953 if (mxml_fd_read(buf) < 0)
954 return (EOF);
955
956 temp = *(buf->current)++;
957
958 ch |= (temp << 8);
959
960 if (mxml_bad_char(ch))
961 {
962 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
963 ch);
964 return (EOF);
965 }
966 else if (ch >= 0xd800 && ch <= 0xdbff)
967 {
968 /*
969 * Multi-word UTF-16 char...
970 */
971
972 int lch;
973
974 if (buf->current >= buf->end)
975 if (mxml_fd_read(buf) < 0)
976 return (EOF);
977
978 lch = *(buf->current)++;
979
980 if (buf->current >= buf->end)
981 if (mxml_fd_read(buf) < 0)
982 return (EOF);
983
984 temp = *(buf->current)++;
985
986 lch |= (temp << 8);
987
988 if (lch < 0xdc00 || lch >= 0xdfff)
989 return (EOF);
990
991 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
992 }
993 break;
994 }
995
996#if DEBUG > 1
997 printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
998#endif /* DEBUG > 1 */
999
1000 return (ch);
1001}
1002
1003
1004/*
1005 * 'mxml_fd_putc()' - Write a character to a file descriptor.
1006 */
1007
1008static int /* O - 0 on success, -1 on error */
1009mxml_fd_putc(int ch, /* I - Character */
1010 void *p) /* I - File descriptor buffer */
1011{
1012 _mxml_fdbuf_t *buf; /* File descriptor buffer */
1013
1014
1015 /*
1016 * Flush the write buffer as needed...
1017 */
1018
1019 buf = (_mxml_fdbuf_t *)p;
1020
1021 if (buf->current >= buf->end)
1022 if (mxml_fd_write(buf) < 0)
1023 return (-1);
1024
1025 *(buf->current)++ = ch;
1026
1027 /*
1028 * Return successfully...
1029 */
1030
1031 return (0);
1032}
1033
1034
1035/*
1036 * 'mxml_fd_read()' - Read a buffer of data from a file descriptor.
1037 */
1038
1039static int /* O - 0 on success, -1 on error */
1040mxml_fd_read(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */
1041{
1042 int bytes; /* Bytes read... */
1043
1044
1045 /*
1046 * Range check input...
1047 */
1048
1049 if (!buf)
1050 return (-1);
1051
1052 /*
1053 * Read from the file descriptor...
1054 */
1055
1056 while ((bytes = read(buf->fd, buf->buffer, sizeof(buf->buffer))) < 0)
1057#ifdef EINTR
1058 if (errno != EAGAIN && errno != EINTR)
1059#else
1060 if (errno != EAGAIN)
1061#endif /* EINTR */
1062 return (-1);
1063
1064 if (bytes == 0)
1065 return (-1);
1066
1067 /*
1068 * Update the pointers and return success...
1069 */
1070
1071 buf->current = buf->buffer;
1072 buf->end = buf->buffer + bytes;
1073
1074 return (0);
1075}
1076
1077
1078/*
1079 * 'mxml_fd_write()' - Write a buffer of data to a file descriptor.
1080 */
1081
1082static int /* O - 0 on success, -1 on error */
1083mxml_fd_write(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */
1084{
1085 int bytes; /* Bytes written */
1086 unsigned char *ptr; /* Pointer into buffer */
1087
1088
1089 /*
1090 * Range check...
1091 */
1092
1093 if (!buf)
1094 return (-1);
1095
1096 /*
1097 * Return 0 if there is nothing to write...
1098 */
1099
1100 if (buf->current == buf->buffer)
1101 return (0);
1102
1103 /*
1104 * Loop until we have written everything...
1105 */
1106
1107 for (ptr = buf->buffer; ptr < buf->current; ptr += bytes)
1108 if ((bytes = write(buf->fd, ptr, buf->current - ptr)) < 0)
1109 return (-1);
1110
1111 /*
1112 * All done, reset pointers and return success...
1113 */
1114
1115 buf->current = buf->buffer;
1116
1117 return (0);
1118}
1119
1120
1121/*
1122 * 'mxml_file_getc()' - Get a character from a file.
1123 */
1124
1125static int /* O - Character or EOF */
1126mxml_file_getc(void *p, /* I - Pointer to file */
1127 int *encoding) /* IO - Encoding */
1128{
1129 int ch, /* Character from file */
1130 temp; /* Temporary character */
1131 FILE *fp; /* Pointer to file */
1132
1133
1134 /*
1135 * Read a character from the file and see if it is EOF or ASCII...
1136 */
1137
1138 fp = (FILE *)p;
1139 ch = getc(fp);
1140
1141 if (ch == EOF)
1142 return (EOF);
1143
1144 switch (*encoding)
1145 {
1146 case ENCODE_UTF8 :
1147 /*
1148 * Got a UTF-8 character; convert UTF-8 to Unicode and return...
1149 */
1150
1151 if (!(ch & 0x80))
1152 {
1153 if (mxml_bad_char(ch))
1154 {
1155 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
1156 ch);
1157 return (EOF);
1158 }
1159
1160#if DEBUG > 1
1161 printf("mxml_file_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
1162#endif /* DEBUG > 1 */
1163
1164 return (ch);
1165 }
1166 else if (ch == 0xfe)
1167 {
1168 /*
1169 * UTF-16 big-endian BOM?
1170 */
1171
1172 ch = getc(fp);
1173 if (ch != 0xff)
1174 return (EOF);
1175
1176 *encoding = ENCODE_UTF16BE;
1177
1178 return (mxml_file_getc(p, encoding));
1179 }
1180 else if (ch == 0xff)
1181 {
1182 /*
1183 * UTF-16 little-endian BOM?
1184 */
1185
1186 ch = getc(fp);
1187 if (ch != 0xfe)
1188 return (EOF);
1189
1190 *encoding = ENCODE_UTF16LE;
1191
1192 return (mxml_file_getc(p, encoding));
1193 }
1194 else if ((ch & 0xe0) == 0xc0)
1195 {
1196 /*
1197 * Two-byte value...
1198 */
1199
1200 if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
1201 return (EOF);
1202
1203 ch = ((ch & 0x1f) << 6) | (temp & 0x3f);
1204
1205 if (ch < 0x80)
1206 {
1207 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
1208 return (EOF);
1209 }
1210 }
1211 else if ((ch & 0xf0) == 0xe0)
1212 {
1213 /*
1214 * Three-byte value...
1215 */
1216
1217 if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
1218 return (EOF);
1219
1220 ch = ((ch & 0x0f) << 6) | (temp & 0x3f);
1221
1222 if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
1223 return (EOF);
1224
1225 ch = (ch << 6) | (temp & 0x3f);
1226
1227 if (ch < 0x800)
1228 {
1229 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
1230 return (EOF);
1231 }
1232
1233 /*
1234 * Ignore (strip) Byte Order Mark (BOM)...
1235 */
1236
1237 if (ch == 0xfeff)
1238 return (mxml_file_getc(p, encoding));
1239 }
1240 else if ((ch & 0xf8) == 0xf0)
1241 {
1242 /*
1243 * Four-byte value...
1244 */
1245
1246 if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
1247 return (EOF);
1248
1249 ch = ((ch & 0x07) << 6) | (temp & 0x3f);
1250
1251 if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
1252 return (EOF);
1253
1254 ch = (ch << 6) | (temp & 0x3f);
1255
1256 if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
1257 return (EOF);
1258
1259 ch = (ch << 6) | (temp & 0x3f);
1260
1261 if (ch < 0x10000)
1262 {
1263 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
1264 return (EOF);
1265 }
1266 }
1267 else
1268 return (EOF);
1269 break;
1270
1271 case ENCODE_UTF16BE :
1272 /*
1273 * Read UTF-16 big-endian char...
1274 */
1275
1276 ch = (ch << 8) | getc(fp);
1277
1278 if (mxml_bad_char(ch))
1279 {
1280 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
1281 ch);
1282 return (EOF);
1283 }
1284 else if (ch >= 0xd800 && ch <= 0xdbff)
1285 {
1286 /*
1287 * Multi-word UTF-16 char...
1288 */
1289
1290 int lch = (getc(fp) << 8) | getc(fp);
1291
1292 if (lch < 0xdc00 || lch >= 0xdfff)
1293 return (EOF);
1294
1295 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
1296 }
1297 break;
1298
1299 case ENCODE_UTF16LE :
1300 /*
1301 * Read UTF-16 little-endian char...
1302 */
1303
1304 ch |= (getc(fp) << 8);
1305
1306 if (mxml_bad_char(ch))
1307 {
1308 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
1309 ch);
1310 return (EOF);
1311 }
1312 else if (ch >= 0xd800 && ch <= 0xdbff)
1313 {
1314 /*
1315 * Multi-word UTF-16 char...
1316 */
1317
1318 int lch = getc(fp) | (getc(fp) << 8);
1319
1320 if (lch < 0xdc00 || lch >= 0xdfff)
1321 return (EOF);
1322
1323 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
1324 }
1325 break;
1326 }
1327
1328#if DEBUG > 1
1329 printf("mxml_file_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
1330#endif /* DEBUG > 1 */
1331
1332 return (ch);
1333}
1334
1335
1336/*
1337 * 'mxml_file_putc()' - Write a character to a file.
1338 */
1339
1340static int /* O - 0 on success, -1 on failure */
1341mxml_file_putc(int ch, /* I - Character to write */
1342 void *p) /* I - Pointer to file */
1343{
1344 return (putc(ch, (FILE *)p) == EOF ? -1 : 0);
1345}
1346
1347
1348/*
1349 * 'mxml_get_entity()' - Get the character corresponding to an entity...
1350 */
1351
1352static int /* O - Character value or EOF on error */
1353mxml_get_entity(mxml_node_t *parent, /* I - Parent node */
1354 void *p, /* I - Pointer to source */
1355 int *encoding, /* IO - Character encoding */
1356 int (*getc_cb)(void *, int *))
1357 /* I - Get character function */
1358{
1359 int ch; /* Current character */
1360 char entity[64], /* Entity string */
1361 *entptr; /* Pointer into entity */
1362
1363
1364 entptr = entity;
1365
1366 while ((ch = (*getc_cb)(p, encoding)) != EOF)
1367 if (ch > 126 || (!isalnum(ch) && ch != '#'))
1368 break;
1369 else if (entptr < (entity + sizeof(entity) - 1))
1370 *entptr++ = ch;
1371 else
1372 {
1373 mxml_error("Entity name too long under parent <%s>!",
1374 parent ? parent->value.element.name : "null");
1375 break;
1376 }
1377
1378 *entptr = '\0';
1379
1380 if (ch != ';')
1381 {
1382 mxml_error("Character entity \"%s\" not terminated under parent <%s>!",
1383 entity, parent ? parent->value.element.name : "null");
1384 return (EOF);
1385 }
1386
1387 if (entity[0] == '#')
1388 {
1389 if (entity[1] == 'x')
1390 ch = strtol(entity + 2, NULL, 16);
1391 else
1392 ch = strtol(entity + 1, NULL, 10);
1393 }
1394 else if ((ch = mxmlEntityGetValue(entity)) < 0)
1395 mxml_error("Entity name \"%s;\" not supported under parent <%s>!",
1396 entity, parent ? parent->value.element.name : "null");
1397
1398 if (mxml_bad_char(ch))
1399 {
1400 mxml_error("Bad control character 0x%02x under parent <%s> not allowed by XML standard!",
1401 ch, parent ? parent->value.element.name : "null");
1402 return (EOF);
1403 }
1404
1405 return (ch);
1406}
1407
1408
1409/*
1410 * 'mxml_load_data()' - Load data into an XML node tree.
1411 */
1412
1413static mxml_node_t * /* O - First node or NULL if the file could not be read. */
1414mxml_load_data(
1415 mxml_node_t *top, /* I - Top node */
1416 void *p, /* I - Pointer to data */
1417 mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
1418 _mxml_getc_cb_t getc_cb, /* I - Read function */
1419 mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
1420 void *sax_data) /* I - SAX user data */
1421{
1422 mxml_node_t *node, /* Current node */
1423 *first, /* First node added */
1424 *parent; /* Current parent node */
1425 int ch, /* Character from file */
1426 whitespace; /* Non-zero if whitespace seen */
1427 char *buffer, /* String buffer */
1428 *bufptr; /* Pointer into buffer */
1429 int bufsize; /* Size of buffer */
1430 mxml_type_t type; /* Current node type */
1431 int encoding; /* Character encoding */
1432 _mxml_global_t *global = _mxml_global();
1433 /* Global data */
1434 static const char * const types[] = /* Type strings... */
1435 {
1436 "MXML_ELEMENT", /* XML element with attributes */
1437 "MXML_INTEGER", /* Integer value */
1438 "MXML_OPAQUE", /* Opaque string */
1439 "MXML_REAL", /* Real value */
1440 "MXML_TEXT", /* Text fragment */
1441 "MXML_CUSTOM" /* Custom data */
1442 };
1443
1444
1445 /*
1446 * Read elements and other nodes from the file...
1447 */
1448
1449 if ((buffer = malloc(64)) == NULL)
1450 {
1451 mxml_error("Unable to allocate string buffer!");
1452 return (NULL);
1453 }
1454
1455 bufsize = 64;
1456 bufptr = buffer;
1457 parent = top;
1458 first = NULL;
1459 whitespace = 0;
1460 encoding = ENCODE_UTF8;
1461
1462 if (cb && parent)
1463 type = (*cb)(parent);
1464 else
1465 type = MXML_TEXT;
1466
1467 while ((ch = (*getc_cb)(p, &encoding)) != EOF)
1468 {
1469 if ((ch == '<' ||
1470 (mxml_isspace(ch) && type != MXML_OPAQUE && type != MXML_CUSTOM)) &&
1471 bufptr > buffer)
1472 {
1473 /*
1474 * Add a new value node...
1475 */
1476
1477 *bufptr = '\0';
1478
1479 switch (type)
1480 {
1481 case MXML_INTEGER :
1482 node = mxmlNewInteger(parent, strtol(buffer, &bufptr, 0));
1483 break;
1484
1485 case MXML_OPAQUE :
1486 node = mxmlNewOpaque(parent, buffer);
1487 break;
1488
1489 case MXML_REAL :
1490 node = mxmlNewReal(parent, strtod(buffer, &bufptr));
1491 break;
1492
1493 case MXML_TEXT :
1494 node = mxmlNewText(parent, whitespace, buffer);
1495 break;
1496
1497 case MXML_CUSTOM :
1498 if (global->custom_load_cb)
1499 {
1500 /*
1501 * Use the callback to fill in the custom data...
1502 */
1503
1504 node = mxmlNewCustom(parent, NULL, NULL);
1505
1506 if ((*global->custom_load_cb)(node, buffer))
1507 {
1508 mxml_error("Bad custom value '%s' in parent <%s>!",
1509 buffer, parent ? parent->value.element.name : "null");
1510 mxmlDelete(node);
1511 node = NULL;
1512 }
1513 break;
1514 }
1515
1516 default : /* Ignore... */
1517 node = NULL;
1518 break;
1519 }
1520
1521 if (*bufptr)
1522 {
1523 /*
1524 * Bad integer/real number value...
1525 */
1526
1527 mxml_error("Bad %s value '%s' in parent <%s>!",
1528 type == MXML_INTEGER ? "integer" : "real", buffer,
1529 parent ? parent->value.element.name : "null");
1530 break;
1531 }
1532
1533 bufptr = buffer;
1534 whitespace = mxml_isspace(ch) && type == MXML_TEXT;
1535
1536 if (!node && type != MXML_IGNORE)
1537 {
1538 /*
1539 * Print error and return...
1540 */
1541
1542 mxml_error("Unable to add value node of type %s to parent <%s>!",
1543 types[type], parent ? parent->value.element.name : "null");
1544 goto error;
1545 }
1546
1547 if (sax_cb)
1548 {
1549 (*sax_cb)(node, MXML_SAX_DATA, sax_data);
1550
1551 if (!mxmlRelease(node))
1552 node = NULL;
1553 }
1554
1555 if (!first && node)
1556 first = node;
1557 }
1558 else if (mxml_isspace(ch) && type == MXML_TEXT)
1559 whitespace = 1;
1560
1561 /*
1562 * Add lone whitespace node if we have an element and existing
1563 * whitespace...
1564 */
1565
1566 if (ch == '<' && whitespace && type == MXML_TEXT)
1567 {
1568 if (parent)
1569 {
1570 node = mxmlNewText(parent, whitespace, "");
1571
1572 if (sax_cb)
1573 {
1574 (*sax_cb)(node, MXML_SAX_DATA, sax_data);
1575
1576 if (!mxmlRelease(node))
1577 node = NULL;
1578 }
1579
1580 if (!first && node)
1581 first = node;
1582 }
1583
1584 whitespace = 0;
1585 }
1586
1587 if (ch == '<')
1588 {
1589 /*
1590 * Start of open/close tag...
1591 */
1592
1593 bufptr = buffer;
1594
1595 while ((ch = (*getc_cb)(p, &encoding)) != EOF)
1596 if (mxml_isspace(ch) || ch == '>' || (ch == '/' && bufptr > buffer))
1597 break;
1598 else if (ch == '<')
1599 {
1600 mxml_error("Bare < in element!");
1601 goto error;
1602 }
1603 else if (ch == '&')
1604 {
1605 if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)
1606 goto error;
1607
1608 if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
1609 goto error;
1610 }
1611 else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
1612 goto error;
1613 else if (((bufptr - buffer) == 1 && buffer[0] == '?') ||
1614 ((bufptr - buffer) == 3 && !strncmp(buffer, "!--", 3)) ||
1615 ((bufptr - buffer) == 8 && !strncmp(buffer, "![CDATA[", 8)))
1616 break;
1617
1618 *bufptr = '\0';
1619
1620 if (!strcmp(buffer, "!--"))
1621 {
1622 /*
1623 * Gather rest of comment...
1624 */
1625
1626 while ((ch = (*getc_cb)(p, &encoding)) != EOF)
1627 {
1628 if (ch == '>' && bufptr > (buffer + 4) &&
1629 bufptr[-3] != '-' && bufptr[-2] == '-' && bufptr[-1] == '-')
1630 break;
1631 else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
1632 goto error;
1633 }
1634
1635 /*
1636 * Error out if we didn't get the whole comment...
1637 */
1638
1639 if (ch != '>')
1640 {
1641 /*
1642 * Print error and return...
1643 */
1644
1645 mxml_error("Early EOF in comment node!");
1646 goto error;
1647 }
1648
1649
1650 /*
1651 * Otherwise add this as an element under the current parent...
1652 */
1653
1654 *bufptr = '\0';
1655
1656 if (!parent && first)
1657 {
1658 /*
1659 * There can only be one root element!
1660 */
1661
1662 mxml_error("<%s> cannot be a second root node after <%s>",
1663 buffer, first->value.element.name);
1664 goto error;
1665 }
1666
1667 if ((node = mxmlNewElement(parent, buffer)) == NULL)
1668 {
1669 /*
1670 * Just print error for now...
1671 */
1672
1673 mxml_error("Unable to add comment node to parent <%s>!",
1674 parent ? parent->value.element.name : "null");
1675 break;
1676 }
1677
1678 if (sax_cb)
1679 {
1680 (*sax_cb)(node, MXML_SAX_COMMENT, sax_data);
1681
1682 if (!mxmlRelease(node))
1683 node = NULL;
1684 }
1685
1686 if (node && !first)
1687 first = node;
1688 }
1689 else if (!strcmp(buffer, "![CDATA["))
1690 {
1691 /*
1692 * Gather CDATA section...
1693 */
1694
1695 while ((ch = (*getc_cb)(p, &encoding)) != EOF)
1696 {
1697 if (ch == '>' && !strncmp(bufptr - 2, "]]", 2))
1698 break;
1699 else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
1700 goto error;
1701 }
1702
1703 /*
1704 * Error out if we didn't get the whole comment...
1705 */
1706
1707 if (ch != '>')
1708 {
1709 /*
1710 * Print error and return...
1711 */
1712
1713 mxml_error("Early EOF in CDATA node!");
1714 goto error;
1715 }
1716
1717
1718 /*
1719 * Otherwise add this as an element under the current parent...
1720 */
1721
1722 *bufptr = '\0';
1723
1724 if (!parent && first)
1725 {
1726 /*
1727 * There can only be one root element!
1728 */
1729
1730 mxml_error("<%s> cannot be a second root node after <%s>",
1731 buffer, first->value.element.name);
1732 goto error;
1733 }
1734
1735 if ((node = mxmlNewElement(parent, buffer)) == NULL)
1736 {
1737 /*
1738 * Print error and return...
1739 */
1740
1741 mxml_error("Unable to add CDATA node to parent <%s>!",
1742 parent ? parent->value.element.name : "null");
1743 goto error;
1744 }
1745
1746 if (sax_cb)
1747 {
1748 (*sax_cb)(node, MXML_SAX_CDATA, sax_data);
1749
1750 if (!mxmlRelease(node))
1751 node = NULL;
1752 }
1753
1754 if (node && !first)
1755 first = node;
1756 }
1757 else if (buffer[0] == '?')
1758 {
1759 /*
1760 * Gather rest of processing instruction...
1761 */
1762
1763 while ((ch = (*getc_cb)(p, &encoding)) != EOF)
1764 {
1765 if (ch == '>' && bufptr > buffer && bufptr[-1] == '?')
1766 break;
1767 else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
1768 goto error;
1769 }
1770
1771 /*
1772 * Error out if we didn't get the whole processing instruction...
1773 */
1774
1775 if (ch != '>')
1776 {
1777 /*
1778 * Print error and return...
1779 */
1780
1781 mxml_error("Early EOF in processing instruction node!");
1782 goto error;
1783 }
1784
1785 /*
1786 * Otherwise add this as an element under the current parent...
1787 */
1788
1789 *bufptr = '\0';
1790
1791 if (!parent && first)
1792 {
1793 /*
1794 * There can only be one root element!
1795 */
1796
1797 mxml_error("<%s> cannot be a second root node after <%s>",
1798 buffer, first->value.element.name);
1799 goto error;
1800 }
1801
1802 if ((node = mxmlNewElement(parent, buffer)) == NULL)
1803 {
1804 /*
1805 * Print error and return...
1806 */
1807
1808 mxml_error("Unable to add processing instruction node to parent <%s>!",
1809 parent ? parent->value.element.name : "null");
1810 goto error;
1811 }
1812
1813 if (sax_cb)
1814 {
1815 (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);
1816
1817 if (!mxmlRelease(node))
1818 node = NULL;
1819 }
1820
1821 if (node)
1822 {
1823 if (!first)
1824 first = node;
1825
1826 if (!parent)
1827 {
1828 parent = node;
1829
1830 if (cb)
1831 type = (*cb)(parent);
1832 }
1833 }
1834 }
1835 else if (buffer[0] == '!')
1836 {
1837 /*
1838 * Gather rest of declaration...
1839 */
1840
1841 do
1842 {
1843 if (ch == '>')
1844 break;
1845 else
1846 {
1847 if (ch == '&')
1848 if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)
1849 goto error;
1850
1851 if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
1852 goto error;
1853 }
1854 }
1855 while ((ch = (*getc_cb)(p, &encoding)) != EOF);
1856
1857 /*
1858 * Error out if we didn't get the whole declaration...
1859 */
1860
1861 if (ch != '>')
1862 {
1863 /*
1864 * Print error and return...
1865 */
1866
1867 mxml_error("Early EOF in declaration node!");
1868 goto error;
1869 }
1870
1871 /*
1872 * Otherwise add this as an element under the current parent...
1873 */
1874
1875 *bufptr = '\0';
1876
1877 if (!parent && first)
1878 {
1879 /*
1880 * There can only be one root element!
1881 */
1882
1883 mxml_error("<%s> cannot be a second root node after <%s>",
1884 buffer, first->value.element.name);
1885 goto error;
1886 }
1887
1888 if ((node = mxmlNewElement(parent, buffer)) == NULL)
1889 {
1890 /*
1891 * Print error and return...
1892 */
1893
1894 mxml_error("Unable to add declaration node to parent <%s>!",
1895 parent ? parent->value.element.name : "null");
1896 goto error;
1897 }
1898
1899 if (sax_cb)
1900 {
1901 (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);
1902
1903 if (!mxmlRelease(node))
1904 node = NULL;
1905 }
1906
1907 if (node)
1908 {
1909 if (!first)
1910 first = node;
1911
1912 if (!parent)
1913 {
1914 parent = node;
1915
1916 if (cb)
1917 type = (*cb)(parent);
1918 }
1919 }
1920 }
1921 else if (buffer[0] == '/')
1922 {
1923 /*
1924 * Handle close tag...
1925 */
1926
1927 if (!parent || strcmp(buffer + 1, parent->value.element.name))
1928 {
1929 /*
1930 * Close tag doesn't match tree; print an error for now...
1931 */
1932
1933 mxml_error("Mismatched close tag <%s> under parent <%s>!",
1934 buffer, parent ? parent->value.element.name : "(null)");
1935 goto error;
1936 }
1937
1938 /*
1939 * Keep reading until we see >...
1940 */
1941
1942 while (ch != '>' && ch != EOF)
1943 ch = (*getc_cb)(p, &encoding);
1944
1945 node = parent;
1946 parent = parent->parent;
1947
1948 if (sax_cb)
1949 {
1950 (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
1951
1952 if (!mxmlRelease(node) && first == node)
1953 first = NULL;
1954 }
1955
1956 /*
1957 * Ascend into the parent and set the value type as needed...
1958 */
1959
1960 if (cb && parent)
1961 type = (*cb)(parent);
1962 }
1963 else
1964 {
1965 /*
1966 * Handle open tag...
1967 */
1968
1969 if (!parent && first)
1970 {
1971 /*
1972 * There can only be one root element!
1973 */
1974
1975 mxml_error("<%s> cannot be a second root node after <%s>",
1976 buffer, first->value.element.name);
1977 goto error;
1978 }
1979
1980 if ((node = mxmlNewElement(parent, buffer)) == NULL)
1981 {
1982 /*
1983 * Just print error for now...
1984 */
1985
1986 mxml_error("Unable to add element node to parent <%s>!",
1987 parent ? parent->value.element.name : "null");
1988 goto error;
1989 }
1990
1991 if (mxml_isspace(ch))
1992 {
1993 if ((ch = mxml_parse_element(node, p, &encoding, getc_cb)) == EOF)
1994 goto error;
1995 }
1996 else if (ch == '/')
1997 {
1998 if ((ch = (*getc_cb)(p, &encoding)) != '>')
1999 {
2000 mxml_error("Expected > but got '%c' instead for element <%s/>!",
2001 ch, buffer);
2002 mxmlDelete(node);
2003 goto error;
2004 }
2005
2006 ch = '/';
2007 }
2008
2009 if (sax_cb)
2010 (*sax_cb)(node, MXML_SAX_ELEMENT_OPEN, sax_data);
2011
2012 if (!first)
2013 first = node;
2014
2015 if (ch == EOF)
2016 break;
2017
2018 if (ch != '/')
2019 {
2020 /*
2021 * Descend into this node, setting the value type as needed...
2022 */
2023
2024 parent = node;
2025
2026 if (cb && parent)
2027 type = (*cb)(parent);
2028 }
2029 else if (sax_cb)
2030 {
2031 (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
2032
2033 if (!mxmlRelease(node) && first == node)
2034 first = NULL;
2035 }
2036 }
2037
2038 bufptr = buffer;
2039 }
2040 else if (ch == '&')
2041 {
2042 /*
2043 * Add character entity to current buffer...
2044 */
2045
2046 if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)
2047 goto error;
2048
2049 if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
2050 goto error;
2051 }
2052 else if (type == MXML_OPAQUE || type == MXML_CUSTOM || !mxml_isspace(ch))
2053 {
2054 /*
2055 * Add character to current buffer...
2056 */
2057
2058 if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
2059 goto error;
2060 }
2061 }
2062
2063 /*
2064 * Free the string buffer - we don't need it anymore...
2065 */
2066
2067 free(buffer);
2068
2069 /*
2070 * Find the top element and return it...
2071 */
2072
2073 if (parent)
2074 {
2075 node = parent;
2076
2077 while (parent->parent != top && parent->parent)
2078 parent = parent->parent;
2079
2080 if (node != parent)
2081 {
2082 mxml_error("Missing close tag </%s> under parent <%s>!",
2083 node->value.element.name,
2084 node->parent ? node->parent->value.element.name : "(null)");
2085
2086 mxmlDelete(first);
2087
2088 return (NULL);
2089 }
2090 }
2091
2092 if (parent)
2093 return (parent);
2094 else
2095 return (first);
2096
2097 /*
2098 * Common error return...
2099 */
2100
2101error:
2102
2103 mxmlDelete(first);
2104
2105 free(buffer);
2106
2107 return (NULL);
2108}
2109
2110
2111/*
2112 * 'mxml_parse_element()' - Parse an element for any attributes...
2113 */
2114
2115static int /* O - Terminating character */
2116mxml_parse_element(
2117 mxml_node_t *node, /* I - Element node */
2118 void *p, /* I - Data to read from */
2119 int *encoding, /* IO - Encoding */
2120 _mxml_getc_cb_t getc_cb) /* I - Data callback */
2121{
2122 int ch, /* Current character in file */
2123 quote; /* Quoting character */
2124 char *name, /* Attribute name */
2125 *value, /* Attribute value */
2126 *ptr; /* Pointer into name/value */
2127 int namesize, /* Size of name string */
2128 valsize; /* Size of value string */
2129
2130
2131 /*
2132 * Initialize the name and value buffers...
2133 */
2134
2135 if ((name = malloc(64)) == NULL)
2136 {
2137 mxml_error("Unable to allocate memory for name!");
2138 return (EOF);
2139 }
2140
2141 namesize = 64;
2142
2143 if ((value = malloc(64)) == NULL)
2144 {
2145 free(name);
2146 mxml_error("Unable to allocate memory for value!");
2147 return (EOF);
2148 }
2149
2150 valsize = 64;
2151
2152 /*
2153 * Loop until we hit a >, /, ?, or EOF...
2154 */
2155
2156 while ((ch = (*getc_cb)(p, encoding)) != EOF)
2157 {
2158#if DEBUG > 1
2159 fprintf(stderr, "parse_element: ch='%c'\n", ch);
2160#endif /* DEBUG > 1 */
2161
2162 /*
2163 * Skip leading whitespace...
2164 */
2165
2166 if (mxml_isspace(ch))
2167 continue;
2168
2169 /*
2170 * Stop at /, ?, or >...
2171 */
2172
2173 if (ch == '/' || ch == '?')
2174 {
2175 /*
2176 * Grab the > character and print an error if it isn't there...
2177 */
2178
2179 quote = (*getc_cb)(p, encoding);
2180
2181 if (quote != '>')
2182 {
2183 mxml_error("Expected '>' after '%c' for element %s, but got '%c'!",
2184 ch, node->value.element.name, quote);
2185 goto error;
2186 }
2187
2188 break;
2189 }
2190 else if (ch == '<')
2191 {
2192 mxml_error("Bare < in element %s!", node->value.element.name);
2193 goto error;
2194 }
2195 else if (ch == '>')
2196 break;
2197
2198 /*
2199 * Read the attribute name...
2200 */
2201
2202 name[0] = ch;
2203 ptr = name + 1;
2204
2205 if (ch == '\"' || ch == '\'')
2206 {
2207 /*
2208 * Name is in quotes, so get a quoted string...
2209 */
2210
2211 quote = ch;
2212
2213 while ((ch = (*getc_cb)(p, encoding)) != EOF)
2214 {
2215 if (ch == '&')
2216 if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
2217 goto error;
2218
2219 if (mxml_add_char(ch, &ptr, &name, &namesize))
2220 goto error;
2221
2222 if (ch == quote)
2223 break;
2224 }
2225 }
2226 else
2227 {
2228 /*
2229 * Grab an normal, non-quoted name...
2230 */
2231
2232 while ((ch = (*getc_cb)(p, encoding)) != EOF)
2233 if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>' ||
2234 ch == '?')
2235 break;
2236 else
2237 {
2238 if (ch == '&')
2239 if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
2240 goto error;
2241
2242 if (mxml_add_char(ch, &ptr, &name, &namesize))
2243 goto error;
2244 }
2245 }
2246
2247 *ptr = '\0';
2248
2249 if (mxmlElementGetAttr(node, name))
2250 goto error;
2251
2252 while (ch != EOF && mxml_isspace(ch))
2253 ch = (*getc_cb)(p, encoding);
2254
2255 if (ch == '=')
2256 {
2257 /*
2258 * Read the attribute value...
2259 */
2260
2261 while ((ch = (*getc_cb)(p, encoding)) != EOF && mxml_isspace(ch));
2262
2263 if (ch == EOF)
2264 {
2265 mxml_error("Missing value for attribute '%s' in element %s!",
2266 name, node->value.element.name);
2267 goto error;
2268 }
2269
2270 if (ch == '\'' || ch == '\"')
2271 {
2272 /*
2273 * Read quoted value...
2274 */
2275
2276 quote = ch;
2277 ptr = value;
2278
2279 while ((ch = (*getc_cb)(p, encoding)) != EOF)
2280 if (ch == quote)
2281 break;
2282 else
2283 {
2284 if (ch == '&')
2285 if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
2286 goto error;
2287
2288 if (mxml_add_char(ch, &ptr, &value, &valsize))
2289 goto error;
2290 }
2291
2292 *ptr = '\0';
2293 }
2294 else
2295 {
2296 /*
2297 * Read unquoted value...
2298 */
2299
2300 value[0] = ch;
2301 ptr = value + 1;
2302
2303 while ((ch = (*getc_cb)(p, encoding)) != EOF)
2304 if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>')
2305 break;
2306 else
2307 {
2308 if (ch == '&')
2309 if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
2310 goto error;
2311
2312 if (mxml_add_char(ch, &ptr, &value, &valsize))
2313 goto error;
2314 }
2315
2316 *ptr = '\0';
2317 }
2318
2319 /*
2320 * Set the attribute with the given string value...
2321 */
2322
2323 mxmlElementSetAttr(node, name, value);
2324 }
2325 else
2326 {
2327 mxml_error("Missing value for attribute '%s' in element %s!",
2328 name, node->value.element.name);
2329 goto error;
2330 }
2331
2332 /*
2333 * Check the end character...
2334 */
2335
2336 if (ch == '/' || ch == '?')
2337 {
2338 /*
2339 * Grab the > character and print an error if it isn't there...
2340 */
2341
2342 quote = (*getc_cb)(p, encoding);
2343
2344 if (quote != '>')
2345 {
2346 mxml_error("Expected '>' after '%c' for element %s, but got '%c'!",
2347 ch, node->value.element.name, quote);
2348 ch = EOF;
2349 }
2350
2351 break;
2352 }
2353 else if (ch == '>')
2354 break;
2355 }
2356
2357 /*
2358 * Free the name and value buffers and return...
2359 */
2360
2361 free(name);
2362 free(value);
2363
2364 return (ch);
2365
2366 /*
2367 * Common error return point...
2368 */
2369
2370error:
2371
2372 free(name);
2373 free(value);
2374
2375 return (EOF);
2376}
2377
2378
2379/*
2380 * 'mxml_string_getc()' - Get a character from a string.
2381 */
2382
2383static int /* O - Character or EOF */
2384mxml_string_getc(void *p, /* I - Pointer to file */
2385 int *encoding) /* IO - Encoding */
2386{
2387 int ch; /* Character */
2388 const char **s; /* Pointer to string pointer */
2389
2390
2391 s = (const char **)p;
2392
2393 if ((ch = (*s)[0] & 255) != 0 || *encoding == ENCODE_UTF16LE)
2394 {
2395 /*
2396 * Got character; convert UTF-8 to integer and return...
2397 */
2398
2399 (*s)++;
2400
2401 switch (*encoding)
2402 {
2403 case ENCODE_UTF8 :
2404 if (!(ch & 0x80))
2405 {
2406#if DEBUG > 1
2407 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
2408#endif /* DEBUG > 1 */
2409
2410 if (mxml_bad_char(ch))
2411 {
2412 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
2413 ch);
2414 return (EOF);
2415 }
2416
2417 return (ch);
2418 }
2419 else if (ch == 0xfe)
2420 {
2421 /*
2422 * UTF-16 big-endian BOM?
2423 */
2424
2425 if (((*s)[0] & 255) != 0xff)
2426 return (EOF);
2427
2428 *encoding = ENCODE_UTF16BE;
2429 (*s)++;
2430
2431 return (mxml_string_getc(p, encoding));
2432 }
2433 else if (ch == 0xff)
2434 {
2435 /*
2436 * UTF-16 little-endian BOM?
2437 */
2438
2439 if (((*s)[0] & 255) != 0xfe)
2440 return (EOF);
2441
2442 *encoding = ENCODE_UTF16LE;
2443 (*s)++;
2444
2445 return (mxml_string_getc(p, encoding));
2446 }
2447 else if ((ch & 0xe0) == 0xc0)
2448 {
2449 /*
2450 * Two-byte value...
2451 */
2452
2453 if (((*s)[0] & 0xc0) != 0x80)
2454 return (EOF);
2455
2456 ch = ((ch & 0x1f) << 6) | ((*s)[0] & 0x3f);
2457
2458 (*s)++;
2459
2460 if (ch < 0x80)
2461 {
2462 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
2463 return (EOF);
2464 }
2465
2466#if DEBUG > 1
2467 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
2468#endif /* DEBUG > 1 */
2469
2470 return (ch);
2471 }
2472 else if ((ch & 0xf0) == 0xe0)
2473 {
2474 /*
2475 * Three-byte value...
2476 */
2477
2478 if (((*s)[0] & 0xc0) != 0x80 ||
2479 ((*s)[1] & 0xc0) != 0x80)
2480 return (EOF);
2481
2482 ch = ((((ch & 0x0f) << 6) | ((*s)[0] & 0x3f)) << 6) | ((*s)[1] & 0x3f);
2483
2484 (*s) += 2;
2485
2486 if (ch < 0x800)
2487 {
2488 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
2489 return (EOF);
2490 }
2491
2492 /*
2493 * Ignore (strip) Byte Order Mark (BOM)...
2494 */
2495
2496 if (ch == 0xfeff)
2497 return (mxml_string_getc(p, encoding));
2498
2499#if DEBUG > 1
2500 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
2501#endif /* DEBUG > 1 */
2502
2503 return (ch);
2504 }
2505 else if ((ch & 0xf8) == 0xf0)
2506 {
2507 /*
2508 * Four-byte value...
2509 */
2510
2511 if (((*s)[0] & 0xc0) != 0x80 ||
2512 ((*s)[1] & 0xc0) != 0x80 ||
2513 ((*s)[2] & 0xc0) != 0x80)
2514 return (EOF);
2515
2516 ch = ((((((ch & 0x07) << 6) | ((*s)[0] & 0x3f)) << 6) |
2517 ((*s)[1] & 0x3f)) << 6) | ((*s)[2] & 0x3f);
2518
2519 (*s) += 3;
2520
2521 if (ch < 0x10000)
2522 {
2523 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
2524 return (EOF);
2525 }
2526
2527#if DEBUG > 1
2528 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
2529#endif /* DEBUG > 1 */
2530
2531 return (ch);
2532 }
2533 else
2534 return (EOF);
2535
2536 case ENCODE_UTF16BE :
2537 /*
2538 * Read UTF-16 big-endian char...
2539 */
2540
2541 ch = (ch << 8) | ((*s)[0] & 255);
2542 (*s) ++;
2543
2544 if (mxml_bad_char(ch))
2545 {
2546 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
2547 ch);
2548 return (EOF);
2549 }
2550 else if (ch >= 0xd800 && ch <= 0xdbff)
2551 {
2552 /*
2553 * Multi-word UTF-16 char...
2554 */
2555
2556 int lch; /* Lower word */
2557
2558
2559 if (!(*s)[0])
2560 return (EOF);
2561
2562 lch = (((*s)[0] & 255) << 8) | ((*s)[1] & 255);
2563 (*s) += 2;
2564
2565 if (lch < 0xdc00 || lch >= 0xdfff)
2566 return (EOF);
2567
2568 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
2569 }
2570
2571#if DEBUG > 1
2572 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
2573#endif /* DEBUG > 1 */
2574
2575 return (ch);
2576
2577 case ENCODE_UTF16LE :
2578 /*
2579 * Read UTF-16 little-endian char...
2580 */
2581
2582 ch = ch | (((*s)[0] & 255) << 8);
2583
2584 if (!ch)
2585 {
2586 (*s) --;
2587 return (EOF);
2588 }
2589
2590 (*s) ++;
2591
2592 if (mxml_bad_char(ch))
2593 {
2594 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
2595 ch);
2596 return (EOF);
2597 }
2598 else if (ch >= 0xd800 && ch <= 0xdbff)
2599 {
2600 /*
2601 * Multi-word UTF-16 char...
2602 */
2603
2604 int lch; /* Lower word */
2605
2606
2607 if (!(*s)[1])
2608 return (EOF);
2609
2610 lch = (((*s)[1] & 255) << 8) | ((*s)[0] & 255);
2611 (*s) += 2;
2612
2613 if (lch < 0xdc00 || lch >= 0xdfff)
2614 return (EOF);
2615
2616 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
2617 }
2618
2619#if DEBUG > 1
2620 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
2621#endif /* DEBUG > 1 */
2622
2623 return (ch);
2624 }
2625 }
2626
2627 return (EOF);
2628}
2629
2630
2631/*
2632 * 'mxml_string_putc()' - Write a character to a string.
2633 */
2634
2635static int /* O - 0 on success, -1 on failure */
2636mxml_string_putc(int ch, /* I - Character to write */
2637 void *p) /* I - Pointer to string pointers */
2638{
2639 char **pp; /* Pointer to string pointers */
2640
2641
2642 pp = (char **)p;
2643
2644 if (pp[0] < pp[1])
2645 pp[0][0] = ch;
2646
2647 pp[0] ++;
2648
2649 return (0);
2650}
2651
2652
2653/*
2654 * 'mxml_write_name()' - Write a name string.
2655 */
2656
2657static int /* O - 0 on success, -1 on failure */
2658mxml_write_name(const char *s, /* I - Name to write */
2659 void *p, /* I - Write pointer */
2660 int (*putc_cb)(int, void *))
2661 /* I - Write callback */
2662{
2663 char quote; /* Quote character */
2664 const char *name; /* Entity name */
2665
2666
2667 if (*s == '\"' || *s == '\'')
2668 {
2669 /*
2670 * Write a quoted name string...
2671 */
2672
2673 if ((*putc_cb)(*s, p) < 0)
2674 return (-1);
2675
2676 quote = *s++;
2677
2678 while (*s && *s != quote)
2679 {
2680 if ((name = mxmlEntityGetName(*s)) != NULL)
2681 {
2682 if ((*putc_cb)('&', p) < 0)
2683 return (-1);
2684
2685 while (*name)
2686 {
2687 if ((*putc_cb)(*name, p) < 0)
2688 return (-1);
2689
2690 name ++;
2691 }
2692
2693 if ((*putc_cb)(';', p) < 0)
2694 return (-1);
2695 }
2696 else if ((*putc_cb)(*s, p) < 0)
2697 return (-1);
2698
2699 s ++;
2700 }
2701
2702 /*
2703 * Write the end quote...
2704 */
2705
2706 if ((*putc_cb)(quote, p) < 0)
2707 return (-1);
2708 }
2709 else
2710 {
2711 /*
2712 * Write a non-quoted name string...
2713 */
2714
2715 while (*s)
2716 {
2717 if ((*putc_cb)(*s, p) < 0)
2718 return (-1);
2719
2720 s ++;
2721 }
2722 }
2723
2724 return (0);
2725}
2726
2727
2728/*
2729 * 'mxml_write_node()' - Save an XML node to a file.
2730 */
2731
2732static int /* O - Column or -1 on error */
2733mxml_write_node(mxml_node_t *node, /* I - Node to write */
2734 void *p, /* I - File to write to */
2735 mxml_save_cb_t cb, /* I - Whitespace callback */
2736 int col, /* I - Current column */
2737 _mxml_putc_cb_t putc_cb,/* I - Output callback */
2738 _mxml_global_t *global)/* I - Global data */
2739{
2740 int i, /* Looping var */
2741 width; /* Width of attr + value */
2742 mxml_attr_t *attr; /* Current attribute */
2743 char s[255]; /* Temporary string */
2744
2745
2746 /*
2747 * Print the node value...
2748 */
2749
2750 switch (node->type)
2751 {
2752 case MXML_ELEMENT :
2753 col = mxml_write_ws(node, p, cb, MXML_WS_BEFORE_OPEN, col, putc_cb);
2754
2755 if ((*putc_cb)('<', p) < 0)
2756 return (-1);
2757 if (node->value.element.name[0] == '?' ||
2758 !strncmp(node->value.element.name, "!--", 3) ||
2759 !strncmp(node->value.element.name, "![CDATA[", 8))
2760 {
2761 /*
2762 * Comments, CDATA, and processing instructions do not
2763 * use character entities.
2764 */
2765
2766 const char *ptr; /* Pointer into name */
2767
2768
2769 for (ptr = node->value.element.name; *ptr; ptr ++)
2770 if ((*putc_cb)(*ptr, p) < 0)
2771 return (-1);
2772 }
2773 else if (mxml_write_name(node->value.element.name, p, putc_cb) < 0)
2774 return (-1);
2775
2776 col += strlen(node->value.element.name) + 1;
2777
2778 for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
2779 i > 0;
2780 i --, attr ++)
2781 {
2782 width = strlen(attr->name);
2783
2784 if (attr->value)
2785 width += strlen(attr->value) + 3;
2786
2787 if (global->wrap > 0 && (col + width) > global->wrap)
2788 {
2789 if ((*putc_cb)('\n', p) < 0)
2790 return (-1);
2791
2792 col = 0;
2793 }
2794 else
2795 {
2796 if ((*putc_cb)(' ', p) < 0)
2797 return (-1);
2798
2799 col ++;
2800 }
2801
2802 if (mxml_write_name(attr->name, p, putc_cb) < 0)
2803 return (-1);
2804
2805 if (attr->value)
2806 {
2807 if ((*putc_cb)('=', p) < 0)
2808 return (-1);
2809 if ((*putc_cb)('\"', p) < 0)
2810 return (-1);
2811 if (mxml_write_string(attr->value, p, putc_cb) < 0)
2812 return (-1);
2813 if ((*putc_cb)('\"', p) < 0)
2814 return (-1);
2815 }
2816
2817 col += width;
2818 }
2819
2820 if (node->child)
2821 {
2822 /*
2823 * Write children...
2824 */
2825
2826 mxml_node_t *child; /* Current child */
2827
2828
2829 if ((*putc_cb)('>', p) < 0)
2830 return (-1);
2831 else
2832 col ++;
2833
2834 col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);
2835
2836 for (child = node->child; child; child = child->next)
2837 {
2838 if ((col = mxml_write_node(child, p, cb, col, putc_cb, global)) < 0)
2839 return (-1);
2840 }
2841
2842 /*
2843 * The ? and ! elements are special-cases and have no end tags...
2844 */
2845
2846 if (node->value.element.name[0] != '!' &&
2847 node->value.element.name[0] != '?')
2848 {
2849 col = mxml_write_ws(node, p, cb, MXML_WS_BEFORE_CLOSE, col, putc_cb);
2850
2851 if ((*putc_cb)('<', p) < 0)
2852 return (-1);
2853 if ((*putc_cb)('/', p) < 0)
2854 return (-1);
2855 if (mxml_write_string(node->value.element.name, p, putc_cb) < 0)
2856 return (-1);
2857 if ((*putc_cb)('>', p) < 0)
2858 return (-1);
2859
2860 col += strlen(node->value.element.name) + 3;
2861
2862 col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_CLOSE, col, putc_cb);
2863 }
2864 }
2865 else if (node->value.element.name[0] == '!' ||
2866 node->value.element.name[0] == '?')
2867 {
2868 /*
2869 * The ? and ! elements are special-cases...
2870 */
2871
2872 if ((*putc_cb)('>', p) < 0)
2873 return (-1);
2874 else
2875 col ++;
2876
2877 col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);
2878 }
2879 else
2880 {
2881 if ((*putc_cb)(' ', p) < 0)
2882 return (-1);
2883 if ((*putc_cb)('/', p) < 0)
2884 return (-1);
2885 if ((*putc_cb)('>', p) < 0)
2886 return (-1);
2887
2888 col += 3;
2889
2890 col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);
2891 }
2892 break;
2893
2894 case MXML_INTEGER :
2895 if (node->prev)
2896 {
2897 if (global->wrap > 0 && col > global->wrap)
2898 {
2899 if ((*putc_cb)('\n', p) < 0)
2900 return (-1);
2901
2902 col = 0;
2903 }
2904 else if ((*putc_cb)(' ', p) < 0)
2905 return (-1);
2906 else
2907 col ++;
2908 }
2909
2910 sprintf(s, "%d", node->value.integer);
2911 if (mxml_write_string(s, p, putc_cb) < 0)
2912 return (-1);
2913
2914 col += strlen(s);
2915 break;
2916
2917 case MXML_OPAQUE :
2918 if (mxml_write_string(node->value.opaque, p, putc_cb) < 0)
2919 return (-1);
2920
2921 col += strlen(node->value.opaque);
2922 break;
2923
2924 case MXML_REAL :
2925 if (node->prev)
2926 {
2927 if (global->wrap > 0 && col > global->wrap)
2928 {
2929 if ((*putc_cb)('\n', p) < 0)
2930 return (-1);
2931
2932 col = 0;
2933 }
2934 else if ((*putc_cb)(' ', p) < 0)
2935 return (-1);
2936 else
2937 col ++;
2938 }
2939
2940 sprintf(s, "%f", node->value.real);
2941 if (mxml_write_string(s, p, putc_cb) < 0)
2942 return (-1);
2943
2944 col += strlen(s);
2945 break;
2946
2947 case MXML_TEXT :
2948 if (node->value.text.whitespace && col > 0)
2949 {
2950 if (global->wrap > 0 && col > global->wrap)
2951 {
2952 if ((*putc_cb)('\n', p) < 0)
2953 return (-1);
2954
2955 col = 0;
2956 }
2957 else if ((*putc_cb)(' ', p) < 0)
2958 return (-1);
2959 else
2960 col ++;
2961 }
2962
2963 if (mxml_write_string(node->value.text.string, p, putc_cb) < 0)
2964 return (-1);
2965
2966 col += strlen(node->value.text.string);
2967 break;
2968
2969 case MXML_CUSTOM :
2970 if (global->custom_save_cb)
2971 {
2972 char *data; /* Custom data string */
2973 const char *newline; /* Last newline in string */
2974
2975
2976 if ((data = (*global->custom_save_cb)(node)) == NULL)
2977 return (-1);
2978
2979 if (mxml_write_string(data, p, putc_cb) < 0)
2980 return (-1);
2981
2982 if ((newline = strrchr(data, '\n')) == NULL)
2983 col += strlen(data);
2984 else
2985 col = strlen(newline);
2986
2987 free(data);
2988 break;
2989 }
2990
2991 default : /* Should never happen */
2992 return (-1);
2993 }
2994
2995 return (col);
2996}
2997
2998
2999/*
3000 * 'mxml_write_string()' - Write a string, escaping & and < as needed.
3001 */
3002
3003static int /* O - 0 on success, -1 on failure */
3004mxml_write_string(
3005 const char *s, /* I - String to write */
3006 void *p, /* I - Write pointer */
3007 _mxml_putc_cb_t putc_cb) /* I - Write callback */
3008{
3009 const char *name; /* Entity name, if any */
3010
3011
3012 while (*s)
3013 {
3014 if ((name = mxmlEntityGetName(*s)) != NULL)
3015 {
3016 if ((*putc_cb)('&', p) < 0)
3017 return (-1);
3018
3019 while (*name)
3020 {
3021 if ((*putc_cb)(*name, p) < 0)
3022 return (-1);
3023 name ++;
3024 }
3025
3026 if ((*putc_cb)(';', p) < 0)
3027 return (-1);
3028 }
3029 else if ((*putc_cb)(*s, p) < 0)
3030 return (-1);
3031
3032 s ++;
3033 }
3034
3035 return (0);
3036}
3037
3038
3039/*
3040 * 'mxml_write_ws()' - Do whitespace callback...
3041 */
3042
3043static int /* O - New column */
3044mxml_write_ws(mxml_node_t *node, /* I - Current node */
3045 void *p, /* I - Write pointer */
3046 mxml_save_cb_t cb, /* I - Callback function */
3047 int ws, /* I - Where value */
3048 int col, /* I - Current column */
3049 _mxml_putc_cb_t putc_cb) /* I - Write callback */
3050{
3051 const char *s; /* Whitespace string */
3052
3053
3054 if (cb && (s = (*cb)(node, ws)) != NULL)
3055 {
3056 while (*s)
3057 {
3058 if ((*putc_cb)(*s, p) < 0)
3059 return (-1);
3060 else if (*s == '\n')
3061 col = 0;
3062 else if (*s == '\t')
3063 {
3064 col += MXML_TAB;
3065 col = col - (col % MXML_TAB);
3066 }
3067 else
3068 col ++;
3069
3070 s ++;
3071 }
3072 }
3073
3074 return (col);
3075}
3076
3077
3078/*
3079 * End of "$Id: mxml-file.c 438 2011-03-24 05:47:51Z mike $".
3080 */
diff --git a/pathologist/src/minixml/mxml-get.c b/pathologist/src/minixml/mxml-get.c
new file mode 100644
index 0000000..a5356d5
--- /dev/null
+++ b/pathologist/src/minixml/mxml-get.c
@@ -0,0 +1,471 @@
1/*
2 * "$Id: mxml-get.c 427 2011-01-03 02:03:29Z mike $"
3 *
4 * Node get functions for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2011 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * mxmlGetCDATA() - Get the value for a CDATA node.
19 * mxmlGetCustom() - Get the value for a custom node.
20 * mxmlGetElement() - Get the name for an element node.
21 * mxmlGetFirstChild() - Get the first child of an element node.
22 * mxmlGetInteger() - Get the integer value from the specified node or its
23 * first child.
24 * mxmlGetLastChild() - Get the last child of an element node.
25 * mxmlGetNextSibling() - Get the next node for the current parent.
26 * mxmlGetOpaque() - Get an opaque string value for a node or its first
27 * child.
28 * mxmlGetParent() - Get the parent node.
29 * mxmlGetPrevSibling() - Get the previous node for the current parent.
30 * mxmlGetReal() - Get the real value for a node or its first child.
31 * mxmlGetText() - Get the text value for a node or its first child.
32 * mxmlGetType() - Get the node type.
33 * mxmlGetUserData() - Get the user data pointer for a node.
34 */
35
36/*
37 * Include necessary headers...
38 */
39
40#include "config.h"
41#include "mxml.h"
42
43
44/*
45 * 'mxmlGetCDATA()' - Get the value for a CDATA node.
46 *
47 * @code NULL@ is returned if the node is not a CDATA element.
48 *
49 * @since Mini-XML 2.7@
50 */
51
52const char * /* O - CDATA value or NULL */
53mxmlGetCDATA(mxml_node_t *node) /* I - Node to get */
54{
55 /*
56 * Range check input...
57 */
58
59 if (!node || node->type != MXML_ELEMENT ||
60 strncmp(node->value.element.name, "![CDATA[", 8))
61 return (NULL);
62
63 /*
64 * Return the text following the CDATA declaration...
65 */
66
67 return (node->value.element.name + 8);
68}
69
70
71/*
72 * 'mxmlGetCustom()' - Get the value for a custom node.
73 *
74 * @code NULL@ is returned if the node (or its first child) is not a custom
75 * value node.
76 *
77 * @since Mini-XML 2.7@
78 */
79
80const void * /* O - Custom value or NULL */
81mxmlGetCustom(mxml_node_t *node) /* I - Node to get */
82{
83 /*
84 * Range check input...
85 */
86
87 if (!node)
88 return (NULL);
89
90 /*
91 * Return the integer value...
92 */
93
94 if (node->type == MXML_CUSTOM)
95 return (node->value.custom.data);
96 else if (node->type == MXML_ELEMENT &&
97 node->child &&
98 node->child->type == MXML_CUSTOM)
99 return (node->child->value.custom.data);
100 else
101 return (NULL);
102}
103
104
105/*
106 * 'mxmlGetElement()' - Get the name for an element node.
107 *
108 * @code NULL@ is returned if the node is not an element node.
109 *
110 * @since Mini-XML 2.7@
111 */
112
113const char * /* O - Element name or NULL */
114mxmlGetElement(mxml_node_t *node) /* I - Node to get */
115{
116 /*
117 * Range check input...
118 */
119
120 if (!node || node->type != MXML_ELEMENT)
121 return (NULL);
122
123 /*
124 * Return the element name...
125 */
126
127 return (node->value.element.name);
128}
129
130
131/*
132 * 'mxmlGetFirstChild()' - Get the first child of an element node.
133 *
134 * @code NULL@ is returned if the node is not an element node or if the node
135 * has no children.
136 *
137 * @since Mini-XML 2.7@
138 */
139
140mxml_node_t * /* O - First child or NULL */
141mxmlGetFirstChild(mxml_node_t *node) /* I - Node to get */
142{
143 /*
144 * Range check input...
145 */
146
147 if (!node || node->type != MXML_ELEMENT)
148 return (NULL);
149
150 /*
151 * Return the first child node...
152 */
153
154 return (node->child);
155}
156
157
158/*
159 * 'mxmlGetInteger()' - Get the integer value from the specified node or its
160 * first child.
161 *
162 * 0 is returned if the node (or its first child) is not an integer value node.
163 *
164 * @since Mini-XML 2.7@
165 */
166
167int /* O - Integer value or 0 */
168mxmlGetInteger(mxml_node_t *node) /* I - Node to get */
169{
170 /*
171 * Range check input...
172 */
173
174 if (!node)
175 return (0);
176
177 /*
178 * Return the integer value...
179 */
180
181 if (node->type == MXML_INTEGER)
182 return (node->value.integer);
183 else if (node->type == MXML_ELEMENT &&
184 node->child &&
185 node->child->type == MXML_INTEGER)
186 return (node->child->value.integer);
187 else
188 return (0);
189}
190
191
192/*
193 * 'mxmlGetLastChild()' - Get the last child of an element node.
194 *
195 * @code NULL@ is returned if the node is not an element node or if the node
196 * has no children.
197 *
198 * @since Mini-XML 2.7@
199 */
200
201mxml_node_t * /* O - Last child or NULL */
202mxmlGetLastChild(mxml_node_t *node) /* I - Node to get */
203{
204 /*
205 * Range check input...
206 */
207
208 if (!node || node->type != MXML_ELEMENT)
209 return (NULL);
210
211 /*
212 * Return the node type...
213 */
214
215 return (node->last_child);
216}
217
218
219/*
220 * 'mxmlGetNextSibling()' - Get the next node for the current parent.
221 *
222 * @code NULL@ is returned if this is the last child for the current parent.
223 *
224 * @since Mini-XML 2.7@
225 */
226
227mxml_node_t *
228mxmlGetNextSibling(mxml_node_t *node) /* I - Node to get */
229{
230 /*
231 * Range check input...
232 */
233
234 if (!node)
235 return (NULL);
236
237 /*
238 * Return the node type...
239 */
240
241 return (node->next);
242}
243
244
245/*
246 * 'mxmlGetOpaque()' - Get an opaque string value for a node or its first child.
247 *
248 * @code NULL@ is returned if the node (or its first child) is not an opaque
249 * value node.
250 *
251 * @since Mini-XML 2.7@
252 */
253
254const char * /* O - Opaque string or NULL */
255mxmlGetOpaque(mxml_node_t *node) /* I - Node to get */
256{
257 /*
258 * Range check input...
259 */
260
261 if (!node)
262 return (NULL);
263
264 /*
265 * Return the integer value...
266 */
267
268 if (node->type == MXML_OPAQUE)
269 return (node->value.opaque);
270 else if (node->type == MXML_ELEMENT &&
271 node->child &&
272 node->child->type == MXML_OPAQUE)
273 return (node->child->value.opaque);
274 else
275 return (NULL);
276}
277
278
279/*
280 * 'mxmlGetParent()' - Get the parent node.
281 *
282 * @code NULL@ is returned for a root node.
283 *
284 * @since Mini-XML 2.7@
285 */
286
287mxml_node_t * /* O - Parent node or NULL */
288mxmlGetParent(mxml_node_t *node) /* I - Node to get */
289{
290 /*
291 * Range check input...
292 */
293
294 if (!node)
295 return (NULL);
296
297 /*
298 * Return the node type...
299 */
300
301 return (node->parent);
302}
303
304
305/*
306 * 'mxmlGetPrevSibling()' - Get the previous node for the current parent.
307 *
308 * @code NULL@ is returned if this is the first child for the current parent.
309 *
310 * @since Mini-XML 2.7@
311 */
312
313mxml_node_t * /* O - Previous node or NULL */
314mxmlGetPrevSibling(mxml_node_t *node) /* I - Node to get */
315{
316 /*
317 * Range check input...
318 */
319
320 if (!node)
321 return (NULL);
322
323 /*
324 * Return the node type...
325 */
326
327 return (node->prev);
328}
329
330
331/*
332 * 'mxmlGetReal()' - Get the real value for a node or its first child.
333 *
334 * 0.0 is returned if the node (or its first child) is not a real value node.
335 *
336 * @since Mini-XML 2.7@
337 */
338
339double /* O - Real value or 0.0 */
340mxmlGetReal(mxml_node_t *node) /* I - Node to get */
341{
342 /*
343 * Range check input...
344 */
345
346 if (!node)
347 return (0.0);
348
349 /*
350 * Return the integer value...
351 */
352
353 if (node->type == MXML_REAL)
354 return (node->value.real);
355 else if (node->type == MXML_ELEMENT &&
356 node->child &&
357 node->child->type == MXML_REAL)
358 return (node->child->value.real);
359 else
360 return (0.0);
361}
362
363
364/*
365 * 'mxmlGetText()' - Get the text value for a node or its first child.
366 *
367 * @code NULL@ is returned if the node (or its first child) is not a text node.
368 * The "whitespace" argument can be NULL.
369 *
370 * @since Mini-XML 2.7@
371 */
372
373const char * /* O - Text string or NULL */
374mxmlGetText(mxml_node_t *node, /* I - Node to get */
375 int *whitespace) /* O - 1 if string is preceded by whitespace, 0 otherwise */
376{
377 /*
378 * Range check input...
379 */
380
381 if (!node)
382 {
383 if (whitespace)
384 *whitespace = 0;
385
386 return (NULL);
387 }
388
389 /*
390 * Return the integer value...
391 */
392
393 if (node->type == MXML_TEXT)
394 {
395 if (whitespace)
396 *whitespace = node->value.text.whitespace;
397
398 return (node->value.text.string);
399 }
400 else if (node->type == MXML_ELEMENT &&
401 node->child &&
402 node->child->type == MXML_TEXT)
403 {
404 if (whitespace)
405 *whitespace = node->child->value.text.whitespace;
406
407 return (node->child->value.text.string);
408 }
409 else
410 {
411 if (whitespace)
412 *whitespace = 0;
413
414 return (NULL);
415 }
416}
417
418
419/*
420 * 'mxmlGetType()' - Get the node type.
421 *
422 * @code MXML_IGNORE@ is returned if "node" is @code NULL@.
423 *
424 * @since Mini-XML 2.7@
425 */
426
427mxml_type_t /* O - Type of node */
428mxmlGetType(mxml_node_t *node) /* I - Node to get */
429{
430 /*
431 * Range check input...
432 */
433
434 if (!node)
435 return (MXML_IGNORE);
436
437 /*
438 * Return the node type...
439 */
440
441 return (node->type);
442}
443
444
445/*
446 * 'mxmlGetUserData()' - Get the user data pointer for a node.
447 *
448 * @since Mini-XML 2.7@
449 */
450
451void * /* O - User data pointer */
452mxmlGetUserData(mxml_node_t *node) /* I - Node to get */
453{
454 /*
455 * Range check input...
456 */
457
458 if (!node)
459 return (NULL);
460
461 /*
462 * Return the user data pointer...
463 */
464
465 return (node->user_data);
466}
467
468
469/*
470 * End of "$Id: mxml-get.c 427 2011-01-03 02:03:29Z mike $".
471 */
diff --git a/pathologist/src/minixml/mxml-index.c b/pathologist/src/minixml/mxml-index.c
new file mode 100644
index 0000000..b6efc66
--- /dev/null
+++ b/pathologist/src/minixml/mxml-index.c
@@ -0,0 +1,662 @@
1/*
2 * "$Id: mxml-index.c 426 2011-01-01 23:42:17Z mike $"
3 *
4 * Index support code for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2011 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 */
19
20/*
21 * Include necessary headers...
22 */
23
24#include "config.h"
25#include "mxml.h"
26
27
28/*
29 * Sort functions...
30 */
31
32static int index_compare(mxml_index_t *ind, mxml_node_t *first,
33 mxml_node_t *second);
34static int index_find(mxml_index_t *ind, const char *element,
35 const char *value, mxml_node_t *node);
36static void index_sort(mxml_index_t *ind, int left, int right);
37
38
39/*
40 * 'mxmlIndexDelete()' - Delete an index.
41 */
42
43void
44mxmlIndexDelete(mxml_index_t *ind) /* I - Index to delete */
45{
46 /*
47 * Range check input..
48 */
49
50 if (!ind)
51 return;
52
53 /*
54 * Free memory...
55 */
56
57 if (ind->attr)
58 free(ind->attr);
59
60 if (ind->alloc_nodes)
61 free(ind->nodes);
62
63 free(ind);
64}
65
66
67/*
68 * 'mxmlIndexEnum()' - Return the next node in the index.
69 *
70 * Nodes are returned in the sorted order of the index.
71 */
72
73mxml_node_t * /* O - Next node or NULL if there is none */
74mxmlIndexEnum(mxml_index_t *ind) /* I - Index to enumerate */
75{
76 /*
77 * Range check input...
78 */
79
80 if (!ind)
81 return (NULL);
82
83 /*
84 * Return the next node...
85 */
86
87 if (ind->cur_node < ind->num_nodes)
88 return (ind->nodes[ind->cur_node ++]);
89 else
90 return (NULL);
91}
92
93
94/*
95 * 'mxmlIndexFind()' - Find the next matching node.
96 *
97 * You should call mxmlIndexReset() prior to using this function for
98 * the first time with a particular set of "element" and "value"
99 * strings. Passing NULL for both "element" and "value" is equivalent
100 * to calling mxmlIndexEnum().
101 */
102
103mxml_node_t * /* O - Node or NULL if none found */
104mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */
105 const char *element, /* I - Element name to find, if any */
106 const char *value) /* I - Attribute value, if any */
107{
108 int diff, /* Difference between names */
109 current, /* Current entity in search */
110 first, /* First entity in search */
111 last; /* Last entity in search */
112
113
114#ifdef DEBUG
115 printf("mxmlIndexFind(ind=%p, element=\"%s\", value=\"%s\")\n",
116 ind, element ? element : "(null)", value ? value : "(null)");
117#endif /* DEBUG */
118
119 /*
120 * Range check input...
121 */
122
123 if (!ind || (!ind->attr && value))
124 {
125#ifdef DEBUG
126 puts(" returning NULL...");
127 printf(" ind->attr=\"%s\"\n", ind->attr ? ind->attr : "(null)");
128#endif /* DEBUG */
129
130 return (NULL);
131 }
132
133 /*
134 * If both element and value are NULL, just enumerate the nodes in the
135 * index...
136 */
137
138 if (!element && !value)
139 return (mxmlIndexEnum(ind));
140
141 /*
142 * If there are no nodes in the index, return NULL...
143 */
144
145 if (!ind->num_nodes)
146 {
147#ifdef DEBUG
148 puts(" returning NULL...");
149 puts(" no nodes!");
150#endif /* DEBUG */
151
152 return (NULL);
153 }
154
155 /*
156 * If cur_node == 0, then find the first matching node...
157 */
158
159 if (ind->cur_node == 0)
160 {
161 /*
162 * Find the first node using a modified binary search algorithm...
163 */
164
165 first = 0;
166 last = ind->num_nodes - 1;
167
168#ifdef DEBUG
169 printf(" find first time, num_nodes=%d...\n", ind->num_nodes);
170#endif /* DEBUG */
171
172 while ((last - first) > 1)
173 {
174 current = (first + last) / 2;
175
176#ifdef DEBUG
177 printf(" first=%d, last=%d, current=%d\n", first, last, current);
178#endif /* DEBUG */
179
180 if ((diff = index_find(ind, element, value, ind->nodes[current])) == 0)
181 {
182 /*
183 * Found a match, move back to find the first...
184 */
185
186#ifdef DEBUG
187 puts(" match!");
188#endif /* DEBUG */
189
190 while (current > 0 &&
191 !index_find(ind, element, value, ind->nodes[current - 1]))
192 current --;
193
194#ifdef DEBUG
195 printf(" returning first match=%d\n", current);
196#endif /* DEBUG */
197
198 /*
199 * Return the first match and save the index to the next...
200 */
201
202 ind->cur_node = current + 1;
203
204 return (ind->nodes[current]);
205 }
206 else if (diff < 0)
207 last = current;
208 else
209 first = current;
210
211#ifdef DEBUG
212 printf(" diff=%d\n", diff);
213#endif /* DEBUG */
214 }
215
216 /*
217 * If we get this far, then we found exactly 0 or 1 matches...
218 */
219
220 for (current = first; current <= last; current ++)
221 if (!index_find(ind, element, value, ind->nodes[current]))
222 {
223 /*
224 * Found exactly one (or possibly two) match...
225 */
226
227#ifdef DEBUG
228 printf(" returning only match %d...\n", current);
229#endif /* DEBUG */
230
231 ind->cur_node = current + 1;
232
233 return (ind->nodes[current]);
234 }
235
236 /*
237 * No matches...
238 */
239
240 ind->cur_node = ind->num_nodes;
241
242#ifdef DEBUG
243 puts(" returning NULL...");
244#endif /* DEBUG */
245
246 return (NULL);
247 }
248 else if (ind->cur_node < ind->num_nodes &&
249 !index_find(ind, element, value, ind->nodes[ind->cur_node]))
250 {
251 /*
252 * Return the next matching node...
253 */
254
255#ifdef DEBUG
256 printf(" returning next match %d...\n", ind->cur_node);
257#endif /* DEBUG */
258
259 return (ind->nodes[ind->cur_node ++]);
260 }
261
262 /*
263 * If we get this far, then we have no matches...
264 */
265
266 ind->cur_node = ind->num_nodes;
267
268#ifdef DEBUG
269 puts(" returning NULL...");
270#endif /* DEBUG */
271
272 return (NULL);
273}
274
275
276/*
277 * 'mxmlIndexGetCount()' - Get the number of nodes in an index.
278 *
279 * @since Mini-XML 2.7@
280 */
281
282int /* I - Number of nodes in index */
283mxmlIndexGetCount(mxml_index_t *ind) /* I - Index of nodes */
284{
285 /*
286 * Range check input...
287 */
288
289 if (!ind)
290 return (0);
291
292 /*
293 * Return the number of nodes in the index...
294 */
295
296 return (ind->num_nodes);
297}
298
299
300/*
301 * 'mxmlIndexNew()' - Create a new index.
302 *
303 * The index will contain all nodes that contain the named element and/or
304 * attribute. If both "element" and "attr" are NULL, then the index will
305 * contain a sorted list of the elements in the node tree. Nodes are
306 * sorted by element name and optionally by attribute value if the "attr"
307 * argument is not NULL.
308 */
309
310mxml_index_t * /* O - New index */
311mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */
312 const char *element, /* I - Element to index or NULL for all */
313 const char *attr) /* I - Attribute to index or NULL for none */
314{
315 mxml_index_t *ind; /* New index */
316 mxml_node_t *current, /* Current node in index */
317 **temp; /* Temporary node pointer array */
318
319
320 /*
321 * Range check input...
322 */
323
324#ifdef DEBUG
325 printf("mxmlIndexNew(node=%p, element=\"%s\", attr=\"%s\")\n",
326 node, element ? element : "(null)", attr ? attr : "(null)");
327#endif /* DEBUG */
328
329 if (!node)
330 return (NULL);
331
332 /*
333 * Create a new index...
334 */
335
336 if ((ind = calloc(1, sizeof(mxml_index_t))) == NULL)
337 {
338 mxml_error("Unable to allocate %d bytes for index - %s",
339 sizeof(mxml_index_t), strerror(errno));
340 return (NULL);
341 }
342
343 if (attr)
344 ind->attr = strdup(attr);
345
346 if (!element && !attr)
347 current = node;
348 else
349 current = mxmlFindElement(node, node, element, attr, NULL, MXML_DESCEND);
350
351 while (current)
352 {
353 if (ind->num_nodes >= ind->alloc_nodes)
354 {
355 if (!ind->alloc_nodes)
356 temp = malloc(64 * sizeof(mxml_node_t *));
357 else
358 temp = realloc(ind->nodes, (ind->alloc_nodes + 64) * sizeof(mxml_node_t *));
359
360 if (!temp)
361 {
362 /*
363 * Unable to allocate memory for the index, so abort...
364 */
365
366 mxml_error("Unable to allocate %d bytes for index: %s",
367 (ind->alloc_nodes + 64) * sizeof(mxml_node_t *),
368 strerror(errno));
369
370 mxmlIndexDelete(ind);
371 return (NULL);
372 }
373
374 ind->nodes = temp;
375 ind->alloc_nodes += 64;
376 }
377
378 ind->nodes[ind->num_nodes ++] = current;
379
380 current = mxmlFindElement(current, node, element, attr, NULL, MXML_DESCEND);
381 }
382
383 /*
384 * Sort nodes based upon the search criteria...
385 */
386
387#ifdef DEBUG
388 {
389 int i; /* Looping var */
390
391
392 printf("%d node(s) in index.\n\n", ind->num_nodes);
393
394 if (attr)
395 {
396 printf("Node Address Element %s\n", attr);
397 puts("-------- -------- -------------- ------------------------------");
398
399 for (i = 0; i < ind->num_nodes; i ++)
400 printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i],
401 ind->nodes[i]->value.element.name,
402 mxmlElementGetAttr(ind->nodes[i], attr));
403 }
404 else
405 {
406 puts("Node Address Element");
407 puts("-------- -------- --------------");
408
409 for (i = 0; i < ind->num_nodes; i ++)
410 printf("%8d %-8p %s\n", i, ind->nodes[i],
411 ind->nodes[i]->value.element.name);
412 }
413
414 putchar('\n');
415 }
416#endif /* DEBUG */
417
418 if (ind->num_nodes > 1)
419 index_sort(ind, 0, ind->num_nodes - 1);
420
421#ifdef DEBUG
422 {
423 int i; /* Looping var */
424
425
426 puts("After sorting:\n");
427
428 if (attr)
429 {
430 printf("Node Address Element %s\n", attr);
431 puts("-------- -------- -------------- ------------------------------");
432
433 for (i = 0; i < ind->num_nodes; i ++)
434 printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i],
435 ind->nodes[i]->value.element.name,
436 mxmlElementGetAttr(ind->nodes[i], attr));
437 }
438 else
439 {
440 puts("Node Address Element");
441 puts("-------- -------- --------------");
442
443 for (i = 0; i < ind->num_nodes; i ++)
444 printf("%8d %-8p %s\n", i, ind->nodes[i],
445 ind->nodes[i]->value.element.name);
446 }
447
448 putchar('\n');
449 }
450#endif /* DEBUG */
451
452 /*
453 * Return the new index...
454 */
455
456 return (ind);
457}
458
459
460/*
461 * 'mxmlIndexReset()' - Reset the enumeration/find pointer in the index and
462 * return the first node in the index.
463 *
464 * This function should be called prior to using mxmlIndexEnum() or
465 * mxmlIndexFind() for the first time.
466 */
467
468mxml_node_t * /* O - First node or NULL if there is none */
469mxmlIndexReset(mxml_index_t *ind) /* I - Index to reset */
470{
471#ifdef DEBUG
472 printf("mxmlIndexReset(ind=%p)\n", ind);
473#endif /* DEBUG */
474
475 /*
476 * Range check input...
477 */
478
479 if (!ind)
480 return (NULL);
481
482 /*
483 * Set the index to the first element...
484 */
485
486 ind->cur_node = 0;
487
488 /*
489 * Return the first node...
490 */
491
492 if (ind->num_nodes)
493 return (ind->nodes[0]);
494 else
495 return (NULL);
496}
497
498
499/*
500 * 'index_compare()' - Compare two nodes.
501 */
502
503static int /* O - Result of comparison */
504index_compare(mxml_index_t *ind, /* I - Index */
505 mxml_node_t *first, /* I - First node */
506 mxml_node_t *second) /* I - Second node */
507{
508 int diff; /* Difference */
509
510
511 /*
512 * Check the element name...
513 */
514
515 if ((diff = strcmp(first->value.element.name,
516 second->value.element.name)) != 0)
517 return (diff);
518
519 /*
520 * Check the attribute value...
521 */
522
523 if (ind->attr)
524 {
525 if ((diff = strcmp(mxmlElementGetAttr(first, ind->attr),
526 mxmlElementGetAttr(second, ind->attr))) != 0)
527 return (diff);
528 }
529
530 /*
531 * No difference, return 0...
532 */
533
534 return (0);
535}
536
537
538/*
539 * 'index_find()' - Compare a node with index values.
540 */
541
542static int /* O - Result of comparison */
543index_find(mxml_index_t *ind, /* I - Index */
544 const char *element, /* I - Element name or NULL */
545 const char *value, /* I - Attribute value or NULL */
546 mxml_node_t *node) /* I - Node */
547{
548 int diff; /* Difference */
549
550
551 /*
552 * Check the element name...
553 */
554
555 if (element)
556 {
557 if ((diff = strcmp(element, node->value.element.name)) != 0)
558 return (diff);
559 }
560
561 /*
562 * Check the attribute value...
563 */
564
565 if (value)
566 {
567 if ((diff = strcmp(value, mxmlElementGetAttr(node, ind->attr))) != 0)
568 return (diff);
569 }
570
571 /*
572 * No difference, return 0...
573 */
574
575 return (0);
576}
577
578
579/*
580 * 'index_sort()' - Sort the nodes in the index...
581 *
582 * This function implements the classic quicksort algorithm...
583 */
584
585static void
586index_sort(mxml_index_t *ind, /* I - Index to sort */
587 int left, /* I - Left node in partition */
588 int right) /* I - Right node in partition */
589{
590 mxml_node_t *pivot, /* Pivot node */
591 *temp; /* Swap node */
592 int templ, /* Temporary left node */
593 tempr; /* Temporary right node */
594
595
596 /*
597 * Loop until we have sorted all the way to the right...
598 */
599
600 do
601 {
602 /*
603 * Sort the pivot in the current partition...
604 */
605
606 pivot = ind->nodes[left];
607
608 for (templ = left, tempr = right; templ < tempr;)
609 {
610 /*
611 * Move left while left node <= pivot node...
612 */
613
614 while ((templ < right) &&
615 index_compare(ind, ind->nodes[templ], pivot) <= 0)
616 templ ++;
617
618 /*
619 * Move right while right node > pivot node...
620 */
621
622 while ((tempr > left) &&
623 index_compare(ind, ind->nodes[tempr], pivot) > 0)
624 tempr --;
625
626 /*
627 * Swap nodes if needed...
628 */
629
630 if (templ < tempr)
631 {
632 temp = ind->nodes[templ];
633 ind->nodes[templ] = ind->nodes[tempr];
634 ind->nodes[tempr] = temp;
635 }
636 }
637
638 /*
639 * When we get here, the right (tempr) node is the new position for the
640 * pivot node...
641 */
642
643 if (index_compare(ind, pivot, ind->nodes[tempr]) > 0)
644 {
645 ind->nodes[left] = ind->nodes[tempr];
646 ind->nodes[tempr] = pivot;
647 }
648
649 /*
650 * Recursively sort the left partition as needed...
651 */
652
653 if (left < (tempr - 1))
654 index_sort(ind, left, tempr - 1);
655 }
656 while (right > (left = tempr + 1));
657}
658
659
660/*
661 * End of "$Id: mxml-index.c 426 2011-01-01 23:42:17Z mike $".
662 */
diff --git a/pathologist/src/minixml/mxml-node.c b/pathologist/src/minixml/mxml-node.c
new file mode 100644
index 0000000..44af759
--- /dev/null
+++ b/pathologist/src/minixml/mxml-node.c
@@ -0,0 +1,807 @@
1/*
2 * "$Id: mxml-node.c 436 2011-01-22 01:02:05Z mike $"
3 *
4 * Node support code for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2011 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * mxmlAdd() - Add a node to a tree.
19 * mxmlDelete() - Delete a node and all of its children.
20 * mxmlGetRefCount() - Get the current reference (use) count for a node.
21 * mxmlNewCDATA() - Create a new CDATA node.
22 * mxmlNewCustom() - Create a new custom data node.
23 * mxmlNewElement() - Create a new element node.
24 * mxmlNewInteger() - Create a new integer node.
25 * mxmlNewOpaque() - Create a new opaque string.
26 * mxmlNewReal() - Create a new real number node.
27 * mxmlNewText() - Create a new text fragment node.
28 * mxmlNewTextf() - Create a new formatted text fragment node.
29 * mxmlRemove() - Remove a node from its parent.
30 * mxmlNewXML() - Create a new XML document tree.
31 * mxmlRelease() - Release a node.
32 * mxmlRetain() - Retain a node.
33 * mxml_new() - Create a new node.
34 */
35
36/*
37 * Include necessary headers...
38 */
39
40#include "config.h"
41#include "mxml.h"
42
43
44/*
45 * Local functions...
46 */
47
48static mxml_node_t *mxml_new(mxml_node_t *parent, mxml_type_t type);
49
50
51/*
52 * 'mxmlAdd()' - Add a node to a tree.
53 *
54 * Adds the specified node to the parent. If the child argument is not
55 * NULL, puts the new node before or after the specified child depending
56 * on the value of the where argument. If the child argument is NULL,
57 * puts the new node at the beginning of the child list (MXML_ADD_BEFORE)
58 * or at the end of the child list (MXML_ADD_AFTER). The constant
59 * MXML_ADD_TO_PARENT can be used to specify a NULL child pointer.
60 */
61
62void
63mxmlAdd(mxml_node_t *parent, /* I - Parent node */
64 int where, /* I - Where to add, MXML_ADD_BEFORE or MXML_ADD_AFTER */
65 mxml_node_t *child, /* I - Child node for where or MXML_ADD_TO_PARENT */
66 mxml_node_t *node) /* I - Node to add */
67{
68#ifdef DEBUG
69 fprintf(stderr, "mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\n", parent,
70 where, child, node);
71#endif /* DEBUG */
72
73 /*
74 * Range check input...
75 */
76
77 if (!parent || !node)
78 return;
79
80#if DEBUG > 1
81 fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent);
82 if (parent)
83 {
84 fprintf(stderr, " BEFORE: parent->child=%p\n", parent->child);
85 fprintf(stderr, " BEFORE: parent->last_child=%p\n", parent->last_child);
86 fprintf(stderr, " BEFORE: parent->prev=%p\n", parent->prev);
87 fprintf(stderr, " BEFORE: parent->next=%p\n", parent->next);
88 }
89#endif /* DEBUG > 1 */
90
91 /*
92 * Remove the node from any existing parent...
93 */
94
95 if (node->parent)
96 mxmlRemove(node);
97
98 /*
99 * Reset pointers...
100 */
101
102 node->parent = parent;
103
104 switch (where)
105 {
106 case MXML_ADD_BEFORE :
107 if (!child || child == parent->child || child->parent != parent)
108 {
109 /*
110 * Insert as first node under parent...
111 */
112
113 node->next = parent->child;
114
115 if (parent->child)
116 parent->child->prev = node;
117 else
118 parent->last_child = node;
119
120 parent->child = node;
121 }
122 else
123 {
124 /*
125 * Insert node before this child...
126 */
127
128 node->next = child;
129 node->prev = child->prev;
130
131 if (child->prev)
132 child->prev->next = node;
133 else
134 parent->child = node;
135
136 child->prev = node;
137 }
138 break;
139
140 case MXML_ADD_AFTER :
141 if (!child || child == parent->last_child || child->parent != parent)
142 {
143 /*
144 * Insert as last node under parent...
145 */
146
147 node->parent = parent;
148 node->prev = parent->last_child;
149
150 if (parent->last_child)
151 parent->last_child->next = node;
152 else
153 parent->child = node;
154
155 parent->last_child = node;
156 }
157 else
158 {
159 /*
160 * Insert node after this child...
161 */
162
163 node->prev = child;
164 node->next = child->next;
165
166 if (child->next)
167 child->next->prev = node;
168 else
169 parent->last_child = node;
170
171 child->next = node;
172 }
173 break;
174 }
175
176#if DEBUG > 1
177 fprintf(stderr, " AFTER: node->parent=%p\n", node->parent);
178 if (parent)
179 {
180 fprintf(stderr, " AFTER: parent->child=%p\n", parent->child);
181 fprintf(stderr, " AFTER: parent->last_child=%p\n", parent->last_child);
182 fprintf(stderr, " AFTER: parent->prev=%p\n", parent->prev);
183 fprintf(stderr, " AFTER: parent->next=%p\n", parent->next);
184 }
185#endif /* DEBUG > 1 */
186}
187
188
189/*
190 * 'mxmlDelete()' - Delete a node and all of its children.
191 *
192 * If the specified node has a parent, this function first removes the
193 * node from its parent using the mxmlRemove() function.
194 */
195
196void
197mxmlDelete(mxml_node_t *node) /* I - Node to delete */
198{
199 int i; /* Looping var */
200
201
202#ifdef DEBUG
203 fprintf(stderr, "mxmlDelete(node=%p)\n", node);
204#endif /* DEBUG */
205
206 /*
207 * Range check input...
208 */
209
210 if (!node)
211 return;
212
213 /*
214 * Remove the node from its parent, if any...
215 */
216
217 mxmlRemove(node);
218
219 /*
220 * Delete children...
221 */
222
223 while (node->child)
224 mxmlDelete(node->child);
225
226 /*
227 * Now delete any node data...
228 */
229
230 switch (node->type)
231 {
232 case MXML_ELEMENT :
233 if (node->value.element.name)
234 free(node->value.element.name);
235
236 if (node->value.element.num_attrs)
237 {
238 for (i = 0; i < node->value.element.num_attrs; i ++)
239 {
240 if (node->value.element.attrs[i].name)
241 free(node->value.element.attrs[i].name);
242 if (node->value.element.attrs[i].value)
243 free(node->value.element.attrs[i].value);
244 }
245
246 free(node->value.element.attrs);
247 }
248 break;
249 case MXML_INTEGER :
250 /* Nothing to do */
251 break;
252 case MXML_OPAQUE :
253 if (node->value.opaque)
254 free(node->value.opaque);
255 break;
256 case MXML_REAL :
257 /* Nothing to do */
258 break;
259 case MXML_TEXT :
260 if (node->value.text.string)
261 free(node->value.text.string);
262 break;
263 case MXML_CUSTOM :
264 if (node->value.custom.data &&
265 node->value.custom.destroy)
266 (*(node->value.custom.destroy))(node->value.custom.data);
267 break;
268 default :
269 break;
270 }
271
272 /*
273 * Free this node...
274 */
275
276 free(node);
277}
278
279
280/*
281 * 'mxmlGetRefCount()' - Get the current reference (use) count for a node.
282 *
283 * The initial reference count of new nodes is 1. Use the @link mxmlRetain@
284 * and @link mxmlRelease@ functions to increment and decrement a node's
285 * reference count.
286 *
287 * @since Mini-XML 2.7@.
288 */
289
290int /* O - Reference count */
291mxmlGetRefCount(mxml_node_t *node) /* I - Node */
292{
293 /*
294 * Range check input...
295 */
296
297 if (!node)
298 return (0);
299
300 /*
301 * Return the reference count...
302 */
303
304 return (node->ref_count);
305}
306
307
308/*
309 * 'mxmlNewCDATA()' - Create a new CDATA node.
310 *
311 * The new CDATA node is added to the end of the specified parent's child
312 * list. The constant MXML_NO_PARENT can be used to specify that the new
313 * CDATA node has no parent. The data string must be nul-terminated and
314 * is copied into the new node. CDATA nodes use the MXML_ELEMENT type.
315 *
316 * @since Mini-XML 2.3@
317 */
318
319mxml_node_t * /* O - New node */
320mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
321 const char *data) /* I - Data string */
322{
323 mxml_node_t *node; /* New node */
324
325
326#ifdef DEBUG
327 fprintf(stderr, "mxmlNewCDATA(parent=%p, data=\"%s\")\n",
328 parent, data ? data : "(null)");
329#endif /* DEBUG */
330
331 /*
332 * Range check input...
333 */
334
335 if (!data)
336 return (NULL);
337
338 /*
339 * Create the node and set the name value...
340 */
341
342 if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)
343 node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data);
344
345 return (node);
346}
347
348
349/*
350 * 'mxmlNewCustom()' - Create a new custom data node.
351 *
352 * The new custom node is added to the end of the specified parent's child
353 * list. The constant MXML_NO_PARENT can be used to specify that the new
354 * element node has no parent. NULL can be passed when the data in the
355 * node is not dynamically allocated or is separately managed.
356 *
357 * @since Mini-XML 2.1@
358 */
359
360mxml_node_t * /* O - New node */
361mxmlNewCustom(
362 mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
363 void *data, /* I - Pointer to data */
364 mxml_custom_destroy_cb_t destroy) /* I - Function to destroy data */
365{
366 mxml_node_t *node; /* New node */
367
368
369#ifdef DEBUG
370 fprintf(stderr, "mxmlNewCustom(parent=%p, data=%p, destroy=%p)\n", parent,
371 data, destroy);
372#endif /* DEBUG */
373
374 /*
375 * Create the node and set the value...
376 */
377
378 if ((node = mxml_new(parent, MXML_CUSTOM)) != NULL)
379 {
380 node->value.custom.data = data;
381 node->value.custom.destroy = destroy;
382 }
383
384 return (node);
385}
386
387
388/*
389 * 'mxmlNewElement()' - Create a new element node.
390 *
391 * The new element node is added to the end of the specified parent's child
392 * list. The constant MXML_NO_PARENT can be used to specify that the new
393 * element node has no parent.
394 */
395
396mxml_node_t * /* O - New node */
397mxmlNewElement(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
398 const char *name) /* I - Name of element */
399{
400 mxml_node_t *node; /* New node */
401
402
403#ifdef DEBUG
404 fprintf(stderr, "mxmlNewElement(parent=%p, name=\"%s\")\n", parent,
405 name ? name : "(null)");
406#endif /* DEBUG */
407
408 /*
409 * Range check input...
410 */
411
412 if (!name)
413 return (NULL);
414
415 /*
416 * Create the node and set the element name...
417 */
418
419 if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)
420 node->value.element.name = strdup(name);
421
422 return (node);
423}
424
425
426/*
427 * 'mxmlNewInteger()' - Create a new integer node.
428 *
429 * The new integer node is added to the end of the specified parent's child
430 * list. The constant MXML_NO_PARENT can be used to specify that the new
431 * integer node has no parent.
432 */
433
434mxml_node_t * /* O - New node */
435mxmlNewInteger(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
436 int integer) /* I - Integer value */
437{
438 mxml_node_t *node; /* New node */
439
440
441#ifdef DEBUG
442 fprintf(stderr, "mxmlNewInteger(parent=%p, integer=%d)\n", parent, integer);
443#endif /* DEBUG */
444
445 /*
446 * Create the node and set the element name...
447 */
448
449 if ((node = mxml_new(parent, MXML_INTEGER)) != NULL)
450 node->value.integer = integer;
451
452 return (node);
453}
454
455
456/*
457 * 'mxmlNewOpaque()' - Create a new opaque string.
458 *
459 * The new opaque node is added to the end of the specified parent's child
460 * list. The constant MXML_NO_PARENT can be used to specify that the new
461 * opaque node has no parent. The opaque string must be nul-terminated and
462 * is copied into the new node.
463 */
464
465mxml_node_t * /* O - New node */
466mxmlNewOpaque(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
467 const char *opaque) /* I - Opaque string */
468{
469 mxml_node_t *node; /* New node */
470
471
472#ifdef DEBUG
473 fprintf(stderr, "mxmlNewOpaque(parent=%p, opaque=\"%s\")\n", parent,
474 opaque ? opaque : "(null)");
475#endif /* DEBUG */
476
477 /*
478 * Range check input...
479 */
480
481 if (!opaque)
482 return (NULL);
483
484 /*
485 * Create the node and set the element name...
486 */
487
488 if ((node = mxml_new(parent, MXML_OPAQUE)) != NULL)
489 node->value.opaque = strdup(opaque);
490
491 return (node);
492}
493
494
495/*
496 * 'mxmlNewReal()' - Create a new real number node.
497 *
498 * The new real number node is added to the end of the specified parent's
499 * child list. The constant MXML_NO_PARENT can be used to specify that
500 * the new real number node has no parent.
501 */
502
503mxml_node_t * /* O - New node */
504mxmlNewReal(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
505 double real) /* I - Real number value */
506{
507 mxml_node_t *node; /* New node */
508
509
510#ifdef DEBUG
511 fprintf(stderr, "mxmlNewReal(parent=%p, real=%g)\n", parent, real);
512#endif /* DEBUG */
513
514 /*
515 * Create the node and set the element name...
516 */
517
518 if ((node = mxml_new(parent, MXML_REAL)) != NULL)
519 node->value.real = real;
520
521 return (node);
522}
523
524
525/*
526 * 'mxmlNewText()' - Create a new text fragment node.
527 *
528 * The new text node is added to the end of the specified parent's child
529 * list. The constant MXML_NO_PARENT can be used to specify that the new
530 * text node has no parent. The whitespace parameter is used to specify
531 * whether leading whitespace is present before the node. The text
532 * string must be nul-terminated and is copied into the new node.
533 */
534
535mxml_node_t * /* O - New node */
536mxmlNewText(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
537 int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
538 const char *string) /* I - String */
539{
540 mxml_node_t *node; /* New node */
541
542
543#ifdef DEBUG
544 fprintf(stderr, "mxmlNewText(parent=%p, whitespace=%d, string=\"%s\")\n",
545 parent, whitespace, string ? string : "(null)");
546#endif /* DEBUG */
547
548 /*
549 * Range check input...
550 */
551
552 if (!string)
553 return (NULL);
554
555 /*
556 * Create the node and set the text value...
557 */
558
559 if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
560 {
561 node->value.text.whitespace = whitespace;
562 node->value.text.string = strdup(string);
563 }
564
565 return (node);
566}
567
568
569/*
570 * 'mxmlNewTextf()' - Create a new formatted text fragment node.
571 *
572 * The new text node is added to the end of the specified parent's child
573 * list. The constant MXML_NO_PARENT can be used to specify that the new
574 * text node has no parent. The whitespace parameter is used to specify
575 * whether leading whitespace is present before the node. The format
576 * string must be nul-terminated and is formatted into the new node.
577 */
578
579mxml_node_t * /* O - New node */
580mxmlNewTextf(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
581 int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
582 const char *format, /* I - Printf-style frmat string */
583 ...) /* I - Additional args as needed */
584{
585 mxml_node_t *node; /* New node */
586 va_list ap; /* Pointer to arguments */
587
588
589#ifdef DEBUG
590 fprintf(stderr, "mxmlNewTextf(parent=%p, whitespace=%d, format=\"%s\", ...)\n",
591 parent, whitespace, format ? format : "(null)");
592#endif /* DEBUG */
593
594 /*
595 * Range check input...
596 */
597
598 if (!format)
599 return (NULL);
600
601 /*
602 * Create the node and set the text value...
603 */
604
605 if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
606 {
607 va_start(ap, format);
608
609 node->value.text.whitespace = whitespace;
610 node->value.text.string = _mxml_vstrdupf(format, ap);
611
612 va_end(ap);
613 }
614
615 return (node);
616}
617
618
619/*
620 * 'mxmlRemove()' - Remove a node from its parent.
621 *
622 * Does not free memory used by the node - use mxmlDelete() for that.
623 * This function does nothing if the node has no parent.
624 */
625
626void
627mxmlRemove(mxml_node_t *node) /* I - Node to remove */
628{
629#ifdef DEBUG
630 fprintf(stderr, "mxmlRemove(node=%p)\n", node);
631#endif /* DEBUG */
632
633 /*
634 * Range check input...
635 */
636
637 if (!node || !node->parent)
638 return;
639
640 /*
641 * Remove from parent...
642 */
643
644#if DEBUG > 1
645 fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent);
646 if (node->parent)
647 {
648 fprintf(stderr, " BEFORE: node->parent->child=%p\n", node->parent->child);
649 fprintf(stderr, " BEFORE: node->parent->last_child=%p\n", node->parent->last_child);
650 }
651 fprintf(stderr, " BEFORE: node->child=%p\n", node->child);
652 fprintf(stderr, " BEFORE: node->last_child=%p\n", node->last_child);
653 fprintf(stderr, " BEFORE: node->prev=%p\n", node->prev);
654 fprintf(stderr, " BEFORE: node->next=%p\n", node->next);
655#endif /* DEBUG > 1 */
656
657 if (node->prev)
658 node->prev->next = node->next;
659 else
660 node->parent->child = node->next;
661
662 if (node->next)
663 node->next->prev = node->prev;
664 else
665 node->parent->last_child = node->prev;
666
667 node->parent = NULL;
668 node->prev = NULL;
669 node->next = NULL;
670
671#if DEBUG > 1
672 fprintf(stderr, " AFTER: node->parent=%p\n", node->parent);
673 if (node->parent)
674 {
675 fprintf(stderr, " AFTER: node->parent->child=%p\n", node->parent->child);
676 fprintf(stderr, " AFTER: node->parent->last_child=%p\n", node->parent->last_child);
677 }
678 fprintf(stderr, " AFTER: node->child=%p\n", node->child);
679 fprintf(stderr, " AFTER: node->last_child=%p\n", node->last_child);
680 fprintf(stderr, " AFTER: node->prev=%p\n", node->prev);
681 fprintf(stderr, " AFTER: node->next=%p\n", node->next);
682#endif /* DEBUG > 1 */
683}
684
685
686/*
687 * 'mxmlNewXML()' - Create a new XML document tree.
688 *
689 * The "version" argument specifies the version number to put in the
690 * ?xml element node. If NULL, version 1.0 is assumed.
691 *
692 * @since Mini-XML 2.3@
693 */
694
695mxml_node_t * /* O - New ?xml node */
696mxmlNewXML(const char *version) /* I - Version number to use */
697{
698 char element[1024]; /* Element text */
699
700
701 snprintf(element, sizeof(element), "?xml version=\"%s\" encoding=\"utf-8\"?",
702 version ? version : "1.0");
703
704 return (mxmlNewElement(NULL, element));
705}
706
707
708/*
709 * 'mxmlRelease()' - Release a node.
710 *
711 * When the reference count reaches zero, the node (and any children)
712 * is deleted via mxmlDelete().
713 *
714 * @since Mini-XML 2.3@
715 */
716
717int /* O - New reference count */
718mxmlRelease(mxml_node_t *node) /* I - Node */
719{
720 if (node)
721 {
722 if ((-- node->ref_count) <= 0)
723 {
724 mxmlDelete(node);
725 return (0);
726 }
727 else
728 return (node->ref_count);
729 }
730 else
731 return (-1);
732}
733
734
735/*
736 * 'mxmlRetain()' - Retain a node.
737 *
738 * @since Mini-XML 2.3@
739 */
740
741int /* O - New reference count */
742mxmlRetain(mxml_node_t *node) /* I - Node */
743{
744 if (node)
745 return (++ node->ref_count);
746 else
747 return (-1);
748}
749
750
751/*
752 * 'mxml_new()' - Create a new node.
753 */
754
755static mxml_node_t * /* O - New node */
756mxml_new(mxml_node_t *parent, /* I - Parent node */
757 mxml_type_t type) /* I - Node type */
758{
759 mxml_node_t *node; /* New node */
760
761
762#if DEBUG > 1
763 fprintf(stderr, "mxml_new(parent=%p, type=%d)\n", parent, type);
764#endif /* DEBUG > 1 */
765
766 /*
767 * Allocate memory for the node...
768 */
769
770 if ((node = calloc(1, sizeof(mxml_node_t))) == NULL)
771 {
772#if DEBUG > 1
773 fputs(" returning NULL\n", stderr);
774#endif /* DEBUG > 1 */
775
776 return (NULL);
777 }
778
779#if DEBUG > 1
780 fprintf(stderr, " returning %p\n", node);
781#endif /* DEBUG > 1 */
782
783 /*
784 * Set the node type...
785 */
786
787 node->type = type;
788 node->ref_count = 1;
789
790 /*
791 * Add to the parent if present...
792 */
793
794 if (parent)
795 mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
796
797 /*
798 * Return the new node...
799 */
800
801 return (node);
802}
803
804
805/*
806 * End of "$Id: mxml-node.c 436 2011-01-22 01:02:05Z mike $".
807 */
diff --git a/pathologist/src/minixml/mxml-private.c b/pathologist/src/minixml/mxml-private.c
new file mode 100644
index 0000000..72f3e23
--- /dev/null
+++ b/pathologist/src/minixml/mxml-private.c
@@ -0,0 +1,331 @@
1/*
2 * "$Id: mxml-private.c 422 2010-11-07 22:55:11Z mike $"
3 *
4 * Private functions for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2010 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * mxml_error() - Display an error message.
19 * mxml_integer_cb() - Default callback for integer values.
20 * mxml_opaque_cb() - Default callback for opaque values.
21 * mxml_real_cb() - Default callback for real number values.
22 * _mxml_global() - Get global data.
23 */
24
25/*
26 * Include necessary headers...
27 */
28
29#include "mxml-private.h"
30
31
32/*
33 * Some crazy people think that unloading a shared object is a good or safe
34 * thing to do. Unfortunately, most objects are simply *not* safe to unload
35 * and bad things *will* happen.
36 *
37 * The following mess of conditional code allows us to provide a destructor
38 * function in Mini-XML for our thread-global storage so that it can possibly
39 * be unloaded safely, although since there is no standard way to do so I
40 * can't even provide any guarantees that you can do it safely on all platforms.
41 *
42 * This code currently supports AIX, HP-UX, Linux, Mac OS X, Solaris, and
43 * Windows. It might work on the BSDs and IRIX, but I haven't tested that.
44 */
45
46#if defined(__sun) || defined(_AIX)
47# pragma fini(_mxml_fini)
48# define _MXML_FINI _mxml_fini
49#elif defined(__hpux)
50# pragma FINI _mxml_fini
51# define _MXML_FINI _mxml_fini
52#elif defined(__GNUC__) /* Linux and Mac OS X */
53# define _MXML_FINI __attribute((destructor)) _mxml_fini
54#else
55# define _MXML_FINI _fini
56#endif /* __sun */
57
58
59/*
60 * 'mxml_error()' - Display an error message.
61 */
62
63void
64mxml_error(const char *format, /* I - Printf-style format string */
65 ...) /* I - Additional arguments as needed */
66{
67 va_list ap; /* Pointer to arguments */
68 char s[1024]; /* Message string */
69 _mxml_global_t *global = _mxml_global();
70 /* Global data */
71
72
73 /*
74 * Range check input...
75 */
76
77 if (!format)
78 return;
79
80 /*
81 * Format the error message string...
82 */
83
84 va_start(ap, format);
85
86 vsnprintf(s, sizeof(s), format, ap);
87
88 va_end(ap);
89
90 /*
91 * And then display the error message...
92 */
93
94 if (global->error_cb)
95 (*global->error_cb)(s);
96 else
97 fprintf(stderr, "mxml: %s\n", s);
98}
99
100
101/*
102 * 'mxml_ignore_cb()' - Default callback for ignored values.
103 */
104
105mxml_type_t /* O - Node type */
106mxml_ignore_cb(mxml_node_t *node) /* I - Current node */
107{
108 (void)node;
109
110 return (MXML_IGNORE);
111}
112
113
114/*
115 * 'mxml_integer_cb()' - Default callback for integer values.
116 */
117
118mxml_type_t /* O - Node type */
119mxml_integer_cb(mxml_node_t *node) /* I - Current node */
120{
121 (void)node;
122
123 return (MXML_INTEGER);
124}
125
126
127/*
128 * 'mxml_opaque_cb()' - Default callback for opaque values.
129 */
130
131mxml_type_t /* O - Node type */
132mxml_opaque_cb(mxml_node_t *node) /* I - Current node */
133{
134 (void)node;
135
136 return (MXML_OPAQUE);
137}
138
139
140/*
141 * 'mxml_real_cb()' - Default callback for real number values.
142 */
143
144mxml_type_t /* O - Node type */
145mxml_real_cb(mxml_node_t *node) /* I - Current node */
146{
147 (void)node;
148
149 return (MXML_REAL);
150}
151
152
153#ifdef HAVE_PTHREAD_H /**** POSIX threading ****/
154# include <pthread.h>
155
156static pthread_key_t _mxml_key = -1; /* Thread local storage key */
157static pthread_once_t _mxml_key_once = PTHREAD_ONCE_INIT;
158 /* One-time initialization object */
159static void _mxml_init(void);
160static void _mxml_destructor(void *g);
161
162
163/*
164 * '_mxml_destructor()' - Free memory used for globals...
165 */
166
167static void
168_mxml_destructor(void *g) /* I - Global data */
169{
170 free(g);
171}
172
173
174/*
175 * '_mxml_fini()' - Clean up when unloaded.
176 */
177
178static void
179_MXML_FINI(void)
180{
181 _mxml_global_t *global; /* Global data */
182
183
184 if (_mxml_key != -1)
185 {
186 if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) != NULL)
187 _mxml_destructor(global);
188
189 pthread_key_delete(_mxml_key);
190 _mxml_key = -1;
191 }
192}
193
194
195/*
196 * '_mxml_global()' - Get global data.
197 */
198
199_mxml_global_t * /* O - Global data */
200_mxml_global(void)
201{
202 _mxml_global_t *global; /* Global data */
203
204
205 pthread_once(&_mxml_key_once, _mxml_init);
206
207 if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) == NULL)
208 {
209 global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
210 pthread_setspecific(_mxml_key, global);
211
212 global->num_entity_cbs = 1;
213 global->entity_cbs[0] = _mxml_entity_cb;
214 global->wrap = 72;
215 }
216
217 return (global);
218}
219
220
221/*
222 * '_mxml_init()' - Initialize global data...
223 */
224
225static void
226_mxml_init(void)
227{
228 pthread_key_create(&_mxml_key, _mxml_destructor);
229}
230
231
232#elif defined(WIN32) && defined(MXML1_EXPORTS) /**** WIN32 threading ****/
233# include <windows.h>
234
235static DWORD _mxml_tls_index; /* Index for global storage */
236
237
238/*
239 * 'DllMain()' - Main entry for library.
240 */
241
242BOOL WINAPI /* O - Success/failure */
243DllMain(HINSTANCE hinst, /* I - DLL module handle */
244 DWORD reason, /* I - Reason */
245 LPVOID reserved) /* I - Unused */
246{
247 _mxml_global_t *global; /* Global data */
248
249
250 (void)hinst;
251 (void)reserved;
252
253 switch (reason)
254 {
255 case DLL_PROCESS_ATTACH : /* Called on library initialization */
256 if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES)
257 return (FALSE);
258 break;
259
260 case DLL_THREAD_DETACH : /* Called when a thread terminates */
261 if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
262 free(global);
263 break;
264
265 case DLL_PROCESS_DETACH : /* Called when library is unloaded */
266 if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
267 free(global);
268
269 TlsFree(_mxml_tls_index);
270 break;
271
272 default:
273 break;
274 }
275
276 return (TRUE);
277}
278
279
280/*
281 * '_mxml_global()' - Get global data.
282 */
283
284_mxml_global_t * /* O - Global data */
285_mxml_global(void)
286{
287 _mxml_global_t *global; /* Global data */
288
289
290 if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) == NULL)
291 {
292 global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
293
294 global->num_entity_cbs = 1;
295 global->entity_cbs[0] = _mxml_entity_cb;
296 global->wrap = 72;
297
298 TlsSetValue(_mxml_tls_index, (LPVOID)global);
299 }
300
301 return (global);
302}
303
304
305#else /**** No threading ****/
306/*
307 * '_mxml_global()' - Get global data.
308 */
309
310_mxml_global_t * /* O - Global data */
311_mxml_global(void)
312{
313 static _mxml_global_t global = /* Global data */
314 {
315 NULL, /* error_cb */
316 1, /* num_entity_cbs */
317 { _mxml_entity_cb }, /* entity_cbs */
318 72, /* wrap */
319 NULL, /* custom_load_cb */
320 NULL /* custom_save_cb */
321 };
322
323
324 return (&global);
325}
326#endif /* HAVE_PTHREAD_H */
327
328
329/*
330 * End of "$Id: mxml-private.c 422 2010-11-07 22:55:11Z mike $".
331 */
diff --git a/pathologist/src/minixml/mxml-private.h b/pathologist/src/minixml/mxml-private.h
new file mode 100644
index 0000000..8789e6c
--- /dev/null
+++ b/pathologist/src/minixml/mxml-private.h
@@ -0,0 +1,50 @@
1/*
2 * "$Id: mxml-private.h 408 2010-09-19 05:26:46Z mike $"
3 *
4 * Private definitions for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2010 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 */
16
17/*
18 * Include necessary headers...
19 */
20
21#include "config.h"
22#include "mxml.h"
23
24
25/*
26 * Global, per-thread data...
27 */
28
29typedef struct _mxml_global_s
30{
31 void (*error_cb)(const char *);
32 int num_entity_cbs;
33 int (*entity_cbs[100])(const char *name);
34 int wrap;
35 mxml_custom_load_cb_t custom_load_cb;
36 mxml_custom_save_cb_t custom_save_cb;
37} _mxml_global_t;
38
39
40/*
41 * Functions...
42 */
43
44extern _mxml_global_t *_mxml_global(void);
45extern int _mxml_entity_cb(const char *name);
46
47
48/*
49 * End of "$Id: mxml-private.h 408 2010-09-19 05:26:46Z mike $".
50 */
diff --git a/pathologist/src/minixml/mxml-search.c b/pathologist/src/minixml/mxml-search.c
new file mode 100644
index 0000000..f975af1
--- /dev/null
+++ b/pathologist/src/minixml/mxml-search.c
@@ -0,0 +1,287 @@
1/*
2 * "$Id: mxml-search.c 427 2011-01-03 02:03:29Z mike $"
3 *
4 * Search/navigation functions for Mini-XML, a small XML-like file
5 * parsing library.
6 *
7 * Copyright 2003-2010 by Michael R Sweet.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Michael R Sweet and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "COPYING"
12 * which should have been included with this file. If this file is
13 * missing or damaged, see the license at:
14 *
15 * http://www.minixml.org/
16 *
17 * Contents:
18 *
19 * mxmlFindElement() - Find the named element.
20 * mxmlFindValue() - Find a value with the given path.
21 * mxmlWalkNext() - Walk to the next logical node in the tree.
22 * mxmlWalkPrev() - Walk to the previous logical node in the tree.
23 */
24
25/*
26 * Include necessary headers...
27 */
28
29#include "config.h"
30#include "mxml.h"
31
32
33/*
34 * 'mxmlFindElement()' - Find the named element.
35 *
36 * The search is constrained by the name, attribute name, and value; any
37 * NULL names or values are treated as wildcards, so different kinds of
38 * searches can be implemented by looking for all elements of a given name
39 * or all elements with a specific attribute. The descend argument determines
40 * whether the search descends into child nodes; normally you will use
41 * MXML_DESCEND_FIRST for the initial search and MXML_NO_DESCEND to find
42 * additional direct descendents of the node. The top node argument
43 * constrains the search to a particular node's children.
44 */
45
46mxml_node_t * /* O - Element node or NULL */
47mxmlFindElement(mxml_node_t *node, /* I - Current node */
48 mxml_node_t *top, /* I - Top node */
49 const char *name, /* I - Element name or NULL for any */
50 const char *attr, /* I - Attribute name, or NULL for none */
51 const char *value, /* I - Attribute value, or NULL for any */
52 int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
53{
54 const char *temp; /* Current attribute value */
55
56
57 /*
58 * Range check input...
59 */
60
61 if (!node || !top || (!attr && value))
62 return (NULL);
63
64 /*
65 * Start with the next node...
66 */
67
68 node = mxmlWalkNext(node, top, descend);
69
70 /*
71 * Loop until we find a matching element...
72 */
73
74 while (node != NULL)
75 {
76 /*
77 * See if this node matches...
78 */
79
80 if (node->type == MXML_ELEMENT &&
81 node->value.element.name &&
82 (!name || !strcmp(node->value.element.name, name)))
83 {
84 /*
85 * See if we need to check for an attribute...
86 */
87
88 if (!attr)
89 return (node); /* No attribute search, return it... */
90
91 /*
92 * Check for the attribute...
93 */
94
95 if ((temp = mxmlElementGetAttr(node, attr)) != NULL)
96 {
97 /*
98 * OK, we have the attribute, does it match?
99 */
100
101 if (!value || !strcmp(value, temp))
102 return (node); /* Yes, return it... */
103 }
104 }
105
106 /*
107 * No match, move on to the next node...
108 */
109
110 if (descend == MXML_DESCEND)
111 node = mxmlWalkNext(node, top, MXML_DESCEND);
112 else
113 node = node->next;
114 }
115
116 return (NULL);
117}
118
119
120/*
121 * 'mxmlFindPath()' - Find a node with the given path.
122 *
123 * The "path" is a slash-separated list of element names. The name "*" is
124 * considered a wildcard for one or more levels of elements. For example,
125 * "foo/one/two", "bar/two/one", "*\/one", and so forth.
126 *
127 * The first child node of the found node is returned if the given node has
128 * children and the first child is a value node.
129 *
130 * @since Mini-XML 2.7@
131 */
132
133mxml_node_t * /* O - Found node or NULL */
134mxmlFindPath(mxml_node_t *top, /* I - Top node */
135 const char *path) /* I - Path to element */
136{
137 mxml_node_t *node; /* Current node */
138 char element[256]; /* Current element name */
139 const char *pathsep; /* Separator in path */
140 int descend; /* mxmlFindElement option */
141
142
143 /*
144 * Range check input...
145 */
146
147 if (!top || !path || !*path)
148 return (NULL);
149
150 /*
151 * Search each element in the path...
152 */
153
154 node = top;
155 while (*path)
156 {
157 /*
158 * Handle wildcards...
159 */
160
161 if (!strncmp(path, "*/", 2))
162 {
163 path += 2;
164 descend = MXML_DESCEND;
165 }
166 else
167 descend = MXML_DESCEND_FIRST;
168
169 /*
170 * Get the next element in the path...
171 */
172
173 if ((pathsep = strchr(path, '/')) == NULL)
174 pathsep = path + strlen(path);
175
176 if (pathsep == path || (pathsep - path) >= sizeof(element))
177 return (NULL);
178
179 memcpy(element, path, pathsep - path);
180 element[pathsep - path] = '\0';
181
182 if (*pathsep)
183 path = pathsep + 1;
184 else
185 path = pathsep;
186
187 /*
188 * Search for the element...
189 */
190
191 if ((node = mxmlFindElement(node, node, element, NULL, NULL,
192 descend)) == NULL)
193 return (NULL);
194 }
195
196 /*
197 * If we get this far, return the node or its first child...
198 */
199
200 if (node->child && node->child->type != MXML_ELEMENT)
201 return (node->child);
202 else
203 return (node);
204}
205
206
207/*
208 * 'mxmlWalkNext()' - Walk to the next logical node in the tree.
209 *
210 * The descend argument controls whether the first child is considered
211 * to be the next node. The top node argument constrains the walk to
212 * the node's children.
213 */
214
215mxml_node_t * /* O - Next node or NULL */
216mxmlWalkNext(mxml_node_t *node, /* I - Current node */
217 mxml_node_t *top, /* I - Top node */
218 int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
219{
220 if (!node)
221 return (NULL);
222 else if (node->child && descend)
223 return (node->child);
224 else if (node == top)
225 return (NULL);
226 else if (node->next)
227 return (node->next);
228 else if (node->parent && node->parent != top)
229 {
230 node = node->parent;
231
232 while (!node->next)
233 if (node->parent == top || !node->parent)
234 return (NULL);
235 else
236 node = node->parent;
237
238 return (node->next);
239 }
240 else
241 return (NULL);
242}
243
244
245/*
246 * 'mxmlWalkPrev()' - Walk to the previous logical node in the tree.
247 *
248 * The descend argument controls whether the previous node's last child
249 * is considered to be the previous node. The top node argument constrains
250 * the walk to the node's children.
251 */
252
253mxml_node_t * /* O - Previous node or NULL */
254mxmlWalkPrev(mxml_node_t *node, /* I - Current node */
255 mxml_node_t *top, /* I - Top node */
256 int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
257{
258 if (!node || node == top)
259 return (NULL);
260 else if (node->prev)
261 {
262 if (node->prev->last_child && descend)
263 {
264 /*
265 * Find the last child under the previous node...
266 */
267
268 node = node->prev->last_child;
269
270 while (node->last_child)
271 node = node->last_child;
272
273 return (node);
274 }
275 else
276 return (node->prev);
277 }
278 else if (node->parent != top)
279 return (node->parent);
280 else
281 return (NULL);
282}
283
284
285/*
286 * End of "$Id: mxml-search.c 427 2011-01-03 02:03:29Z mike $".
287 */
diff --git a/pathologist/src/minixml/mxml-set.c b/pathologist/src/minixml/mxml-set.c
new file mode 100644
index 0000000..b0bd527
--- /dev/null
+++ b/pathologist/src/minixml/mxml-set.c
@@ -0,0 +1,349 @@
1/*
2 * "$Id: mxml-set.c 441 2011-12-09 23:49:00Z mike $"
3 *
4 * Node set functions for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2011 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * mxmlSetCDATA() - Set the element name of a CDATA node.
19 * mxmlSetCustom() - Set the data and destructor of a custom data node.
20 * mxmlSetElement() - Set the name of an element node.
21 * mxmlSetInteger() - Set the value of an integer node.
22 * mxmlSetOpaque() - Set the value of an opaque node.
23 * mxmlSetReal() - Set the value of a real number node.
24 * mxmlSetText() - Set the value of a text node.
25 * mxmlSetTextf() - Set the value of a text node to a formatted string.
26 * mxmlSetUserData() - Set the user data pointer for a node.
27 */
28
29/*
30 * Include necessary headers...
31 */
32
33#include "config.h"
34#include "mxml.h"
35
36
37/*
38 * 'mxmlSetCDATA()' - Set the element name of a CDATA node.
39 *
40 * The node is not changed if it (or its first child) is not a CDATA element node.
41 *
42 * @since Mini-XML 2.3@
43 */
44
45int /* O - 0 on success, -1 on failure */
46mxmlSetCDATA(mxml_node_t *node, /* I - Node to set */
47 const char *data) /* I - New data string */
48{
49 /*
50 * Range check input...
51 */
52
53 if (node && node->type == MXML_ELEMENT &&
54 strncmp(node->value.element.name, "![CDATA[", 8) &&
55 node->child && node->child->type == MXML_ELEMENT &&
56 !strncmp(node->child->value.element.name, "![CDATA[", 8))
57 node = node->child;
58
59 if (!node || node->type != MXML_ELEMENT || !data ||
60 strncmp(node->value.element.name, "![CDATA[", 8))
61 return (-1);
62
63 /*
64 * Free any old element value and set the new value...
65 */
66
67 if (node->value.element.name)
68 free(node->value.element.name);
69
70 node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data);
71
72 return (0);
73}
74
75
76/*
77 * 'mxmlSetCustom()' - Set the data and destructor of a custom data node.
78 *
79 * The node is not changed if it (or its first child) is not a custom node.
80 *
81 * @since Mini-XML 2.1@
82 */
83
84int /* O - 0 on success, -1 on failure */
85mxmlSetCustom(
86 mxml_node_t *node, /* I - Node to set */
87 void *data, /* I - New data pointer */
88 mxml_custom_destroy_cb_t destroy) /* I - New destructor function */
89{
90 /*
91 * Range check input...
92 */
93
94 if (node && node->type == MXML_ELEMENT &&
95 node->child && node->child->type == MXML_CUSTOM)
96 node = node->child;
97
98 if (!node || node->type != MXML_CUSTOM)
99 return (-1);
100
101 /*
102 * Free any old element value and set the new value...
103 */
104
105 if (node->value.custom.data && node->value.custom.destroy)
106 (*(node->value.custom.destroy))(node->value.custom.data);
107
108 node->value.custom.data = data;
109 node->value.custom.destroy = destroy;
110
111 return (0);
112}
113
114
115/*
116 * 'mxmlSetElement()' - Set the name of an element node.
117 *
118 * The node is not changed if it is not an element node.
119 */
120
121int /* O - 0 on success, -1 on failure */
122mxmlSetElement(mxml_node_t *node, /* I - Node to set */
123 const char *name) /* I - New name string */
124{
125 /*
126 * Range check input...
127 */
128
129 if (!node || node->type != MXML_ELEMENT || !name)
130 return (-1);
131
132 /*
133 * Free any old element value and set the new value...
134 */
135
136 if (node->value.element.name)
137 free(node->value.element.name);
138
139 node->value.element.name = strdup(name);
140
141 return (0);
142}
143
144
145/*
146 * 'mxmlSetInteger()' - Set the value of an integer node.
147 *
148 * The node is not changed if it (or its first child) is not an integer node.
149 */
150
151int /* O - 0 on success, -1 on failure */
152mxmlSetInteger(mxml_node_t *node, /* I - Node to set */
153 int integer) /* I - Integer value */
154{
155 /*
156 * Range check input...
157 */
158
159 if (node && node->type == MXML_ELEMENT &&
160 node->child && node->child->type == MXML_INTEGER)
161 node = node->child;
162
163 if (!node || node->type != MXML_INTEGER)
164 return (-1);
165
166 /*
167 * Set the new value and return...
168 */
169
170 node->value.integer = integer;
171
172 return (0);
173}
174
175
176/*
177 * 'mxmlSetOpaque()' - Set the value of an opaque node.
178 *
179 * The node is not changed if it (or its first child) is not an opaque node.
180 */
181
182int /* O - 0 on success, -1 on failure */
183mxmlSetOpaque(mxml_node_t *node, /* I - Node to set */
184 const char *opaque) /* I - Opaque string */
185{
186 /*
187 * Range check input...
188 */
189
190 if (node && node->type == MXML_ELEMENT &&
191 node->child && node->child->type == MXML_OPAQUE)
192 node = node->child;
193
194 if (!node || node->type != MXML_OPAQUE || !opaque)
195 return (-1);
196
197 /*
198 * Free any old opaque value and set the new value...
199 */
200
201 if (node->value.opaque)
202 free(node->value.opaque);
203
204 node->value.opaque = strdup(opaque);
205
206 return (0);
207}
208
209
210/*
211 * 'mxmlSetReal()' - Set the value of a real number node.
212 *
213 * The node is not changed if it (or its first child) is not a real number node.
214 */
215
216int /* O - 0 on success, -1 on failure */
217mxmlSetReal(mxml_node_t *node, /* I - Node to set */
218 double real) /* I - Real number value */
219{
220 /*
221 * Range check input...
222 */
223
224 if (node && node->type == MXML_ELEMENT &&
225 node->child && node->child->type == MXML_REAL)
226 node = node->child;
227
228 if (!node || node->type != MXML_REAL)
229 return (-1);
230
231 /*
232 * Set the new value and return...
233 */
234
235 node->value.real = real;
236
237 return (0);
238}
239
240
241/*
242 * 'mxmlSetText()' - Set the value of a text node.
243 *
244 * The node is not changed if it (or its first child) is not a text node.
245 */
246
247int /* O - 0 on success, -1 on failure */
248mxmlSetText(mxml_node_t *node, /* I - Node to set */
249 int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
250 const char *string) /* I - String */
251{
252 /*
253 * Range check input...
254 */
255
256 if (node && node->type == MXML_ELEMENT &&
257 node->child && node->child->type == MXML_TEXT)
258 node = node->child;
259
260 if (!node || node->type != MXML_TEXT || !string)
261 return (-1);
262
263 /*
264 * Free any old string value and set the new value...
265 */
266
267 if (node->value.text.string)
268 free(node->value.text.string);
269
270 node->value.text.whitespace = whitespace;
271 node->value.text.string = strdup(string);
272
273 return (0);
274}
275
276
277/*
278 * 'mxmlSetTextf()' - Set the value of a text node to a formatted string.
279 *
280 * The node is not changed if it (or its first child) is not a text node.
281 */
282
283int /* O - 0 on success, -1 on failure */
284mxmlSetTextf(mxml_node_t *node, /* I - Node to set */
285 int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
286 const char *format, /* I - Printf-style format string */
287 ...) /* I - Additional arguments as needed */
288{
289 va_list ap; /* Pointer to arguments */
290
291
292 /*
293 * Range check input...
294 */
295
296 if (node && node->type == MXML_ELEMENT &&
297 node->child && node->child->type == MXML_TEXT)
298 node = node->child;
299
300 if (!node || node->type != MXML_TEXT || !format)
301 return (-1);
302
303 /*
304 * Free any old string value and set the new value...
305 */
306
307 if (node->value.text.string)
308 free(node->value.text.string);
309
310 va_start(ap, format);
311
312 node->value.text.whitespace = whitespace;
313 node->value.text.string = _mxml_strdupf(format, ap);
314
315 va_end(ap);
316
317 return (0);
318}
319
320
321/*
322 * 'mxmlSetUserData()' - Set the user data pointer for a node.
323 *
324 * @since Mini-XML 2.7@
325 */
326
327int /* O - 0 on success, -1 on failure */
328mxmlSetUserData(mxml_node_t *node, /* I - Node to set */
329 void *data) /* I - User data pointer */
330{
331 /*
332 * Range check input...
333 */
334
335 if (!node)
336 return (-1);
337
338 /*
339 * Set the user data pointer and return...
340 */
341
342 node->user_data = data;
343 return (0);
344}
345
346
347/*
348 * End of "$Id: mxml-set.c 441 2011-12-09 23:49:00Z mike $".
349 */
diff --git a/pathologist/src/minixml/mxml-string.c b/pathologist/src/minixml/mxml-string.c
new file mode 100644
index 0000000..6be4252
--- /dev/null
+++ b/pathologist/src/minixml/mxml-string.c
@@ -0,0 +1,476 @@
1/*
2 * "$Id: mxml-string.c 424 2010-12-25 16:21:50Z mike $"
3 *
4 * String functions for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2010 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * _mxml_snprintf() - Format a string.
19 * _mxml_strdup() - Duplicate a string.
20 * _mxml_strdupf() - Format and duplicate a string.
21 * _mxml_vsnprintf() - Format a string into a fixed size buffer.
22 * _mxml_vstrdupf() - Format and duplicate a string.
23 */
24
25/*
26 * Include necessary headers...
27 */
28
29#include "config.h"
30
31
32/*
33 * The va_copy macro is part of C99, but many compilers don't implement it.
34 * Provide a "direct assignment" implmentation when va_copy isn't defined...
35 */
36
37#ifndef va_copy
38# ifdef __va_copy
39# define va_copy(dst,src) __va_copy(dst,src)
40# else
41# define va_copy(dst,src) memcpy(&dst, &src, sizeof(va_list))
42# endif /* __va_copy */
43#endif /* va_copy */
44
45
46#ifndef HAVE_SNPRINTF
47/*
48 * '_mxml_snprintf()' - Format a string.
49 */
50
51int /* O - Number of bytes formatted */
52_mxml_snprintf(char *buffer, /* I - Output buffer */
53 size_t bufsize, /* I - Size of output buffer */
54 const char *format, /* I - Printf-style format string */
55 ...) /* I - Additional arguments as needed */
56{
57 va_list ap; /* Argument list */
58 int bytes; /* Number of bytes formatted */
59
60
61 va_start(ap, format);
62 bytes = vsnprintf(buffer, bufsize, format, ap);
63 va_end(ap);
64
65 return (bytes);
66}
67#endif /* !HAVE_SNPRINTF */
68
69
70/*
71 * '_mxml_strdup()' - Duplicate a string.
72 */
73
74#ifndef HAVE_STRDUP
75char * /* O - New string pointer */
76_mxml_strdup(const char *s) /* I - String to duplicate */
77{
78 char *t; /* New string pointer */
79
80
81 if (s == NULL)
82 return (NULL);
83
84 if ((t = malloc(strlen(s) + 1)) == NULL)
85 return (NULL);
86
87 return (strcpy(t, s));
88}
89#endif /* !HAVE_STRDUP */
90
91
92/*
93 * '_mxml_strdupf()' - Format and duplicate a string.
94 */
95
96char * /* O - New string pointer */
97_mxml_strdupf(const char *format, /* I - Printf-style format string */
98 ...) /* I - Additional arguments as needed */
99{
100 va_list ap; /* Pointer to additional arguments */
101 char *s; /* Pointer to formatted string */
102
103
104 /*
105 * Get a pointer to the additional arguments, format the string,
106 * and return it...
107 */
108
109 va_start(ap, format);
110 s = _mxml_vstrdupf(format, ap);
111 va_end(ap);
112
113 return (s);
114}
115
116
117#ifndef HAVE_VSNPRINTF
118/*
119 * '_mxml_vsnprintf()' - Format a string into a fixed size buffer.
120 */
121
122int /* O - Number of bytes formatted */
123_mxml_vsnprintf(char *buffer, /* O - Output buffer */
124 size_t bufsize, /* O - Size of output buffer */
125 const char *format, /* I - Printf-style format string */
126 va_list ap) /* I - Pointer to additional arguments */
127{
128 char *bufptr, /* Pointer to position in buffer */
129 *bufend, /* Pointer to end of buffer */
130 sign, /* Sign of format width */
131 size, /* Size character (h, l, L) */
132 type; /* Format type character */
133 int width, /* Width of field */
134 prec; /* Number of characters of precision */
135 char tformat[100], /* Temporary format string for sprintf() */
136 *tptr, /* Pointer into temporary format */
137 temp[1024]; /* Buffer for formatted numbers */
138 char *s; /* Pointer to string */
139 int slen; /* Length of string */
140 int bytes; /* Total number of bytes needed */
141
142
143 /*
144 * Loop through the format string, formatting as needed...
145 */
146
147 bufptr = buffer;
148 bufend = buffer + bufsize - 1;
149 bytes = 0;
150
151 while (*format)
152 {
153 if (*format == '%')
154 {
155 tptr = tformat;
156 *tptr++ = *format++;
157
158 if (*format == '%')
159 {
160 if (bufptr && bufptr < bufend) *bufptr++ = *format;
161 bytes ++;
162 format ++;
163 continue;
164 }
165 else if (strchr(" -+#\'", *format))
166 {
167 *tptr++ = *format;
168 sign = *format++;
169 }
170 else
171 sign = 0;
172
173 if (*format == '*')
174 {
175 /*
176 * Get width from argument...
177 */
178
179 format ++;
180 width = va_arg(ap, int);
181
182 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
183 tptr += strlen(tptr);
184 }
185 else
186 {
187 width = 0;
188
189 while (isdigit(*format & 255))
190 {
191 if (tptr < (tformat + sizeof(tformat) - 1))
192 *tptr++ = *format;
193
194 width = width * 10 + *format++ - '0';
195 }
196 }
197
198 if (*format == '.')
199 {
200 if (tptr < (tformat + sizeof(tformat) - 1))
201 *tptr++ = *format;
202
203 format ++;
204
205 if (*format == '*')
206 {
207 /*
208 * Get precision from argument...
209 */
210
211 format ++;
212 prec = va_arg(ap, int);
213
214 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
215 tptr += strlen(tptr);
216 }
217 else
218 {
219 prec = 0;
220
221 while (isdigit(*format & 255))
222 {
223 if (tptr < (tformat + sizeof(tformat) - 1))
224 *tptr++ = *format;
225
226 prec = prec * 10 + *format++ - '0';
227 }
228 }
229 }
230 else
231 prec = -1;
232
233 if (*format == 'l' && format[1] == 'l')
234 {
235 size = 'L';
236
237 if (tptr < (tformat + sizeof(tformat) - 2))
238 {
239 *tptr++ = 'l';
240 *tptr++ = 'l';
241 }
242
243 format += 2;
244 }
245 else if (*format == 'h' || *format == 'l' || *format == 'L')
246 {
247 if (tptr < (tformat + sizeof(tformat) - 1))
248 *tptr++ = *format;
249
250 size = *format++;
251 }
252
253 if (!*format)
254 break;
255
256 if (tptr < (tformat + sizeof(tformat) - 1))
257 *tptr++ = *format;
258
259 type = *format++;
260 *tptr = '\0';
261
262 switch (type)
263 {
264 case 'E' : /* Floating point formats */
265 case 'G' :
266 case 'e' :
267 case 'f' :
268 case 'g' :
269 if ((width + 2) > sizeof(temp))
270 break;
271
272 sprintf(temp, tformat, va_arg(ap, double));
273
274 bytes += strlen(temp);
275
276 if (bufptr)
277 {
278 if ((bufptr + strlen(temp)) > bufend)
279 {
280 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
281 bufptr = bufend;
282 }
283 else
284 {
285 strcpy(bufptr, temp);
286 bufptr += strlen(temp);
287 }
288 }
289 break;
290
291 case 'B' : /* Integer formats */
292 case 'X' :
293 case 'b' :
294 case 'd' :
295 case 'i' :
296 case 'o' :
297 case 'u' :
298 case 'x' :
299 if ((width + 2) > sizeof(temp))
300 break;
301
302#ifdef HAVE_LONG_LONG
303 if (size == 'L')
304 sprintf(temp, tformat, va_arg(ap, long long));
305 else
306#endif /* HAVE_LONG_LONG */
307 sprintf(temp, tformat, va_arg(ap, int));
308
309 bytes += strlen(temp);
310
311 if (bufptr)
312 {
313 if ((bufptr + strlen(temp)) > bufend)
314 {
315 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
316 bufptr = bufend;
317 }
318 else
319 {
320 strcpy(bufptr, temp);
321 bufptr += strlen(temp);
322 }
323 }
324 break;
325
326 case 'p' : /* Pointer value */
327 if ((width + 2) > sizeof(temp))
328 break;
329
330 sprintf(temp, tformat, va_arg(ap, void *));
331
332 bytes += strlen(temp);
333
334 if (bufptr)
335 {
336 if ((bufptr + strlen(temp)) > bufend)
337 {
338 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
339 bufptr = bufend;
340 }
341 else
342 {
343 strcpy(bufptr, temp);
344 bufptr += strlen(temp);
345 }
346 }
347 break;
348
349 case 'c' : /* Character or character array */
350 bytes += width;
351
352 if (bufptr)
353 {
354 if (width <= 1)
355 *bufptr++ = va_arg(ap, int);
356 else
357 {
358 if ((bufptr + width) > bufend)
359 width = bufend - bufptr;
360
361 memcpy(bufptr, va_arg(ap, char *), (size_t)width);
362 bufptr += width;
363 }
364 }
365 break;
366
367 case 's' : /* String */
368 if ((s = va_arg(ap, char *)) == NULL)
369 s = "(null)";
370
371 slen = strlen(s);
372 if (slen > width && prec != width)
373 width = slen;
374
375 bytes += width;
376
377 if (bufptr)
378 {
379 if ((bufptr + width) > bufend)
380 width = bufend - bufptr;
381
382 if (slen > width)
383 slen = width;
384
385 if (sign == '-')
386 {
387 strncpy(bufptr, s, (size_t)slen);
388 memset(bufptr + slen, ' ', (size_t)(width - slen));
389 }
390 else
391 {
392 memset(bufptr, ' ', (size_t)(width - slen));
393 strncpy(bufptr + width - slen, s, (size_t)slen);
394 }
395
396 bufptr += width;
397 }
398 break;
399
400 case 'n' : /* Output number of chars so far */
401 *(va_arg(ap, int *)) = bytes;
402 break;
403 }
404 }
405 else
406 {
407 bytes ++;
408
409 if (bufptr && bufptr < bufend)
410 *bufptr++ = *format;
411
412 format ++;
413 }
414 }
415
416 /*
417 * Nul-terminate the string and return the number of characters needed.
418 */
419
420 *bufptr = '\0';
421
422 return (bytes);
423}
424#endif /* !HAVE_VSNPRINTF */
425
426
427/*
428 * '_mxml_vstrdupf()' - Format and duplicate a string.
429 */
430
431char * /* O - New string pointer */
432_mxml_vstrdupf(const char *format, /* I - Printf-style format string */
433 va_list ap) /* I - Pointer to additional arguments */
434{
435 int bytes; /* Number of bytes required */
436 char *buffer, /* String buffer */
437 temp[256]; /* Small buffer for first vsnprintf */
438 va_list apcopy; /* Copy of argument list */
439
440
441 /*
442 * First format with a tiny buffer; this will tell us how many bytes are
443 * needed...
444 */
445
446 va_copy(apcopy, ap);
447 bytes = vsnprintf(temp, sizeof(temp), format, apcopy);
448
449 if (bytes < sizeof(temp))
450 {
451 /*
452 * Hey, the formatted string fits in the tiny buffer, so just dup that...
453 */
454
455 return (strdup(temp));
456 }
457
458 /*
459 * Allocate memory for the whole thing and reformat to the new, larger
460 * buffer...
461 */
462
463 if ((buffer = calloc(1, bytes + 1)) != NULL)
464 vsnprintf(buffer, bytes + 1, format, ap);
465
466 /*
467 * Return the new string...
468 */
469
470 return (buffer);
471}
472
473
474/*
475 * End of "$Id: mxml-string.c 424 2010-12-25 16:21:50Z mike $".
476 */
diff --git a/pathologist/src/minixml/mxmldoc.c b/pathologist/src/minixml/mxmldoc.c
new file mode 100644
index 0000000..28316ee
--- /dev/null
+++ b/pathologist/src/minixml/mxmldoc.c
@@ -0,0 +1,5809 @@
1/*#define DEBUG 1*/
2/*
3 * "$Id: mxmldoc.c 440 2011-08-11 18:51:26Z mike $"
4 *
5 * Documentation generator using Mini-XML, a small XML-like file parsing
6 * library.
7 *
8 * Copyright 2003-2011 by Michael R Sweet.
9 *
10 * These coded instructions, statements, and computer programs are the
11 * property of Michael R Sweet and are protected by Federal copyright
12 * law. Distribution and use rights are outlined in the file "COPYING"
13 * which should have been included with this file. If this file is
14 * missing or damaged, see the license at:
15 *
16 * http://www.minixml.org/
17 *
18 * Contents:
19 *
20 * main() - Main entry for test program.
21 * add_variable() - Add a variable or argument.
22 * find_public() - Find a public function, type, etc.
23 * get_comment_info() - Get info from comment.
24 * get_text() - Get the text for a node.
25 * load_cb() - Set the type of child nodes.
26 * new_documentation() - Create a new documentation tree.
27 * remove_directory() - Remove a directory.
28 * safe_strcpy() - Copy a string allowing for overlapping strings.
29 * scan_file() - Scan a source file.
30 * sort_node() - Insert a node sorted into a tree.
31 * update_comment() - Update a comment node.
32 * usage() - Show program usage...
33 * write_description() - Write the description text.
34 * write_element() - Write an element's text nodes.
35 * write_file() - Copy a file to the output.
36 * write_function() - Write documentation for a function.
37 * write_html() - Write HTML documentation.
38 * write_html_head() - Write the standard HTML header.
39 * write_man() - Write manpage documentation.
40 * write_scu() - Write a structure, class, or union.
41 * write_string() - Write a string, quoting HTML special chars as needed.
42 * write_toc() - Write a table-of-contents.
43 * write_tokens() - Write <Token> nodes for all APIs.
44 * ws_cb() - Whitespace callback for saving.
45 */
46
47/*
48 * Include necessary headers...
49 */
50
51#include "config.h"
52#include "mxml.h"
53#include <time.h>
54#include <sys/stat.h>
55#ifndef WIN32
56# include <dirent.h>
57# include <unistd.h>
58#endif /* !WIN32 */
59#ifdef __APPLE__
60# include <spawn.h>
61# include <sys/wait.h>
62extern char **environ;
63#endif /* __APPLE__ */
64
65
66/*
67 * This program scans source and header files and produces public API
68 * documentation for code that conforms to the CUPS Configuration
69 * Management Plan (CMP) coding standards. Please see the following web
70 * page for details:
71 *
72 * http://www.cups.org/cmp.html
73 *
74 * Using Mini-XML, this program creates and maintains an XML representation
75 * of the public API code documentation which can then be converted to HTML
76 * as desired. The following is a poor-man's schema:
77 *
78 * <?xml version="1.0"?>
79 * <mxmldoc xmlns="http://www.easysw.com"
80 * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
81 * xsi:schemaLocation="http://www.minixml.org/mxmldoc.xsd">
82 *
83 * <namespace name=""> [optional...]
84 * <constant name="">
85 * <description>descriptive text</description>
86 * </constant>
87 *
88 * <enumeration name="">
89 * <description>descriptive text</description>
90 * <constant name="">...</constant>
91 * </enumeration>
92 *
93 * <typedef name="">
94 * <description>descriptive text</description>
95 * <type>type string</type>
96 * </typedef>
97 *
98 * <function name="" scope="">
99 * <description>descriptive text</description>
100 * <argument name="" direction="I|O|IO" default="">
101 * <description>descriptive text</description>
102 * <type>type string</type>
103 * </argument>
104 * <returnvalue>
105 * <description>descriptive text</description>
106 * <type>type string</type>
107 * </returnvalue>
108 * <seealso>function names separated by spaces</seealso>
109 * </function>
110 *
111 * <variable name="" scope="">
112 * <description>descriptive text</description>
113 * <type>type string</type>
114 * </variable>
115 *
116 * <struct name="">
117 * <description>descriptive text</description>
118 * <variable name="">...</variable>
119 * <function name="">...</function>
120 * </struct>
121 *
122 * <union name="">
123 * <description>descriptive text</description>
124 * <variable name="">...</variable>
125 * </union>
126 *
127 * <class name="" parent="">
128 * <description>descriptive text</description>
129 * <class name="">...</class>
130 * <enumeration name="">...</enumeration>
131 * <function name="">...</function>
132 * <struct name="">...</struct>
133 * <variable name="">...</variable>
134 * </class>
135 * </namespace>
136 * </mxmldoc>
137 */
138
139
140/*
141 * Basic states for file parser...
142 */
143
144#define STATE_NONE 0 /* No state - whitespace, etc. */
145#define STATE_PREPROCESSOR 1 /* Preprocessor directive */
146#define STATE_C_COMMENT 2 /* Inside a C comment */
147#define STATE_CXX_COMMENT 3 /* Inside a C++ comment */
148#define STATE_STRING 4 /* Inside a string constant */
149#define STATE_CHARACTER 5 /* Inside a character constant */
150#define STATE_IDENTIFIER 6 /* Inside a keyword/identifier */
151
152
153/*
154 * Output modes...
155 */
156
157#define OUTPUT_NONE 0 /* No output */
158#define OUTPUT_HTML 1 /* Output HTML */
159#define OUTPUT_XML 2 /* Output XML */
160#define OUTPUT_MAN 3 /* Output nroff/man */
161#define OUTPUT_TOKENS 4 /* Output docset Tokens.xml file */
162
163
164/*
165 * Local functions...
166 */
167
168static mxml_node_t *add_variable(mxml_node_t *parent, const char *name,
169 mxml_node_t *type);
170static mxml_node_t *find_public(mxml_node_t *node, mxml_node_t *top,
171 const char *name);
172static char *get_comment_info(mxml_node_t *description);
173static char *get_text(mxml_node_t *node, char *buffer, int buflen);
174static mxml_type_t load_cb(mxml_node_t *node);
175static mxml_node_t *new_documentation(mxml_node_t **mxmldoc);
176static int remove_directory(const char *path);
177static void safe_strcpy(char *dst, const char *src);
178static int scan_file(const char *filename, FILE *fp,
179 mxml_node_t *doc);
180static void sort_node(mxml_node_t *tree, mxml_node_t *func);
181static void update_comment(mxml_node_t *parent,
182 mxml_node_t *comment);
183static void usage(const char *option);
184static void write_description(FILE *out, mxml_node_t *description,
185 const char *element, int summary);
186static void write_element(FILE *out, mxml_node_t *doc,
187 mxml_node_t *element, int mode);
188static void write_file(FILE *out, const char *file);
189static void write_function(FILE *out, mxml_node_t *doc,
190 mxml_node_t *function, int level);
191static void write_html(const char *section, const char *title,
192 const char *footerfile,
193 const char *headerfile,
194 const char *introfile, const char *cssfile,
195 const char *framefile,
196 const char *docset, const char *docversion,
197 const char *feedname, const char *feedurl,
198 mxml_node_t *doc);
199static void write_html_head(FILE *out, const char *section,
200 const char *title, const char *cssfile);
201static void write_man(const char *man_name, const char *section,
202 const char *title, const char *headerfile,
203 const char *footerfile, const char *introfile,
204 mxml_node_t *doc);
205static void write_scu(FILE *out, mxml_node_t *doc,
206 mxml_node_t *scut);
207static void write_string(FILE *out, const char *s, int mode);
208static void write_toc(FILE *out, mxml_node_t *doc,
209 const char *introfile, const char *target,
210 int xml);
211static void write_tokens(FILE *out, mxml_node_t *doc,
212 const char *path);
213static const char *ws_cb(mxml_node_t *node, int where);
214
215
216/*
217 * 'main()' - Main entry for test program.
218 */
219
220int /* O - Exit status */
221main(int argc, /* I - Number of command-line args */
222 char *argv[]) /* I - Command-line args */
223{
224 int i; /* Looping var */
225 int len; /* Length of argument */
226 FILE *fp; /* File to read */
227 mxml_node_t *doc; /* XML documentation tree */
228 mxml_node_t *mxmldoc; /* mxmldoc node */
229 const char *cssfile, /* CSS stylesheet file */
230 *docset, /* Documentation set directory */
231 *docversion, /* Documentation set version */
232 *feedname, /* Feed name for documentation set */
233 *feedurl, /* Feed URL for documentation set */
234 *footerfile, /* Footer file */
235 *framefile, /* Framed HTML basename */
236 *headerfile, /* Header file */
237 *introfile, /* Introduction file */
238 *name, /* Name of manpage */
239 *path, /* Path to help file for tokens */
240 *section, /* Section/keywords of documentation */
241 *title, /* Title of documentation */
242 *xmlfile; /* XML file */
243 int mode, /* Output mode */
244 update; /* Updated XML file */
245
246
247 /*
248 * Check arguments...
249 */
250
251 cssfile = NULL;
252 doc = NULL;
253 docset = NULL;
254 docversion = NULL;
255 feedname = NULL;
256 feedurl = NULL;
257 footerfile = NULL;
258 framefile = NULL;
259 headerfile = NULL;
260 introfile = NULL;
261 mode = OUTPUT_HTML;
262 mxmldoc = NULL;
263 name = NULL;
264 path = NULL;
265 section = NULL;
266 title = NULL;
267 update = 0;
268 xmlfile = NULL;
269
270 for (i = 1; i < argc; i ++)
271 if (!strcmp(argv[i], "--help"))
272 {
273 /*
274 * Show help...
275 */
276
277 usage(NULL);
278 }
279 else if (!strcmp(argv[i], "--version"))
280 {
281 /*
282 * Show version...
283 */
284
285 puts(MXML_VERSION + 10);
286 return (0);
287 }
288 else if (!strcmp(argv[i], "--css") && !cssfile)
289 {
290 /*
291 * Set CSS stylesheet file...
292 */
293
294 i ++;
295 if (i < argc)
296 cssfile = argv[i];
297 else
298 usage(NULL);
299 }
300 else if (!strcmp(argv[i], "--docset") && !docset)
301 {
302 /*
303 * Set documentation set directory...
304 */
305
306 i ++;
307 if (i < argc)
308 docset = argv[i];
309 else
310 usage(NULL);
311 }
312 else if (!strcmp(argv[i], "--docversion") && !docversion)
313 {
314 /*
315 * Set documentation set directory...
316 */
317
318 i ++;
319 if (i < argc)
320 docversion = argv[i];
321 else
322 usage(NULL);
323 }
324 else if (!strcmp(argv[i], "--footer") && !footerfile)
325 {
326 /*
327 * Set footer file...
328 */
329
330 i ++;
331 if (i < argc)
332 footerfile = argv[i];
333 else
334 usage(NULL);
335 }
336 else if (!strcmp(argv[i], "--feedname") && !feedname)
337 {
338 /*
339 * Set documentation set feed name...
340 */
341
342 i ++;
343 if (i < argc)
344 feedname = argv[i];
345 else
346 usage(NULL);
347 }
348 else if (!strcmp(argv[i], "--feedurl") && !feedurl)
349 {
350 /*
351 * Set documentation set feed name...
352 */
353
354 i ++;
355 if (i < argc)
356 feedurl = argv[i];
357 else
358 usage(NULL);
359 }
360 else if (!strcmp(argv[i], "--framed") && !framefile)
361 {
362 /*
363 * Set base filename for framed HTML output...
364 */
365
366 i ++;
367 if (i < argc)
368 framefile = argv[i];
369 else
370 usage(NULL);
371 }
372 else if (!strcmp(argv[i], "--header") && !headerfile)
373 {
374 /*
375 * Set header file...
376 */
377
378 i ++;
379 if (i < argc)
380 headerfile = argv[i];
381 else
382 usage(NULL);
383 }
384 else if (!strcmp(argv[i], "--intro") && !introfile)
385 {
386 /*
387 * Set intro file...
388 */
389
390 i ++;
391 if (i < argc)
392 introfile = argv[i];
393 else
394 usage(NULL);
395 }
396 else if (!strcmp(argv[i], "--man") && !name)
397 {
398 /*
399 * Output manpage...
400 */
401
402 i ++;
403 if (i < argc)
404 {
405 mode = OUTPUT_MAN;
406 name = argv[i];
407 }
408 else
409 usage(NULL);
410 }
411 else if (!strcmp(argv[i], "--no-output"))
412 mode = OUTPUT_NONE;
413 else if (!strcmp(argv[i], "--section") && !section)
414 {
415 /*
416 * Set section/keywords...
417 */
418
419 i ++;
420 if (i < argc)
421 section = argv[i];
422 else
423 usage(NULL);
424 }
425 else if (!strcmp(argv[i], "--title") && !title)
426 {
427 /*
428 * Set title...
429 */
430
431 i ++;
432 if (i < argc)
433 title = argv[i];
434 else
435 usage(NULL);
436 }
437 else if (!strcmp(argv[i], "--tokens"))
438 {
439 /*
440 * Output Tokens.xml file...
441 */
442
443 mode = OUTPUT_TOKENS;
444
445 i ++;
446 if (i < argc)
447 path = argv[i];
448 else
449 usage(NULL);
450 }
451 else if (argv[i][0] == '-')
452 {
453 /*
454 * Unknown/bad option...
455 */
456
457 usage(argv[i]);
458 }
459 else
460 {
461 /*
462 * Process XML or source file...
463 */
464
465 len = (int)strlen(argv[i]);
466 if (len > 4 && !strcmp(argv[i] + len - 4, ".xml"))
467 {
468 /*
469 * Set XML file...
470 */
471
472 if (xmlfile)
473 usage(NULL);
474
475 xmlfile = argv[i];
476
477 if (!doc)
478 {
479 if ((fp = fopen(argv[i], "r")) != NULL)
480 {
481 /*
482 * Read the existing XML file...
483 */
484
485 doc = mxmlLoadFile(NULL, fp, load_cb);
486
487 fclose(fp);
488
489 if (!doc)
490 {
491 mxmldoc = NULL;
492
493 fprintf(stderr,
494 "mxmldoc: Unable to read the XML documentation file "
495 "\"%s\"!\n", argv[i]);
496 }
497 else if ((mxmldoc = mxmlFindElement(doc, doc, "mxmldoc", NULL,
498 NULL, MXML_DESCEND)) == NULL)
499 {
500 fprintf(stderr,
501 "mxmldoc: XML documentation file \"%s\" is missing "
502 "<mxmldoc> node!!\n", argv[i]);
503
504 mxmlDelete(doc);
505 doc = NULL;
506 }
507 }
508 else
509 {
510 doc = NULL;
511 mxmldoc = NULL;
512 }
513
514 if (!doc)
515 doc = new_documentation(&mxmldoc);
516 }
517 }
518 else
519 {
520 /*
521 * Load source file...
522 */
523
524 update = 1;
525
526 if (!doc)
527 doc = new_documentation(&mxmldoc);
528
529 if ((fp = fopen(argv[i], "r")) == NULL)
530 {
531 fprintf(stderr, "mxmldoc: Unable to open source file \"%s\": %s\n",
532 argv[i], strerror(errno));
533 mxmlDelete(doc);
534 return (1);
535 }
536 else if (scan_file(argv[i], fp, mxmldoc))
537 {
538 fclose(fp);
539 mxmlDelete(doc);
540 return (1);
541 }
542 else
543 fclose(fp);
544 }
545 }
546
547 if (update && xmlfile)
548 {
549 /*
550 * Save the updated XML documentation file...
551 */
552
553 if ((fp = fopen(xmlfile, "w")) != NULL)
554 {
555 /*
556 * Write over the existing XML file...
557 */
558
559 mxmlSetWrapMargin(0);
560
561 if (mxmlSaveFile(doc, fp, ws_cb))
562 {
563 fprintf(stderr,
564 "mxmldoc: Unable to write the XML documentation file \"%s\": "
565 "%s!\n", xmlfile, strerror(errno));
566 fclose(fp);
567 mxmlDelete(doc);
568 return (1);
569 }
570
571 fclose(fp);
572 }
573 else
574 {
575 fprintf(stderr,
576 "mxmldoc: Unable to create the XML documentation file \"%s\": "
577 "%s!\n", xmlfile, strerror(errno));
578 mxmlDelete(doc);
579 return (1);
580 }
581 }
582
583 switch (mode)
584 {
585 case OUTPUT_HTML :
586 /*
587 * Write HTML documentation...
588 */
589
590 write_html(section, title ? title : "Documentation", footerfile,
591 headerfile, introfile, cssfile, framefile, docset,
592 docversion, feedname, feedurl, mxmldoc);
593 break;
594
595 case OUTPUT_MAN :
596 /*
597 * Write manpage documentation...
598 */
599
600 write_man(name, section, title, footerfile, headerfile, introfile,
601 mxmldoc);
602 break;
603
604 case OUTPUT_TOKENS :
605 fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
606 "<Tokens version=\"1.0\">\n", stdout);
607
608 write_tokens(stdout, mxmldoc, path);
609
610 fputs("</Tokens>\n", stdout);
611 break;
612 }
613
614 /*
615 * Delete the tree and return...
616 */
617
618 mxmlDelete(doc);
619
620 return (0);
621}
622
623
624/*
625 * 'add_variable()' - Add a variable or argument.
626 */
627
628static mxml_node_t * /* O - New variable/argument */
629add_variable(mxml_node_t *parent, /* I - Parent node */
630 const char *name, /* I - "argument" or "variable" */
631 mxml_node_t *type) /* I - Type nodes */
632{
633 mxml_node_t *variable, /* New variable */
634 *node, /* Current node */
635 *next; /* Next node */
636 char buffer[16384], /* String buffer */
637 *bufptr; /* Pointer into buffer */
638
639
640#ifdef DEBUG
641 fprintf(stderr, "add_variable(parent=%p, name=\"%s\", type=%p)\n",
642 parent, name, type);
643#endif /* DEBUG */
644
645 /*
646 * Range check input...
647 */
648
649 if (!type || !type->child)
650 return (NULL);
651
652 /*
653 * Create the variable/argument node...
654 */
655
656 variable = mxmlNewElement(parent, name);
657
658 /*
659 * Check for a default value...
660 */
661
662 for (node = type->child; node; node = node->next)
663 if (!strcmp(node->value.text.string, "="))
664 break;
665
666 if (node)
667 {
668 /*
669 * Default value found, copy it and add as a "default" attribute...
670 */
671
672 for (bufptr = buffer; node; bufptr += strlen(bufptr))
673 {
674 if (node->value.text.whitespace && bufptr > buffer)
675 *bufptr++ = ' ';
676
677 strcpy(bufptr, node->value.text.string);
678
679 next = node->next;
680 mxmlDelete(node);
681 node = next;
682 }
683
684 mxmlElementSetAttr(variable, "default", buffer);
685 }
686
687 /*
688 * Extract the argument/variable name...
689 */
690
691 if (type->last_child->value.text.string[0] == ')')
692 {
693 /*
694 * Handle "type (*name)(args)"...
695 */
696
697 for (node = type->child; node; node = node->next)
698 if (node->value.text.string[0] == '(')
699 break;
700
701 for (bufptr = buffer; node; bufptr += strlen(bufptr))
702 {
703 if (node->value.text.whitespace && bufptr > buffer)
704 *bufptr++ = ' ';
705
706 strcpy(bufptr, node->value.text.string);
707
708 next = node->next;
709 mxmlDelete(node);
710 node = next;
711 }
712 }
713 else
714 {
715 /*
716 * Handle "type name"...
717 */
718
719 strcpy(buffer, type->last_child->value.text.string);
720 mxmlDelete(type->last_child);
721 }
722
723 /*
724 * Set the name...
725 */
726
727 mxmlElementSetAttr(variable, "name", buffer);
728
729 /*
730 * Add the remaining type information to the variable node...
731 */
732
733 mxmlAdd(variable, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type);
734
735 /*
736 * Add new new variable node...
737 */
738
739 return (variable);
740}
741
742
743/*
744 * 'find_public()' - Find a public function, type, etc.
745 */
746
747static mxml_node_t * /* I - Found node or NULL */
748find_public(mxml_node_t *node, /* I - Current node */
749 mxml_node_t *top, /* I - Top node */
750 const char *name) /* I - Name of element */
751{
752 mxml_node_t *description, /* Description node */
753 *comment; /* Comment node */
754
755
756 for (node = mxmlFindElement(node, top, name, NULL, NULL,
757 node == top ? MXML_DESCEND_FIRST :
758 MXML_NO_DESCEND);
759 node;
760 node = mxmlFindElement(node, top, name, NULL, NULL, MXML_NO_DESCEND))
761 {
762 /*
763 * Get the description for this node...
764 */
765
766 description = mxmlFindElement(node, node, "description", NULL, NULL,
767 MXML_DESCEND_FIRST);
768
769 /*
770 * A missing or empty description signals a private node...
771 */
772
773 if (!description)
774 continue;
775
776 /*
777 * Look for @private@ in the comment text...
778 */
779
780 for (comment = description->child; comment; comment = comment->next)
781 if ((comment->type == MXML_TEXT &&
782 strstr(comment->value.text.string, "@private@")) ||
783 (comment->type == MXML_OPAQUE &&
784 strstr(comment->value.opaque, "@private@")))
785 break;
786
787 if (!comment)
788 {
789 /*
790 * No @private@, so return this node...
791 */
792
793 return (node);
794 }
795 }
796
797 /*
798 * If we get here, there are no (more) public nodes...
799 */
800
801 return (NULL);
802}
803
804
805/*
806 * 'get_comment_info()' - Get info from comment.
807 */
808
809static char * /* O - Info from comment */
810get_comment_info(
811 mxml_node_t *description) /* I - Description node */
812{
813 char text[10240], /* Description text */
814 since[255], /* @since value */
815 *ptr; /* Pointer into text */
816 static char info[1024]; /* Info string */
817
818
819 if (!description)
820 return ("");
821
822 get_text(description, text, sizeof(text));
823
824 for (ptr = strchr(text, '@'); ptr; ptr = strchr(ptr + 1, '@'))
825 {
826 if (!strncmp(ptr, "@deprecated@", 12))
827 return ("<span class=\"info\">&nbsp;DEPRECATED&nbsp;</span>");
828 else if (!strncmp(ptr, "@since ", 7))
829 {
830 strncpy(since, ptr + 7, sizeof(since) - 1);
831 since[sizeof(since) - 1] = '\0';
832
833 if ((ptr = strchr(since, '@')) != NULL)
834 *ptr = '\0';
835
836 snprintf(info, sizeof(info), "<span class=\"info\">&nbsp;%s&nbsp;</span>", since);
837 return (info);
838 }
839 }
840
841 return ("");
842}
843
844
845/*
846 * 'get_text()' - Get the text for a node.
847 */
848
849static char * /* O - Text in node */
850get_text(mxml_node_t *node, /* I - Node to get */
851 char *buffer, /* I - Buffer */
852 int buflen) /* I - Size of buffer */
853{
854 char *ptr, /* Pointer into buffer */
855 *end; /* End of buffer */
856 int len; /* Length of node */
857 mxml_node_t *current; /* Current node */
858
859
860 ptr = buffer;
861 end = buffer + buflen - 1;
862
863 for (current = node->child; current && ptr < end; current = current->next)
864 {
865 if (current->type == MXML_TEXT)
866 {
867 if (current->value.text.whitespace)
868 *ptr++ = ' ';
869
870 len = (int)strlen(current->value.text.string);
871 if (len > (int)(end - ptr))
872 len = (int)(end - ptr);
873
874 memcpy(ptr, current->value.text.string, len);
875 ptr += len;
876 }
877 else if (current->type == MXML_OPAQUE)
878 {
879 len = (int)strlen(current->value.opaque);
880 if (len > (int)(end - ptr))
881 len = (int)(end - ptr);
882
883 memcpy(ptr, current->value.opaque, len);
884 ptr += len;
885 }
886 }
887
888 *ptr = '\0';
889
890 return (buffer);
891}
892
893
894/*
895 * 'load_cb()' - Set the type of child nodes.
896 */
897
898static mxml_type_t /* O - Node type */
899load_cb(mxml_node_t *node) /* I - Node */
900{
901 if (!strcmp(node->value.element.name, "description"))
902 return (MXML_OPAQUE);
903 else
904 return (MXML_TEXT);
905}
906
907
908/*
909 * 'new_documentation()' - Create a new documentation tree.
910 */
911
912static mxml_node_t * /* O - New documentation */
913new_documentation(mxml_node_t **mxmldoc)/* O - mxmldoc node */
914{
915 mxml_node_t *doc; /* New documentation */
916
917
918 /*
919 * Create an empty XML documentation file...
920 */
921
922 doc = mxmlNewXML(NULL);
923
924 *mxmldoc = mxmlNewElement(doc, "mxmldoc");
925
926 mxmlElementSetAttr(*mxmldoc, "xmlns", "http://www.easysw.com");
927 mxmlElementSetAttr(*mxmldoc, "xmlns:xsi",
928 "http://www.w3.org/2001/XMLSchema-instance");
929 mxmlElementSetAttr(*mxmldoc, "xsi:schemaLocation",
930 "http://www.minixml.org/mxmldoc.xsd");
931
932 return (doc);
933}
934
935
936/*
937 * 'remove_directory()' - Remove a directory.
938 */
939
940static int /* O - 1 on success, 0 on failure */
941remove_directory(const char *path) /* I - Directory to remove */
942{
943#ifdef WIN32
944 /* TODO: Add Windows directory removal code */
945
946#else
947 DIR *dir; /* Directory */
948 struct dirent *dent; /* Current directory entry */
949 char filename[1024]; /* Current filename */
950 struct stat fileinfo; /* File information */
951
952
953 if ((dir = opendir(path)) == NULL)
954 {
955 fprintf(stderr, "mxmldoc: Unable to open directory \"%s\": %s\n", path,
956 strerror(errno));
957 return (0);
958 }
959
960 while ((dent = readdir(dir)) != NULL)
961 {
962 /*
963 * Skip "." and ".."...
964 */
965
966 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
967 continue;
968
969 /*
970 * See if we have a file or directory...
971 */
972
973 snprintf(filename, sizeof(filename), "%s/%s", path, dent->d_name);
974
975 if (stat(filename, &fileinfo))
976 {
977 fprintf(stderr, "mxmldoc: Unable to stat \"%s\": %s\n", filename,
978 strerror(errno));
979 closedir(dir);
980 return (0);
981 }
982
983 if (S_ISDIR(fileinfo.st_mode))
984 {
985 if (!remove_directory(filename))
986 {
987 closedir(dir);
988 return (0);
989 }
990 }
991 else if (unlink(filename))
992 {
993 fprintf(stderr, "mxmldoc: Unable to remove \"%s\": %s\n", filename,
994 strerror(errno));
995 closedir(dir);
996 return (0);
997 }
998 }
999
1000 closedir(dir);
1001
1002 if (rmdir(path))
1003 {
1004 fprintf(stderr, "mxmldoc: Unable to remove directory \"%s\": %s\n", path,
1005 strerror(errno));
1006 return (0);
1007 }
1008#endif /* WIN32 */
1009
1010 return (1);
1011}
1012
1013
1014/*
1015 * 'safe_strcpy()' - Copy a string allowing for overlapping strings.
1016 */
1017
1018static void
1019safe_strcpy(char *dst, /* I - Destination string */
1020 const char *src) /* I - Source string */
1021{
1022 while (*src)
1023 *dst++ = *src++;
1024
1025 *dst = '\0';
1026}
1027
1028
1029/*
1030 * 'scan_file()' - Scan a source file.
1031 */
1032
1033static int /* O - 0 on success, -1 on error */
1034scan_file(const char *filename, /* I - Filename */
1035 FILE *fp, /* I - File to scan */
1036 mxml_node_t *tree) /* I - Function tree */
1037{
1038 int state, /* Current parser state */
1039 braces, /* Number of braces active */
1040 parens; /* Number of active parenthesis */
1041 int ch; /* Current character */
1042 char buffer[65536], /* String buffer */
1043 *bufptr; /* Pointer into buffer */
1044 const char *scope; /* Current variable/function scope */
1045 mxml_node_t *comment, /* <comment> node */
1046 *constant, /* <constant> node */
1047 *enumeration, /* <enumeration> node */
1048 *function, /* <function> node */
1049 *fstructclass, /* function struct/class node */
1050 *structclass, /* <struct> or <class> node */
1051 *typedefnode, /* <typedef> node */
1052 *variable, /* <variable> or <argument> node */
1053 *returnvalue, /* <returnvalue> node */
1054 *type, /* <type> node */
1055 *description, /* <description> node */
1056 *node, /* Current node */
1057 *next; /* Next node */
1058#if DEBUG > 1
1059 mxml_node_t *temp; /* Temporary node */
1060 int oldstate, /* Previous state */
1061 oldch; /* Old character */
1062 static const char *states[] = /* State strings */
1063 {
1064 "STATE_NONE",
1065 "STATE_PREPROCESSOR",
1066 "STATE_C_COMMENT",
1067 "STATE_CXX_COMMENT",
1068 "STATE_STRING",
1069 "STATE_CHARACTER",
1070 "STATE_IDENTIFIER"
1071 };
1072#endif /* DEBUG > 1 */
1073
1074
1075#ifdef DEBUG
1076 fprintf(stderr, "scan_file(filename=\"%s\", fp=%p, tree=%p)\n", filename,
1077 fp, tree);
1078#endif /* DEBUG */
1079
1080 /*
1081 * Initialize the finite state machine...
1082 */
1083
1084 state = STATE_NONE;
1085 braces = 0;
1086 parens = 0;
1087 bufptr = buffer;
1088
1089 comment = mxmlNewElement(MXML_NO_PARENT, "temp");
1090 constant = NULL;
1091 enumeration = NULL;
1092 function = NULL;
1093 variable = NULL;
1094 returnvalue = NULL;
1095 type = NULL;
1096 description = NULL;
1097 typedefnode = NULL;
1098 structclass = NULL;
1099 fstructclass = NULL;
1100
1101 if (!strcmp(tree->value.element.name, "class"))
1102 scope = "private";
1103 else
1104 scope = NULL;
1105
1106 /*
1107 * Read until end-of-file...
1108 */
1109
1110 while ((ch = getc(fp)) != EOF)
1111 {
1112#if DEBUG > 1
1113 oldstate = state;
1114 oldch = ch;
1115#endif /* DEBUG > 1 */
1116
1117 switch (state)
1118 {
1119 case STATE_NONE : /* No state - whitespace, etc. */
1120 switch (ch)
1121 {
1122 case '/' : /* Possible C/C++ comment */
1123 ch = getc(fp);
1124 bufptr = buffer;
1125
1126 if (ch == '*')
1127 state = STATE_C_COMMENT;
1128 else if (ch == '/')
1129 state = STATE_CXX_COMMENT;
1130 else
1131 {
1132 ungetc(ch, fp);
1133
1134 if (type)
1135 {
1136#ifdef DEBUG
1137 fputs("Identifier: <<<< / >>>\n", stderr);
1138#endif /* DEBUG */
1139 ch = type->last_child->value.text.string[0];
1140 mxmlNewText(type, isalnum(ch) || ch == '_', "/");
1141 }
1142 }
1143 break;
1144
1145 case '#' : /* Preprocessor */
1146#ifdef DEBUG
1147 fputs(" #preprocessor...\n", stderr);
1148#endif /* DEBUG */
1149 state = STATE_PREPROCESSOR;
1150 break;
1151
1152 case '\'' : /* Character constant */
1153 state = STATE_CHARACTER;
1154 bufptr = buffer;
1155 *bufptr++ = ch;
1156 break;
1157
1158 case '\"' : /* String constant */
1159 state = STATE_STRING;
1160 bufptr = buffer;
1161 *bufptr++ = ch;
1162 break;
1163
1164 case '{' :
1165#ifdef DEBUG
1166 fprintf(stderr, " open brace, function=%p, type=%p...\n",
1167 function, type);
1168 if (type)
1169 fprintf(stderr, " type->child=\"%s\"...\n",
1170 type->child->value.text.string);
1171#endif /* DEBUG */
1172
1173 if (function)
1174 {
1175 if (fstructclass)
1176 {
1177 sort_node(fstructclass, function);
1178 fstructclass = NULL;
1179 }
1180 else
1181 sort_node(tree, function);
1182
1183 function = NULL;
1184 }
1185 else if (type && type->child &&
1186 ((!strcmp(type->child->value.text.string, "typedef") &&
1187 type->child->next &&
1188 (!strcmp(type->child->next->value.text.string, "struct") ||
1189 !strcmp(type->child->next->value.text.string, "union") ||
1190 !strcmp(type->child->next->value.text.string, "class"))) ||
1191 !strcmp(type->child->value.text.string, "union") ||
1192 !strcmp(type->child->value.text.string, "struct") ||
1193 !strcmp(type->child->value.text.string, "class")))
1194 {
1195 /*
1196 * Start of a class or structure...
1197 */
1198
1199 if (!strcmp(type->child->value.text.string, "typedef"))
1200 {
1201#ifdef DEBUG
1202 fputs(" starting typedef...\n", stderr);
1203#endif /* DEBUG */
1204
1205 typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef");
1206 mxmlDelete(type->child);
1207 }
1208 else
1209 typedefnode = NULL;
1210
1211 structclass = mxmlNewElement(MXML_NO_PARENT,
1212 type->child->value.text.string);
1213
1214#ifdef DEBUG
1215 fprintf(stderr, "%c%s: <<<< %s >>>\n",
1216 toupper(type->child->value.text.string[0]),
1217 type->child->value.text.string + 1,
1218 type->child->next ?
1219 type->child->next->value.text.string : "(noname)");
1220
1221 fputs(" type =", stderr);
1222 for (node = type->child; node; node = node->next)
1223 fprintf(stderr, " \"%s\"", node->value.text.string);
1224 putc('\n', stderr);
1225
1226 fprintf(stderr, " scope = %s\n", scope ? scope : "(null)");
1227#endif /* DEBUG */
1228
1229 if (type->child->next)
1230 {
1231 mxmlElementSetAttr(structclass, "name",
1232 type->child->next->value.text.string);
1233 sort_node(tree, structclass);
1234 }
1235
1236 if (typedefnode && type->child)
1237 type->child->value.text.whitespace = 0;
1238 else if (structclass && type->child &&
1239 type->child->next && type->child->next->next)
1240 {
1241 for (bufptr = buffer, node = type->child->next->next;
1242 node;
1243 bufptr += strlen(bufptr))
1244 {
1245 if (node->value.text.whitespace && bufptr > buffer)
1246 *bufptr++ = ' ';
1247
1248 strcpy(bufptr, node->value.text.string);
1249
1250 next = node->next;
1251 mxmlDelete(node);
1252 node = next;
1253 }
1254
1255 mxmlElementSetAttr(structclass, "parent", buffer);
1256
1257 mxmlDelete(type);
1258 type = NULL;
1259 }
1260 else
1261 {
1262 mxmlDelete(type);
1263 type = NULL;
1264 }
1265
1266 if (typedefnode && comment->last_child)
1267 {
1268 /*
1269 * Copy comment for typedef as well as class/struct/union...
1270 */
1271
1272 mxmlNewText(comment, 0,
1273 comment->last_child->value.text.string);
1274 description = mxmlNewElement(typedefnode, "description");
1275#ifdef DEBUG
1276 fprintf(stderr,
1277 " duplicating comment %p/%p for typedef...\n",
1278 comment->last_child, comment->child);
1279#endif /* DEBUG */
1280 update_comment(typedefnode, comment->last_child);
1281 mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
1282 comment->last_child);
1283 }
1284
1285 description = mxmlNewElement(structclass, "description");
1286#ifdef DEBUG
1287 fprintf(stderr, " adding comment %p/%p to %s...\n",
1288 comment->last_child, comment->child,
1289 structclass->value.element.name);
1290#endif /* DEBUG */
1291 update_comment(structclass, comment->last_child);
1292 mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
1293 comment->last_child);
1294
1295 if (scan_file(filename, fp, structclass))
1296 {
1297 mxmlDelete(comment);
1298 return (-1);
1299 }
1300
1301#ifdef DEBUG
1302 fputs(" ended typedef...\n", stderr);
1303#endif /* DEBUG */
1304 structclass = NULL;
1305 break;
1306 }
1307 else if (type && type->child && type->child->next &&
1308 (!strcmp(type->child->value.text.string, "enum") ||
1309 (!strcmp(type->child->value.text.string, "typedef") &&
1310 !strcmp(type->child->next->value.text.string, "enum"))))
1311 {
1312 /*
1313 * Enumeration type...
1314 */
1315
1316 if (!strcmp(type->child->value.text.string, "typedef"))
1317 {
1318#ifdef DEBUG
1319 fputs(" starting typedef...\n", stderr);
1320#endif /* DEBUG */
1321
1322 typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef");
1323 mxmlDelete(type->child);
1324 }
1325 else
1326 typedefnode = NULL;
1327
1328 enumeration = mxmlNewElement(MXML_NO_PARENT, "enumeration");
1329
1330#ifdef DEBUG
1331 fprintf(stderr, "Enumeration: <<<< %s >>>\n",
1332 type->child->next ?
1333 type->child->next->value.text.string : "(noname)");
1334#endif /* DEBUG */
1335
1336 if (type->child->next)
1337 {
1338 mxmlElementSetAttr(enumeration, "name",
1339 type->child->next->value.text.string);
1340 sort_node(tree, enumeration);
1341 }
1342
1343 if (typedefnode && type->child)
1344 type->child->value.text.whitespace = 0;
1345 else
1346 {
1347 mxmlDelete(type);
1348 type = NULL;
1349 }
1350
1351 if (typedefnode && comment->last_child)
1352 {
1353 /*
1354 * Copy comment for typedef as well as class/struct/union...
1355 */
1356
1357 mxmlNewText(comment, 0,
1358 comment->last_child->value.text.string);
1359 description = mxmlNewElement(typedefnode, "description");
1360#ifdef DEBUG
1361 fprintf(stderr,
1362 " duplicating comment %p/%p for typedef...\n",
1363 comment->last_child, comment->child);
1364#endif /* DEBUG */
1365 update_comment(typedefnode, comment->last_child);
1366 mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
1367 comment->last_child);
1368 }
1369
1370 description = mxmlNewElement(enumeration, "description");
1371#ifdef DEBUG
1372 fprintf(stderr, " adding comment %p/%p to enumeration...\n",
1373 comment->last_child, comment->child);
1374#endif /* DEBUG */
1375 update_comment(enumeration, comment->last_child);
1376 mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
1377 comment->last_child);
1378 }
1379 else if (type && type->child &&
1380 !strcmp(type->child->value.text.string, "extern"))
1381 {
1382 if (scan_file(filename, fp, tree))
1383 {
1384 mxmlDelete(comment);
1385 return (-1);
1386 }
1387 }
1388 else if (type)
1389 {
1390 mxmlDelete(type);
1391 type = NULL;
1392 }
1393
1394 braces ++;
1395 function = NULL;
1396 variable = NULL;
1397 break;
1398
1399 case '}' :
1400#ifdef DEBUG
1401 fputs(" close brace...\n", stderr);
1402#endif /* DEBUG */
1403
1404 if (structclass)
1405 scope = NULL;
1406
1407 if (!typedefnode)
1408 enumeration = NULL;
1409
1410 constant = NULL;
1411 structclass = NULL;
1412
1413 if (braces > 0)
1414 braces --;
1415 else
1416 {
1417 mxmlDelete(comment);
1418 return (0);
1419 }
1420 break;
1421
1422 case '(' :
1423 if (type)
1424 {
1425#ifdef DEBUG
1426 fputs("Identifier: <<<< ( >>>\n", stderr);
1427#endif /* DEBUG */
1428 mxmlNewText(type, 0, "(");
1429 }
1430
1431 parens ++;
1432 break;
1433
1434 case ')' :
1435 if (type && parens)
1436 {
1437#ifdef DEBUG
1438 fputs("Identifier: <<<< ) >>>\n", stderr);
1439#endif /* DEBUG */
1440 mxmlNewText(type, 0, ")");
1441 }
1442
1443 if (function && type && !parens)
1444 {
1445 /*
1446 * Check for "void" argument...
1447 */
1448
1449 if (type->child && type->child->next)
1450 variable = add_variable(function, "argument", type);
1451 else
1452 mxmlDelete(type);
1453
1454 type = NULL;
1455 }
1456
1457 if (parens > 0)
1458 parens --;
1459 break;
1460
1461 case ';' :
1462#ifdef DEBUG
1463 fputs("Identifier: <<<< ; >>>\n", stderr);
1464 fprintf(stderr, " enumeration=%p, function=%p, type=%p, type->child=%p, typedefnode=%p\n",
1465 enumeration, function, type, type ? type->child : NULL, typedefnode);
1466#endif /* DEBUG */
1467
1468 if (function)
1469 {
1470 if (!strcmp(tree->value.element.name, "class"))
1471 {
1472#ifdef DEBUG
1473 fputs(" ADDING FUNCTION TO CLASS\n", stderr);
1474#endif /* DEBUG */
1475 sort_node(tree, function);
1476 }
1477 else
1478 mxmlDelete(function);
1479
1480 function = NULL;
1481 variable = NULL;
1482 }
1483
1484 if (type)
1485 {
1486 /*
1487 * See if we have a typedef...
1488 */
1489
1490 if (type->child &&
1491 !strcmp(type->child->value.text.string, "typedef"))
1492 {
1493 /*
1494 * Yes, add it!
1495 */
1496
1497 typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef");
1498
1499 for (node = type->child->next; node; node = node->next)
1500 if (!strcmp(node->value.text.string, "("))
1501 break;
1502
1503 if (node)
1504 {
1505 for (node = node->next; node; node = node->next)
1506 if (strcmp(node->value.text.string, "*"))
1507 break;
1508 }
1509
1510 if (!node)
1511 node = type->last_child;
1512
1513#ifdef DEBUG
1514 fprintf(stderr, " ADDING TYPEDEF FOR %p(%s)...\n",
1515 node, node->value.text.string);
1516#endif /* DEBUG */
1517
1518 mxmlElementSetAttr(typedefnode, "name",
1519 node->value.text.string);
1520 sort_node(tree, typedefnode);
1521
1522 if (type->child != node)
1523 mxmlDelete(type->child);
1524
1525 mxmlDelete(node);
1526
1527 if (type->child)
1528 type->child->value.text.whitespace = 0;
1529
1530 mxmlAdd(typedefnode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
1531 type);
1532 type = NULL;
1533 break;
1534 }
1535 else if (typedefnode && enumeration)
1536 {
1537 /*
1538 * Add enum typedef...
1539 */
1540
1541 node = type->child;
1542
1543#ifdef DEBUG
1544 fprintf(stderr, " ADDING TYPEDEF FOR %p(%s)...\n",
1545 node, node->value.text.string);
1546#endif /* DEBUG */
1547
1548 mxmlElementSetAttr(typedefnode, "name",
1549 node->value.text.string);
1550 sort_node(tree, typedefnode);
1551 mxmlDelete(type);
1552
1553 type = mxmlNewElement(typedefnode, "type");
1554 mxmlNewText(type, 0, "enum");
1555 mxmlNewText(type, 1,
1556 mxmlElementGetAttr(enumeration, "name"));
1557 enumeration = NULL;
1558 type = NULL;
1559 break;
1560 }
1561
1562 mxmlDelete(type);
1563 type = NULL;
1564 }
1565 break;
1566
1567 case ':' :
1568 if (type)
1569 {
1570#ifdef DEBUG
1571 fputs("Identifier: <<<< : >>>\n", stderr);
1572#endif /* DEBUG */
1573 mxmlNewText(type, 1, ":");
1574 }
1575 break;
1576
1577 case '*' :
1578 if (type)
1579 {
1580#ifdef DEBUG
1581 fputs("Identifier: <<<< * >>>\n", stderr);
1582#endif /* DEBUG */
1583 ch = type->last_child->value.text.string[0];
1584 mxmlNewText(type, isalnum(ch) || ch == '_', "*");
1585 }
1586 break;
1587
1588 case ',' :
1589 if (type && !enumeration)
1590 {
1591#ifdef DEBUG
1592 fputs("Identifier: <<<< , >>>\n", stderr);
1593#endif /* DEBUG */
1594 mxmlNewText(type, 0, ",");
1595 }
1596 break;
1597
1598 case '&' :
1599 if (type)
1600 {
1601#ifdef DEBUG
1602 fputs("Identifier: <<<< & >>>\n", stderr);
1603#endif /* DEBUG */
1604 mxmlNewText(type, 1, "&");
1605 }
1606 break;
1607
1608 case '+' :
1609 if (type)
1610 {
1611#ifdef DEBUG
1612 fputs("Identifier: <<<< + >>>\n", stderr);
1613#endif /* DEBUG */
1614 ch = type->last_child->value.text.string[0];
1615 mxmlNewText(type, isalnum(ch) || ch == '_', "+");
1616 }
1617 break;
1618
1619 case '-' :
1620 if (type)
1621 {
1622#ifdef DEBUG
1623 fputs("Identifier: <<<< - >>>\n", stderr);
1624#endif /* DEBUG */
1625 ch = type->last_child->value.text.string[0];
1626 mxmlNewText(type, isalnum(ch) || ch == '_', "-");
1627 }
1628 break;
1629
1630 case '=' :
1631 if (type)
1632 {
1633#ifdef DEBUG
1634 fputs("Identifier: <<<< = >>>\n", stderr);
1635#endif /* DEBUG */
1636 ch = type->last_child->value.text.string[0];
1637 mxmlNewText(type, isalnum(ch) || ch == '_', "=");
1638 }
1639 break;
1640
1641 default : /* Other */
1642 if (isalnum(ch) || ch == '_' || ch == '.' || ch == ':' || ch == '~')
1643 {
1644 state = STATE_IDENTIFIER;
1645 bufptr = buffer;
1646 *bufptr++ = ch;
1647 }
1648 break;
1649 }
1650 break;
1651
1652 case STATE_PREPROCESSOR : /* Preprocessor directive */
1653 if (ch == '\n')
1654 state = STATE_NONE;
1655 else if (ch == '\\')
1656 getc(fp);
1657 break;
1658
1659 case STATE_C_COMMENT : /* Inside a C comment */
1660 switch (ch)
1661 {
1662 case '\n' :
1663 while ((ch = getc(fp)) != EOF)
1664 if (ch == '*')
1665 {
1666 ch = getc(fp);
1667
1668 if (ch == '/')
1669 {
1670 *bufptr = '\0';
1671
1672 if (comment->child != comment->last_child)
1673 {
1674#ifdef DEBUG
1675 fprintf(stderr, " removing comment %p(%20.20s), last comment %p(%20.20s)...\n",
1676 comment->child,
1677 comment->child ? comment->child->value.text.string : "",
1678 comment->last_child,
1679 comment->last_child ? comment->last_child->value.text.string : "");
1680#endif /* DEBUG */
1681 mxmlDelete(comment->child);
1682#ifdef DEBUG
1683 fprintf(stderr, " new comment %p, last comment %p...\n",
1684 comment->child, comment->last_child);
1685#endif /* DEBUG */
1686 }
1687
1688#ifdef DEBUG
1689 fprintf(stderr,
1690 " processing comment, variable=%p, "
1691 "constant=%p, typedefnode=%p, tree=\"%s\"\n",
1692 variable, constant, typedefnode,
1693 tree->value.element.name);
1694#endif /* DEBUG */
1695
1696 if (variable)
1697 {
1698 if (strstr(buffer, "@private@"))
1699 {
1700 /*
1701 * Delete private variables...
1702 */
1703
1704 mxmlDelete(variable);
1705 }
1706 else
1707 {
1708 description = mxmlNewElement(variable, "description");
1709#ifdef DEBUG
1710 fprintf(stderr,
1711 " adding comment %p/%p to variable...\n",
1712 comment->last_child, comment->child);
1713#endif /* DEBUG */
1714 mxmlNewText(comment, 0, buffer);
1715 update_comment(variable,
1716 mxmlNewText(description, 0, buffer));
1717 }
1718
1719 variable = NULL;
1720 }
1721 else if (constant)
1722 {
1723 if (strstr(buffer, "@private@"))
1724 {
1725 /*
1726 * Delete private constants...
1727 */
1728
1729 mxmlDelete(constant);
1730 }
1731 else
1732 {
1733 description = mxmlNewElement(constant, "description");
1734#ifdef DEBUG
1735 fprintf(stderr,
1736 " adding comment %p/%p to constant...\n",
1737 comment->last_child, comment->child);
1738#endif /* DEBUG */
1739 mxmlNewText(comment, 0, buffer);
1740 update_comment(constant,
1741 mxmlNewText(description, 0, buffer));
1742 }
1743
1744 constant = NULL;
1745 }
1746 else if (typedefnode)
1747 {
1748 if (strstr(buffer, "@private@"))
1749 {
1750 /*
1751 * Delete private typedefs...
1752 */
1753
1754 mxmlDelete(typedefnode);
1755
1756 if (structclass)
1757 {
1758 mxmlDelete(structclass);
1759 structclass = NULL;
1760 }
1761
1762 if (enumeration)
1763 {
1764 mxmlDelete(enumeration);
1765 enumeration = NULL;
1766 }
1767 }
1768 else
1769 {
1770 description = mxmlNewElement(typedefnode, "description");
1771#ifdef DEBUG
1772 fprintf(stderr,
1773 " adding comment %p/%p to typedef %s...\n",
1774 comment->last_child, comment->child,
1775 mxmlElementGetAttr(typedefnode, "name"));
1776#endif /* DEBUG */
1777 mxmlNewText(comment, 0, buffer);
1778 update_comment(typedefnode,
1779 mxmlNewText(description, 0, buffer));
1780
1781 if (structclass)
1782 {
1783 description = mxmlNewElement(structclass, "description");
1784 update_comment(structclass,
1785 mxmlNewText(description, 0, buffer));
1786 }
1787 else if (enumeration)
1788 {
1789 description = mxmlNewElement(enumeration, "description");
1790 update_comment(enumeration,
1791 mxmlNewText(description, 0, buffer));
1792 }
1793 }
1794
1795 typedefnode = NULL;
1796 }
1797 else if (strcmp(tree->value.element.name, "mxmldoc") &&
1798 !mxmlFindElement(tree, tree, "description",
1799 NULL, NULL, MXML_DESCEND_FIRST))
1800 {
1801 description = mxmlNewElement(tree, "description");
1802#ifdef DEBUG
1803 fprintf(stderr, " adding comment %p/%p to parent...\n",
1804 comment->last_child, comment->child);
1805#endif /* DEBUG */
1806 mxmlNewText(comment, 0, buffer);
1807 update_comment(tree,
1808 mxmlNewText(description, 0, buffer));
1809 }
1810 else
1811 {
1812#ifdef DEBUG
1813 fprintf(stderr, " before adding comment, child=%p, last_child=%p\n",
1814 comment->child, comment->last_child);
1815#endif /* DEBUG */
1816 mxmlNewText(comment, 0, buffer);
1817#ifdef DEBUG
1818 fprintf(stderr, " after adding comment, child=%p, last_child=%p\n",
1819 comment->child, comment->last_child);
1820#endif /* DEBUG */
1821 }
1822#ifdef DEBUG
1823 fprintf(stderr, "C comment: <<<< %s >>>\n", buffer);
1824#endif /* DEBUG */
1825
1826 state = STATE_NONE;
1827 break;
1828 }
1829 else
1830 ungetc(ch, fp);
1831 }
1832 else if (ch == '\n' && bufptr > buffer &&
1833 bufptr < (buffer + sizeof(buffer) - 1))
1834 *bufptr++ = ch;
1835 else if (!isspace(ch))
1836 break;
1837
1838 if (ch != EOF)
1839 ungetc(ch, fp);
1840
1841 if (bufptr > buffer && bufptr < (buffer + sizeof(buffer) - 1))
1842 *bufptr++ = '\n';
1843 break;
1844
1845 case '/' :
1846 if (ch == '/' && bufptr > buffer && bufptr[-1] == '*')
1847 {
1848 while (bufptr > buffer &&
1849 (bufptr[-1] == '*' || isspace(bufptr[-1] & 255)))
1850 bufptr --;
1851 *bufptr = '\0';
1852
1853 if (comment->child != comment->last_child)
1854 {
1855#ifdef DEBUG
1856 fprintf(stderr, " removing comment %p(%20.20s), last comment %p(%20.20s)...\n",
1857 comment->child,
1858 comment->child ? comment->child->value.text.string : "",
1859 comment->last_child,
1860 comment->last_child ? comment->last_child->value.text.string : "");
1861#endif /* DEBUG */
1862 mxmlDelete(comment->child);
1863#ifdef DEBUG
1864 fprintf(stderr, " new comment %p, last comment %p...\n",
1865 comment->child, comment->last_child);
1866#endif /* DEBUG */
1867 }
1868
1869#ifdef DEBUG
1870 fprintf(stderr,
1871 " processing comment, variable=%p, "
1872 "constant=%p, typedefnode=%p, tree=\"%s\"\n",
1873 variable, constant, typedefnode,
1874 tree->value.element.name);
1875#endif /* DEBUG */
1876
1877 if (variable)
1878 {
1879 if (strstr(buffer, "@private@"))
1880 {
1881 /*
1882 * Delete private variables...
1883 */
1884
1885 mxmlDelete(variable);
1886 }
1887 else
1888 {
1889 description = mxmlNewElement(variable, "description");
1890#ifdef DEBUG
1891 fprintf(stderr, " adding comment %p/%p to variable...\n",
1892 comment->last_child, comment->child);
1893#endif /* DEBUG */
1894 mxmlNewText(comment, 0, buffer);
1895 update_comment(variable,
1896 mxmlNewText(description, 0, buffer));
1897 }
1898
1899 variable = NULL;
1900 }
1901 else if (constant)
1902 {
1903 if (strstr(buffer, "@private@"))
1904 {
1905 /*
1906 * Delete private constants...
1907 */
1908
1909 mxmlDelete(constant);
1910 }
1911 else
1912 {
1913 description = mxmlNewElement(constant, "description");
1914#ifdef DEBUG
1915 fprintf(stderr, " adding comment %p/%p to constant...\n",
1916 comment->last_child, comment->child);
1917#endif /* DEBUG */
1918 mxmlNewText(comment, 0, buffer);
1919 update_comment(constant,
1920 mxmlNewText(description, 0, buffer));
1921 }
1922
1923 constant = NULL;
1924 }
1925 else if (typedefnode)
1926 {
1927 if (strstr(buffer, "@private@"))
1928 {
1929 /*
1930 * Delete private typedefs...
1931 */
1932
1933 mxmlDelete(typedefnode);
1934
1935 if (structclass)
1936 {
1937 mxmlDelete(structclass);
1938 structclass = NULL;
1939 }
1940
1941 if (enumeration)
1942 {
1943 mxmlDelete(enumeration);
1944 enumeration = NULL;
1945 }
1946 }
1947 else
1948 {
1949 description = mxmlNewElement(typedefnode, "description");
1950#ifdef DEBUG
1951 fprintf(stderr,
1952 " adding comment %p/%p to typedef %s...\n",
1953 comment->last_child, comment->child,
1954 mxmlElementGetAttr(typedefnode, "name"));
1955#endif /* DEBUG */
1956 mxmlNewText(comment, 0, buffer);
1957 update_comment(typedefnode,
1958 mxmlNewText(description, 0, buffer));
1959
1960 if (structclass)
1961 {
1962 description = mxmlNewElement(structclass, "description");
1963 update_comment(structclass,
1964 mxmlNewText(description, 0, buffer));
1965 }
1966 else if (enumeration)
1967 {
1968 description = mxmlNewElement(enumeration, "description");
1969 update_comment(enumeration,
1970 mxmlNewText(description, 0, buffer));
1971 }
1972 }
1973
1974 typedefnode = NULL;
1975 }
1976 else if (strcmp(tree->value.element.name, "mxmldoc") &&
1977 !mxmlFindElement(tree, tree, "description",
1978 NULL, NULL, MXML_DESCEND_FIRST))
1979 {
1980 description = mxmlNewElement(tree, "description");
1981#ifdef DEBUG
1982 fprintf(stderr, " adding comment %p/%p to parent...\n",
1983 comment->last_child, comment->child);
1984#endif /* DEBUG */
1985 mxmlNewText(comment, 0, buffer);
1986 update_comment(tree,
1987 mxmlNewText(description, 0, buffer));
1988 }
1989 else
1990 mxmlNewText(comment, 0, buffer);
1991
1992#ifdef DEBUG
1993 fprintf(stderr, "C comment: <<<< %s >>>\n", buffer);
1994#endif /* DEBUG */
1995
1996 state = STATE_NONE;
1997 break;
1998 }
1999
2000 default :
2001 if (ch == ' ' && bufptr == buffer)
2002 break;
2003
2004 if (bufptr < (buffer + sizeof(buffer) - 1))
2005 *bufptr++ = ch;
2006 break;
2007 }
2008 break;
2009
2010 case STATE_CXX_COMMENT : /* Inside a C++ comment */
2011 if (ch == '\n')
2012 {
2013 state = STATE_NONE;
2014 *bufptr = '\0';
2015
2016 if (comment->child != comment->last_child)
2017 {
2018#ifdef DEBUG
2019 fprintf(stderr, " removing comment %p(%20.20s), last comment %p(%20.20s)...\n",
2020 comment->child,
2021 comment->child ? comment->child->value.text.string : "",
2022 comment->last_child,
2023 comment->last_child ? comment->last_child->value.text.string : "");
2024#endif /* DEBUG */
2025 mxmlDelete(comment->child);
2026#ifdef DEBUG
2027 fprintf(stderr, " new comment %p, last comment %p...\n",
2028 comment->child, comment->last_child);
2029#endif /* DEBUG */
2030 }
2031
2032 if (variable)
2033 {
2034 if (strstr(buffer, "@private@"))
2035 {
2036 /*
2037 * Delete private variables...
2038 */
2039
2040 mxmlDelete(variable);
2041 }
2042 else
2043 {
2044 description = mxmlNewElement(variable, "description");
2045#ifdef DEBUG
2046 fprintf(stderr, " adding comment %p/%p to variable...\n",
2047 comment->last_child, comment->child);
2048#endif /* DEBUG */
2049 mxmlNewText(comment, 0, buffer);
2050 update_comment(variable,
2051 mxmlNewText(description, 0, buffer));
2052 }
2053
2054 variable = NULL;
2055 }
2056 else if (constant)
2057 {
2058 if (strstr(buffer, "@private@"))
2059 {
2060 /*
2061 * Delete private constants...
2062 */
2063
2064 mxmlDelete(constant);
2065 }
2066 else
2067 {
2068 description = mxmlNewElement(constant, "description");
2069#ifdef DEBUG
2070 fprintf(stderr, " adding comment %p/%p to constant...\n",
2071 comment->last_child, comment->child);
2072#endif /* DEBUG */
2073 mxmlNewText(comment, 0, buffer);
2074 update_comment(constant,
2075 mxmlNewText(description, 0, buffer));
2076 }
2077
2078 constant = NULL;
2079 }
2080 else if (typedefnode)
2081 {
2082 if (strstr(buffer, "@private@"))
2083 {
2084 /*
2085 * Delete private typedefs...
2086 */
2087
2088 mxmlDelete(typedefnode);
2089 typedefnode = NULL;
2090
2091 if (structclass)
2092 {
2093 mxmlDelete(structclass);
2094 structclass = NULL;
2095 }
2096
2097 if (enumeration)
2098 {
2099 mxmlDelete(enumeration);
2100 enumeration = NULL;
2101 }
2102 }
2103 else
2104 {
2105 description = mxmlNewElement(typedefnode, "description");
2106#ifdef DEBUG
2107 fprintf(stderr, " adding comment %p/%p to typedef %s...\n",
2108 comment->last_child, comment->child,
2109 mxmlElementGetAttr(typedefnode, "name"));
2110#endif /* DEBUG */
2111 mxmlNewText(comment, 0, buffer);
2112 update_comment(typedefnode,
2113 mxmlNewText(description, 0, buffer));
2114
2115 if (structclass)
2116 {
2117 description = mxmlNewElement(structclass, "description");
2118 update_comment(structclass,
2119 mxmlNewText(description, 0, buffer));
2120 }
2121 else if (enumeration)
2122 {
2123 description = mxmlNewElement(enumeration, "description");
2124 update_comment(enumeration,
2125 mxmlNewText(description, 0, buffer));
2126 }
2127 }
2128 }
2129 else if (strcmp(tree->value.element.name, "mxmldoc") &&
2130 !mxmlFindElement(tree, tree, "description",
2131 NULL, NULL, MXML_DESCEND_FIRST))
2132 {
2133 description = mxmlNewElement(tree, "description");
2134#ifdef DEBUG
2135 fprintf(stderr, " adding comment %p/%p to parent...\n",
2136 comment->last_child, comment->child);
2137#endif /* DEBUG */
2138 mxmlNewText(comment, 0, buffer);
2139 update_comment(tree,
2140 mxmlNewText(description, 0, buffer));
2141 }
2142 else
2143 mxmlNewText(comment, 0, buffer);
2144
2145#ifdef DEBUG
2146 fprintf(stderr, "C++ comment: <<<< %s >>>\n", buffer);
2147#endif /* DEBUG */
2148 }
2149 else if (ch == ' ' && bufptr == buffer)
2150 break;
2151 else if (bufptr < (buffer + sizeof(buffer) - 1))
2152 *bufptr++ = ch;
2153 break;
2154
2155 case STATE_STRING : /* Inside a string constant */
2156 *bufptr++ = ch;
2157
2158 if (ch == '\\')
2159 *bufptr++ = getc(fp);
2160 else if (ch == '\"')
2161 {
2162 *bufptr = '\0';
2163
2164 if (type)
2165 mxmlNewText(type, type->child != NULL, buffer);
2166
2167 state = STATE_NONE;
2168 }
2169 break;
2170
2171 case STATE_CHARACTER : /* Inside a character constant */
2172 *bufptr++ = ch;
2173
2174 if (ch == '\\')
2175 *bufptr++ = getc(fp);
2176 else if (ch == '\'')
2177 {
2178 *bufptr = '\0';
2179
2180 if (type)
2181 mxmlNewText(type, type->child != NULL, buffer);
2182
2183 state = STATE_NONE;
2184 }
2185 break;
2186
2187 case STATE_IDENTIFIER : /* Inside a keyword or identifier */
2188 if (isalnum(ch) || ch == '_' || ch == '[' || ch == ']' ||
2189 (ch == ',' && (parens > 1 || (type && !enumeration && !function))) ||
2190 ch == ':' || ch == '.' || ch == '~')
2191 {
2192 if (bufptr < (buffer + sizeof(buffer) - 1))
2193 *bufptr++ = ch;
2194 }
2195 else
2196 {
2197 ungetc(ch, fp);
2198 *bufptr = '\0';
2199 state = STATE_NONE;
2200
2201#ifdef DEBUG
2202 fprintf(stderr, " braces=%d, type=%p, type->child=%p, buffer=\"%s\"\n",
2203 braces, type, type ? type->child : NULL, buffer);
2204#endif /* DEBUG */
2205
2206 if (!braces)
2207 {
2208 if (!type || !type->child)
2209 {
2210 if (!strcmp(tree->value.element.name, "class"))
2211 {
2212 if (!strcmp(buffer, "public") ||
2213 !strcmp(buffer, "public:"))
2214 {
2215 scope = "public";
2216#ifdef DEBUG
2217 fputs(" scope = public\n", stderr);
2218#endif /* DEBUG */
2219 break;
2220 }
2221 else if (!strcmp(buffer, "private") ||
2222 !strcmp(buffer, "private:"))
2223 {
2224 scope = "private";
2225#ifdef DEBUG
2226 fputs(" scope = private\n", stderr);
2227#endif /* DEBUG */
2228 break;
2229 }
2230 else if (!strcmp(buffer, "protected") ||
2231 !strcmp(buffer, "protected:"))
2232 {
2233 scope = "protected";
2234#ifdef DEBUG
2235 fputs(" scope = protected\n", stderr);
2236#endif /* DEBUG */
2237 break;
2238 }
2239 }
2240 }
2241
2242 if (!type)
2243 type = mxmlNewElement(MXML_NO_PARENT, "type");
2244
2245#ifdef DEBUG
2246 fprintf(stderr, " function=%p (%s), type->child=%p, ch='%c', parens=%d\n",
2247 function,
2248 function ? mxmlElementGetAttr(function, "name") : "null",
2249 type->child, ch, parens);
2250#endif /* DEBUG */
2251
2252 if (!function && ch == '(')
2253 {
2254 if (type->child &&
2255 !strcmp(type->child->value.text.string, "extern"))
2256 {
2257 /*
2258 * Remove external declarations...
2259 */
2260
2261 mxmlDelete(type);
2262 type = NULL;
2263 break;
2264 }
2265
2266 if (type->child &&
2267 !strcmp(type->child->value.text.string, "static") &&
2268 !strcmp(tree->value.element.name, "mxmldoc"))
2269 {
2270 /*
2271 * Remove static functions...
2272 */
2273
2274 mxmlDelete(type);
2275 type = NULL;
2276 break;
2277 }
2278
2279 function = mxmlNewElement(MXML_NO_PARENT, "function");
2280 if ((bufptr = strchr(buffer, ':')) != NULL && bufptr[1] == ':')
2281 {
2282 *bufptr = '\0';
2283 bufptr += 2;
2284
2285 if ((fstructclass =
2286 mxmlFindElement(tree, tree, "class", "name", buffer,
2287 MXML_DESCEND_FIRST)) == NULL)
2288 fstructclass =
2289 mxmlFindElement(tree, tree, "struct", "name", buffer,
2290 MXML_DESCEND_FIRST);
2291 }
2292 else
2293 bufptr = buffer;
2294
2295 mxmlElementSetAttr(function, "name", bufptr);
2296
2297 if (scope)
2298 mxmlElementSetAttr(function, "scope", scope);
2299
2300#ifdef DEBUG
2301 fprintf(stderr, "function: %s\n", buffer);
2302 fprintf(stderr, " scope = %s\n", scope ? scope : "(null)");
2303 fprintf(stderr, " comment = %p\n", comment);
2304 fprintf(stderr, " child = (%p) %s\n",
2305 comment->child,
2306 comment->child ?
2307 comment->child->value.text.string : "(null)");
2308 fprintf(stderr, " last_child = (%p) %s\n",
2309 comment->last_child,
2310 comment->last_child ?
2311 comment->last_child->value.text.string : "(null)");
2312#endif /* DEBUG */
2313
2314 if (type->last_child &&
2315 strcmp(type->last_child->value.text.string, "void"))
2316 {
2317 returnvalue = mxmlNewElement(function, "returnvalue");
2318
2319 mxmlAdd(returnvalue, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type);
2320
2321 description = mxmlNewElement(returnvalue, "description");
2322#ifdef DEBUG
2323 fprintf(stderr, " adding comment %p/%p to returnvalue...\n",
2324 comment->last_child, comment->child);
2325#endif /* DEBUG */
2326 update_comment(returnvalue, comment->last_child);
2327 mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
2328 comment->last_child);
2329 }
2330 else
2331 mxmlDelete(type);
2332
2333 description = mxmlNewElement(function, "description");
2334#ifdef DEBUG
2335 fprintf(stderr, " adding comment %p/%p to function...\n",
2336 comment->last_child, comment->child);
2337#endif /* DEBUG */
2338 update_comment(function, comment->last_child);
2339 mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
2340 comment->last_child);
2341
2342 type = NULL;
2343 }
2344 else if (function && ((ch == ')' && parens == 1) || ch == ','))
2345 {
2346 /*
2347 * Argument definition...
2348 */
2349
2350 if (strcmp(buffer, "void"))
2351 {
2352 mxmlNewText(type, type->child != NULL &&
2353 type->last_child->value.text.string[0] != '(' &&
2354 type->last_child->value.text.string[0] != '*',
2355 buffer);
2356
2357#ifdef DEBUG
2358 fprintf(stderr, "Argument: <<<< %s >>>\n", buffer);
2359#endif /* DEBUG */
2360
2361 variable = add_variable(function, "argument", type);
2362 }
2363 else
2364 mxmlDelete(type);
2365
2366 type = NULL;
2367 }
2368 else if (type->child && !function && (ch == ';' || ch == ','))
2369 {
2370#ifdef DEBUG
2371 fprintf(stderr, " got semicolon, typedefnode=%p, structclass=%p\n",
2372 typedefnode, structclass);
2373#endif /* DEBUG */
2374
2375 if (typedefnode || structclass)
2376 {
2377#ifdef DEBUG
2378 fprintf(stderr, "Typedef/struct/class: <<<< %s >>>>\n", buffer);
2379#endif /* DEBUG */
2380
2381 if (typedefnode)
2382 {
2383 mxmlElementSetAttr(typedefnode, "name", buffer);
2384
2385 sort_node(tree, typedefnode);
2386 }
2387
2388 if (structclass && !mxmlElementGetAttr(structclass, "name"))
2389 {
2390#ifdef DEBUG
2391 fprintf(stderr, "setting struct/class name to %s!\n",
2392 type->last_child->value.text.string);
2393#endif /* DEBUG */
2394 mxmlElementSetAttr(structclass, "name", buffer);
2395
2396 sort_node(tree, structclass);
2397 structclass = NULL;
2398 }
2399
2400 if (typedefnode)
2401 mxmlAdd(typedefnode, MXML_ADD_BEFORE, MXML_ADD_TO_PARENT,
2402 type);
2403 else
2404 mxmlDelete(type);
2405
2406 type = NULL;
2407 typedefnode = NULL;
2408 }
2409 else if (type->child &&
2410 !strcmp(type->child->value.text.string, "typedef"))
2411 {
2412 /*
2413 * Simple typedef...
2414 */
2415
2416#ifdef DEBUG
2417 fprintf(stderr, "Typedef: <<<< %s >>>\n", buffer);
2418#endif /* DEBUG */
2419
2420 typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef");
2421 mxmlElementSetAttr(typedefnode, "name", buffer);
2422 mxmlDelete(type->child);
2423
2424 sort_node(tree, typedefnode);
2425
2426 if (type->child)
2427 type->child->value.text.whitespace = 0;
2428
2429 mxmlAdd(typedefnode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type);
2430 type = NULL;
2431 }
2432 else if (!parens)
2433 {
2434 /*
2435 * Variable definition...
2436 */
2437
2438 if (type->child &&
2439 !strcmp(type->child->value.text.string, "static") &&
2440 !strcmp(tree->value.element.name, "mxmldoc"))
2441 {
2442 /*
2443 * Remove static functions...
2444 */
2445
2446 mxmlDelete(type);
2447 type = NULL;
2448 break;
2449 }
2450
2451 mxmlNewText(type, type->child != NULL &&
2452 type->last_child->value.text.string[0] != '(' &&
2453 type->last_child->value.text.string[0] != '*',
2454 buffer);
2455
2456#ifdef DEBUG
2457 fprintf(stderr, "Variable: <<<< %s >>>>\n", buffer);
2458 fprintf(stderr, " scope = %s\n", scope ? scope : "(null)");
2459#endif /* DEBUG */
2460
2461 variable = add_variable(MXML_NO_PARENT, "variable", type);
2462 type = NULL;
2463
2464 sort_node(tree, variable);
2465
2466 if (scope)
2467 mxmlElementSetAttr(variable, "scope", scope);
2468 }
2469 }
2470 else
2471 {
2472#ifdef DEBUG
2473 fprintf(stderr, "Identifier: <<<< %s >>>>\n", buffer);
2474#endif /* DEBUG */
2475
2476 mxmlNewText(type, type->child != NULL &&
2477 type->last_child->value.text.string[0] != '(' &&
2478 type->last_child->value.text.string[0] != '*',
2479 buffer);
2480 }
2481 }
2482 else if (enumeration && !isdigit(buffer[0] & 255))
2483 {
2484#ifdef DEBUG
2485 fprintf(stderr, "Constant: <<<< %s >>>\n", buffer);
2486#endif /* DEBUG */
2487
2488 constant = mxmlNewElement(MXML_NO_PARENT, "constant");
2489 mxmlElementSetAttr(constant, "name", buffer);
2490 sort_node(enumeration, constant);
2491 }
2492 else if (type)
2493 {
2494 mxmlDelete(type);
2495 type = NULL;
2496 }
2497 }
2498 break;
2499 }
2500
2501#if DEBUG > 1
2502 if (state != oldstate)
2503 {
2504 fprintf(stderr, " changed states from %s to %s on receipt of character '%c'...\n",
2505 states[oldstate], states[state], oldch);
2506 fprintf(stderr, " variable = %p\n", variable);
2507 if (type)
2508 {
2509 fputs(" type =", stderr);
2510 for (temp = type->child; temp; temp = temp->next)
2511 fprintf(stderr, " \"%s\"", temp->value.text.string);
2512 fputs("\n", stderr);
2513 }
2514 }
2515#endif /* DEBUG > 1 */
2516 }
2517
2518 mxmlDelete(comment);
2519
2520 /*
2521 * All done, return with no errors...
2522 */
2523
2524 return (0);
2525}
2526
2527
2528/*
2529 * 'sort_node()' - Insert a node sorted into a tree.
2530 */
2531
2532static void
2533sort_node(mxml_node_t *tree, /* I - Tree to sort into */
2534 mxml_node_t *node) /* I - Node to add */
2535{
2536 mxml_node_t *temp; /* Current node */
2537 const char *tempname, /* Name of current node */
2538 *nodename, /* Name of node */
2539 *scope; /* Scope */
2540
2541
2542#if DEBUG > 1
2543 fprintf(stderr, " sort_node(tree=%p, node=%p)\n", tree, node);
2544#endif /* DEBUG > 1 */
2545
2546 /*
2547 * Range check input...
2548 */
2549
2550 if (!tree || !node || node->parent == tree)
2551 return;
2552
2553 /*
2554 * Get the node name...
2555 */
2556
2557 if ((nodename = mxmlElementGetAttr(node, "name")) == NULL)
2558 return;
2559
2560 if (nodename[0] == '_')
2561 return; /* Hide private names */
2562
2563#if DEBUG > 1
2564 fprintf(stderr, " nodename=%p (\"%s\")\n", nodename, nodename);
2565#endif /* DEBUG > 1 */
2566
2567 /*
2568 * Delete any existing definition at this level, if one exists...
2569 */
2570
2571 if ((temp = mxmlFindElement(tree, tree, node->value.element.name,
2572 "name", nodename, MXML_DESCEND_FIRST)) != NULL)
2573 {
2574 /*
2575 * Copy the scope if needed...
2576 */
2577
2578 if ((scope = mxmlElementGetAttr(temp, "scope")) != NULL &&
2579 mxmlElementGetAttr(node, "scope") == NULL)
2580 {
2581#ifdef DEBUG
2582 fprintf(stderr, " copying scope %s for %s\n", scope, nodename);
2583#endif /* DEBUG */
2584
2585 mxmlElementSetAttr(node, "scope", scope);
2586 }
2587
2588 mxmlDelete(temp);
2589 }
2590
2591 /*
2592 * Add the node into the tree at the proper place...
2593 */
2594
2595 for (temp = tree->child; temp; temp = temp->next)
2596 {
2597#if DEBUG > 1
2598 fprintf(stderr, " temp=%p\n", temp);
2599#endif /* DEBUG > 1 */
2600
2601 if ((tempname = mxmlElementGetAttr(temp, "name")) == NULL)
2602 continue;
2603
2604#if DEBUG > 1
2605 fprintf(stderr, " tempname=%p (\"%s\")\n", tempname, tempname);
2606#endif /* DEBUG > 1 */
2607
2608 if (strcmp(nodename, tempname) < 0)
2609 break;
2610 }
2611
2612 if (temp)
2613 mxmlAdd(tree, MXML_ADD_BEFORE, temp, node);
2614 else
2615 mxmlAdd(tree, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
2616}
2617
2618
2619/*
2620 * 'update_comment()' - Update a comment node.
2621 */
2622
2623static void
2624update_comment(mxml_node_t *parent, /* I - Parent node */
2625 mxml_node_t *comment) /* I - Comment node */
2626{
2627 char *ptr; /* Pointer into comment */
2628
2629
2630#ifdef DEBUG
2631 fprintf(stderr, "update_comment(parent=%p, comment=%p)\n",
2632 parent, comment);
2633#endif /* DEBUG */
2634
2635 /*
2636 * Range check the input...
2637 */
2638
2639 if (!parent || !comment)
2640 return;
2641
2642 /*
2643 * Convert "\/" to "/"...
2644 */
2645
2646 for (ptr = strstr(comment->value.text.string, "\\/");
2647 ptr;
2648 ptr = strstr(ptr, "\\/"))
2649 safe_strcpy(ptr, ptr + 1);
2650
2651 /*
2652 * Update the comment...
2653 */
2654
2655 ptr = comment->value.text.string;
2656
2657 if (*ptr == '\'')
2658 {
2659 /*
2660 * Convert "'name()' - description" to "description".
2661 */
2662
2663 for (ptr ++; *ptr && *ptr != '\''; ptr ++);
2664
2665 if (*ptr == '\'')
2666 {
2667 ptr ++;
2668 while (isspace(*ptr & 255))
2669 ptr ++;
2670
2671 if (*ptr == '-')
2672 ptr ++;
2673
2674 while (isspace(*ptr & 255))
2675 ptr ++;
2676
2677 safe_strcpy(comment->value.text.string, ptr);
2678 }
2679 }
2680 else if (!strncmp(ptr, "I ", 2) || !strncmp(ptr, "O ", 2) ||
2681 !strncmp(ptr, "IO ", 3))
2682 {
2683 /*
2684 * 'Convert "I - description", "IO - description", or "O - description"
2685 * to description + direction attribute.
2686 */
2687
2688 ptr = strchr(ptr, ' ');
2689 *ptr++ = '\0';
2690
2691 if (!strcmp(parent->value.element.name, "argument"))
2692 mxmlElementSetAttr(parent, "direction", comment->value.text.string);
2693
2694 while (isspace(*ptr & 255))
2695 ptr ++;
2696
2697 if (*ptr == '-')
2698 ptr ++;
2699
2700 while (isspace(*ptr & 255))
2701 ptr ++;
2702
2703 safe_strcpy(comment->value.text.string, ptr);
2704 }
2705
2706 /*
2707 * Eliminate leading and trailing *'s...
2708 */
2709
2710 for (ptr = comment->value.text.string; *ptr == '*'; ptr ++);
2711 for (; isspace(*ptr & 255); ptr ++);
2712 if (ptr > comment->value.text.string)
2713 safe_strcpy(comment->value.text.string, ptr);
2714
2715 for (ptr = comment->value.text.string + strlen(comment->value.text.string) - 1;
2716 ptr > comment->value.text.string && *ptr == '*';
2717 ptr --)
2718 *ptr = '\0';
2719 for (; ptr > comment->value.text.string && isspace(*ptr & 255); ptr --)
2720 *ptr = '\0';
2721
2722#ifdef DEBUG
2723 fprintf(stderr, " updated comment = %s\n", comment->value.text.string);
2724#endif /* DEBUG */
2725}
2726
2727
2728/*
2729 * 'usage()' - Show program usage...
2730 */
2731
2732static void
2733usage(const char *option) /* I - Unknown option */
2734{
2735 if (option)
2736 printf("mxmldoc: Bad option \"%s\"!\n\n", option);
2737
2738 puts("Usage: mxmldoc [options] [filename.xml] [source files] >filename.html");
2739 puts("Options:");
2740 puts(" --css filename.css Set CSS stylesheet file");
2741 puts(" --docset bundleid.docset Generate documentation set");
2742 puts(" --docversion version Set documentation version");
2743 puts(" --feedname name Set documentation set feed name");
2744 puts(" --feedurl url Set documentation set feed URL");
2745 puts(" --footer footerfile Set footer file");
2746 puts(" --framed basename Generate framed HTML to basename*.html");
2747 puts(" --header headerfile Set header file");
2748 puts(" --intro introfile Set introduction file");
2749 puts(" --man name Generate man page");
2750 puts(" --no-output Do no generate documentation file");
2751 puts(" --section section Set section name");
2752 puts(" --title title Set documentation title");
2753 puts(" --tokens path Generate Xcode docset Tokens.xml file");
2754 puts(" --version Show mxmldoc/Mini-XML version");
2755
2756 exit(1);
2757}
2758
2759
2760/*
2761 * 'write_description()' - Write the description text.
2762 */
2763
2764static void
2765write_description(
2766 FILE *out, /* I - Output file */
2767 mxml_node_t *description, /* I - Description node */
2768 const char *element, /* I - HTML element, if any */
2769 int summary) /* I - Show summary */
2770{
2771 char text[10240], /* Text for description */
2772 *start, /* Start of code/link */
2773 *ptr; /* Pointer into text */
2774 int col; /* Current column */
2775
2776
2777 if (!description)
2778 return;
2779
2780 get_text(description, text, sizeof(text));
2781
2782 ptr = strstr(text, "\n\n");
2783
2784 if (summary)
2785 {
2786 if (ptr)
2787 *ptr = '\0';
2788
2789 ptr = text;
2790 }
2791 else if (!ptr || !ptr[2])
2792 return;
2793 else
2794 ptr += 2;
2795
2796 if (element && *element)
2797 fprintf(out, "<%s class=\"%s\">", element,
2798 summary ? "description" : "discussion");
2799 else if (!summary)
2800 fputs(".PP\n", out);
2801
2802 for (col = 0; *ptr; ptr ++)
2803 {
2804 if (*ptr == '@' &&
2805 (!strncmp(ptr + 1, "deprecated@", 11) ||
2806 !strncmp(ptr + 1, "since ", 6)))
2807 {
2808 ptr ++;
2809 while (*ptr && *ptr != '@')
2810 ptr ++;
2811
2812 if (!*ptr)
2813 return;
2814 }
2815 else if (!strncmp(ptr, "@code ", 6))
2816 {
2817 for (ptr += 6; isspace(*ptr & 255); ptr ++);
2818
2819 for (start = ptr, ptr ++; *ptr && *ptr != '@'; ptr ++);
2820
2821 if (*ptr)
2822 *ptr = '\0';
2823 else
2824 ptr --;
2825
2826 if (element && *element)
2827 fprintf(out, "<code>%s</code>", start);
2828 else if (element)
2829 fputs(start, out);
2830 else
2831 fprintf(out, "\\fB%s\\fR", start);
2832 }
2833 else if (!strncmp(ptr, "@link ", 6))
2834 {
2835 for (ptr += 6; isspace(*ptr & 255); ptr ++);
2836
2837 for (start = ptr, ptr ++; *ptr && *ptr != '@'; ptr ++);
2838
2839 if (*ptr)
2840 *ptr = '\0';
2841 else
2842 ptr --;
2843
2844 if (element && *element)
2845 fprintf(out, "<a href=\"#%s\"><code>%s</code></a>", start, start);
2846 else if (element)
2847 fputs(start, out);
2848 else
2849 fprintf(out, "\\fI%s\\fR", start);
2850 }
2851 else if (element)
2852 {
2853 if (*ptr == '&')
2854 fputs("&amp;", out);
2855 else if (*ptr == '<')
2856 fputs("&lt;", out);
2857 else if (*ptr == '>')
2858 fputs("&gt;", out);
2859 else if (*ptr == '\"')
2860 fputs("&quot;", out);
2861 else if (*ptr & 128)
2862 {
2863 /*
2864 * Convert UTF-8 to Unicode constant...
2865 */
2866
2867 int ch; /* Unicode character */
2868
2869
2870 ch = *ptr & 255;
2871
2872 if ((ch & 0xe0) == 0xc0)
2873 {
2874 ch = ((ch & 0x1f) << 6) | (ptr[1] & 0x3f);
2875 ptr ++;
2876 }
2877 else if ((ch & 0xf0) == 0xe0)
2878 {
2879 ch = ((((ch * 0x0f) << 6) | (ptr[1] & 0x3f)) << 6) | (ptr[2] & 0x3f);
2880 ptr += 2;
2881 }
2882
2883 if (ch == 0xa0)
2884 {
2885 /*
2886 * Handle non-breaking space as-is...
2887 */
2888
2889 fputs("&nbsp;", out);
2890 }
2891 else
2892 fprintf(out, "&#x%x;", ch);
2893 }
2894 else if (*ptr == '\n' && ptr[1] == '\n' && ptr[2] && ptr[2] != '@')
2895 {
2896 fputs("<br>\n<br>\n", out);
2897 ptr ++;
2898 }
2899 else
2900 putc(*ptr, out);
2901 }
2902 else if (*ptr == '\n' && ptr[1] == '\n' && ptr[2] && ptr[2] != '@')
2903 {
2904 fputs("\n.PP\n", out);
2905 ptr ++;
2906 }
2907 else
2908 {
2909 if (*ptr == '\\' || (*ptr == '.' && col == 0))
2910 putc('\\', out);
2911
2912 putc(*ptr, out);
2913
2914 if (*ptr == '\n')
2915 col = 0;
2916 else
2917 col ++;
2918 }
2919 }
2920
2921 if (element && *element)
2922 fprintf(out, "</%s>\n", element);
2923 else if (!element)
2924 putc('\n', out);
2925}
2926
2927
2928/*
2929 * 'write_element()' - Write an element's text nodes.
2930 */
2931
2932static void
2933write_element(FILE *out, /* I - Output file */
2934 mxml_node_t *doc, /* I - Document tree */
2935 mxml_node_t *element, /* I - Element to write */
2936 int mode) /* I - Output mode */
2937{
2938 mxml_node_t *node; /* Current node */
2939
2940
2941 if (!element)
2942 return;
2943
2944 for (node = element->child;
2945 node;
2946 node = mxmlWalkNext(node, element, MXML_NO_DESCEND))
2947 if (node->type == MXML_TEXT)
2948 {
2949 if (node->value.text.whitespace)
2950 putc(' ', out);
2951
2952 if (mode == OUTPUT_HTML &&
2953 (mxmlFindElement(doc, doc, "class", "name", node->value.text.string,
2954 MXML_DESCEND) ||
2955 mxmlFindElement(doc, doc, "enumeration", "name",
2956 node->value.text.string, MXML_DESCEND) ||
2957 mxmlFindElement(doc, doc, "struct", "name", node->value.text.string,
2958 MXML_DESCEND) ||
2959 mxmlFindElement(doc, doc, "typedef", "name", node->value.text.string,
2960 MXML_DESCEND) ||
2961 mxmlFindElement(doc, doc, "union", "name", node->value.text.string,
2962 MXML_DESCEND)))
2963 {
2964 fputs("<a href=\"#", out);
2965 write_string(out, node->value.text.string, mode);
2966 fputs("\">", out);
2967 write_string(out, node->value.text.string, mode);
2968 fputs("</a>", out);
2969 }
2970 else
2971 write_string(out, node->value.text.string, mode);
2972 }
2973
2974 if (!strcmp(element->value.element.name, "type") &&
2975 element->last_child->value.text.string[0] != '*')
2976 putc(' ', out);
2977}
2978
2979
2980/*
2981 * 'write_file()' - Copy a file to the output.
2982 */
2983
2984static void
2985write_file(FILE *out, /* I - Output file */
2986 const char *file) /* I - File to copy */
2987{
2988 FILE *fp; /* Copy file */
2989 char line[8192]; /* Line from file */
2990
2991
2992 if ((fp = fopen(file, "r")) == NULL)
2993 {
2994 fprintf(stderr, "mxmldoc: Unable to open \"%s\": %s\n", file,
2995 strerror(errno));
2996 return;
2997 }
2998
2999 while (fgets(line, sizeof(line), fp))
3000 fputs(line, out);
3001
3002 fclose(fp);
3003}
3004
3005
3006/*
3007 * 'write_function()' - Write documentation for a function.
3008 */
3009
3010static void
3011write_function(FILE *out, /* I - Output file */
3012 mxml_node_t *doc, /* I - Document */
3013 mxml_node_t *function, /* I - Function */
3014 int level) /* I - Base heading level */
3015{
3016 mxml_node_t *arg, /* Current argument */
3017 *adesc, /* Description of argument */
3018 *description, /* Description of function */
3019 *type, /* Type for argument */
3020 *node; /* Node in description */
3021 const char *name, /* Name of function/type */
3022 *defval; /* Default value */
3023 char prefix; /* Prefix character */
3024 char *sep; /* Newline separator */
3025
3026
3027 name = mxmlElementGetAttr(function, "name");
3028 description = mxmlFindElement(function, function, "description", NULL,
3029 NULL, MXML_DESCEND_FIRST);
3030
3031 fprintf(out, "<h%d class=\"%s\">%s<a name=\"%s\">%s</a></h%d>\n",
3032 level, level == 3 ? "function" : "method",
3033 get_comment_info(description), name, name, level);
3034
3035 if (description)
3036 write_description(out, description, "p", 1);
3037
3038 fputs("<p class=\"code\">\n", out);
3039
3040 arg = mxmlFindElement(function, function, "returnvalue", NULL,
3041 NULL, MXML_DESCEND_FIRST);
3042
3043 if (arg)
3044 write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL,
3045 NULL, MXML_DESCEND_FIRST),
3046 OUTPUT_HTML);
3047 else
3048 fputs("void ", out);
3049
3050 fprintf(out, "%s ", name);
3051 for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
3052 MXML_DESCEND_FIRST), prefix = '(';
3053 arg;
3054 arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
3055 MXML_NO_DESCEND), prefix = ',')
3056 {
3057 type = mxmlFindElement(arg, arg, "type", NULL, NULL,
3058 MXML_DESCEND_FIRST);
3059
3060 fprintf(out, "%c<br>\n&nbsp;&nbsp;&nbsp;&nbsp;", prefix);
3061 if (type->child)
3062 write_element(out, doc, type, OUTPUT_HTML);
3063
3064 fputs(mxmlElementGetAttr(arg, "name"), out);
3065 if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
3066 fprintf(out, " %s", defval);
3067 }
3068
3069 if (prefix == '(')
3070 fputs("(void);</p>\n", out);
3071 else
3072 {
3073 fprintf(out,
3074 "<br>\n);</p>\n"
3075 "<h%d class=\"parameters\">Parameters</h%d>\n"
3076 "<dl>\n", level + 1, level + 1);
3077
3078 for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
3079 MXML_DESCEND_FIRST);
3080 arg;
3081 arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
3082 MXML_NO_DESCEND))
3083 {
3084 fprintf(out, "<dt>%s</dt>\n", mxmlElementGetAttr(arg, "name"));
3085
3086 adesc = mxmlFindElement(arg, arg, "description", NULL, NULL,
3087 MXML_DESCEND_FIRST);
3088
3089 write_description(out, adesc, "dd", 1);
3090 write_description(out, adesc, "dd", 0);
3091 }
3092
3093 fputs("</dl>\n", out);
3094 }
3095
3096 arg = mxmlFindElement(function, function, "returnvalue", NULL,
3097 NULL, MXML_DESCEND_FIRST);
3098
3099 if (arg)
3100 {
3101 fprintf(out, "<h%d class=\"returnvalue\">Return Value</h%d>\n", level + 1,
3102 level + 1);
3103
3104 adesc = mxmlFindElement(arg, arg, "description", NULL, NULL,
3105 MXML_DESCEND_FIRST);
3106
3107 write_description(out, adesc, "p", 1);
3108 write_description(out, adesc, "p", 0);
3109 }
3110
3111 if (description)
3112 {
3113 for (node = description->child; node; node = node->next)
3114 if (node->value.text.string &&
3115 (sep = strstr(node->value.text.string, "\n\n")) != NULL)
3116 {
3117 sep += 2;
3118 if (*sep && strncmp(sep, "@since ", 7) &&
3119 strncmp(sep, "@deprecated@", 12))
3120 break;
3121 }
3122
3123 if (node)
3124 {
3125 fprintf(out, "<h%d class=\"discussion\">Discussion</h%d>\n", level + 1,
3126 level + 1);
3127 write_description(out, description, "p", 0);
3128 }
3129 }
3130}
3131
3132
3133/*
3134 * 'write_html()' - Write HTML documentation.
3135 */
3136
3137static void
3138write_html(const char *section, /* I - Section */
3139 const char *title, /* I - Title */
3140 const char *footerfile, /* I - Footer file */
3141 const char *headerfile, /* I - Header file */
3142 const char *introfile, /* I - Intro file */
3143 const char *cssfile, /* I - Stylesheet file */
3144 const char *framefile, /* I - Framed HTML basename */
3145 const char *docset, /* I - Documentation set directory */
3146 const char *docversion, /* I - Documentation set version */
3147 const char *feedname, /* I - Feed name for doc set */
3148 const char *feedurl, /* I - Feed URL for doc set */
3149 mxml_node_t *doc) /* I - XML documentation */
3150{
3151 FILE *out; /* Output file */
3152 mxml_node_t *function, /* Current function */
3153 *scut, /* Struct/class/union/typedef */
3154 *arg, /* Current argument */
3155 *description, /* Description of function/var */
3156 *type; /* Type for argument */
3157 const char *name, /* Name of function/type */
3158 *defval, /* Default value */
3159 *basename; /* Base filename for framed output */
3160 char filename[1024]; /* Current output filename */
3161
3162
3163 if (framefile)
3164 {
3165 /*
3166 * Get the basename of the frame file...
3167 */
3168
3169 if ((basename = strrchr(framefile, '/')) != NULL)
3170 basename ++;
3171 else
3172 basename = framefile;
3173
3174 if (strstr(basename, ".html"))
3175 fputs("mxmldoc: Frame base name should not contain .html extension!\n",
3176 stderr);
3177
3178 /*
3179 * Create the container HTML file for the frames...
3180 */
3181
3182 snprintf(filename, sizeof(filename), "%s.html", framefile);
3183
3184 if ((out = fopen(filename, "w")) == NULL)
3185 {
3186 fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename,
3187 strerror(errno));
3188 return;
3189 }
3190
3191 fputs("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\" "
3192 "\"http://www.w3.org/TR/html4/frameset.dtd\">\n"
3193 "<html>\n"
3194 "<head>\n"
3195 "\t<title>", out);
3196 write_string(out, title, OUTPUT_HTML);
3197 fputs("</title>\n", out);
3198
3199 if (section)
3200 fprintf(out, "\t<meta name=\"keywords\" content=\"%s\">\n", section);
3201
3202 fputs("\t<meta http-equiv=\"Content-Type\" "
3203 "content=\"text/html;charset=utf-8\">\n"
3204 "\t<meta name=\"creator\" content=\"" MXML_VERSION "\">\n"
3205 "</head>\n", out);
3206
3207 fputs("<frameset cols=\"250,*\">\n", out);
3208 fprintf(out, "<frame src=\"%s-toc.html\">\n", basename);
3209 fprintf(out, "<frame name=\"body\" src=\"%s-body.html\">\n", basename);
3210 fputs("</frameset>\n"
3211 "<noframes>\n"
3212 "<h1>", out);
3213 write_string(out, title, OUTPUT_HTML);
3214 fprintf(out,
3215 "</h1>\n"
3216 "<ul>\n"
3217 "\t<li><a href=\"%s-toc.html\">Table of Contents</a></li>\n"
3218 "\t<li><a href=\"%s-body.html\">Body</a></li>\n"
3219 "</ul>\n", basename, basename);
3220 fputs("</noframes>\n"
3221 "</html>\n", out);
3222 fclose(out);
3223
3224 /*
3225 * Write the table-of-contents file...
3226 */
3227
3228 snprintf(filename, sizeof(filename), "%s-toc.html", framefile);
3229
3230 if ((out = fopen(filename, "w")) == NULL)
3231 {
3232 fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename,
3233 strerror(errno));
3234 return;
3235 }
3236
3237 write_html_head(out, section, title, cssfile);
3238
3239 snprintf(filename, sizeof(filename), "%s-body.html", basename);
3240
3241 fputs("<div class=\"contents\">\n", out);
3242 fprintf(out, "<h1 class=\"title\"><a href=\"%s\" target=\"body\">",
3243 filename);
3244 write_string(out, title, OUTPUT_HTML);
3245 fputs("</a></h1>\n", out);
3246
3247 write_toc(out, doc, introfile, filename, 0);
3248
3249 fputs("</div>\n"
3250 "</body>\n"
3251 "</html>\n", out);
3252 fclose(out);
3253
3254 /*
3255 * Finally, open the body file...
3256 */
3257
3258 snprintf(filename, sizeof(filename), "%s-body.html", framefile);
3259
3260 if ((out = fopen(filename, "w")) == NULL)
3261 {
3262 fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename,
3263 strerror(errno));
3264 return;
3265 }
3266 }
3267 else if (docset)
3268 {
3269 /*
3270 * Create an Xcode documentation set - start by removing any existing
3271 * output directory...
3272 */
3273
3274#ifdef __APPLE__
3275 const char *id; /* Identifier */
3276
3277
3278 if (!access(docset, 0) && !remove_directory(docset))
3279 return;
3280
3281 /*
3282 * Then make the Apple standard bundle directory structure...
3283 */
3284
3285 if (mkdir(docset, 0755))
3286 {
3287 fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", docset,
3288 strerror(errno));
3289 return;
3290 }
3291
3292 snprintf(filename, sizeof(filename), "%s/Contents", docset);
3293 if (mkdir(filename, 0755))
3294 {
3295 fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename,
3296 strerror(errno));
3297 return;
3298 }
3299
3300 snprintf(filename, sizeof(filename), "%s/Contents/Resources", docset);
3301 if (mkdir(filename, 0755))
3302 {
3303 fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename,
3304 strerror(errno));
3305 return;
3306 }
3307
3308 snprintf(filename, sizeof(filename), "%s/Contents/Resources/Documentation",
3309 docset);
3310 if (mkdir(filename, 0755))
3311 {
3312 fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename,
3313 strerror(errno));
3314 return;
3315 }
3316
3317 /*
3318 * The Info.plist file, which describes the documentation set...
3319 */
3320
3321 if ((id = strrchr(docset, '/')) != NULL)
3322 id ++;
3323 else
3324 id = docset;
3325
3326 snprintf(filename, sizeof(filename), "%s/Contents/Info.plist", docset);
3327 if ((out = fopen(filename, "w")) == NULL)
3328 {
3329 fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename,
3330 strerror(errno));
3331 return;
3332 }
3333
3334 fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
3335 "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
3336 "<plist version=\"1.0\">\n"
3337 "<dict>\n"
3338 "\t<key>CFBundleIdentifier</key>\n"
3339 "\t<string>", out);
3340 write_string(out, id, OUTPUT_HTML);
3341 fputs("</string>\n"
3342 "\t<key>CFBundleName</key>\n"
3343 "\t<string>", out);
3344 write_string(out, title, OUTPUT_HTML);
3345 fputs("</string>\n"
3346 "\t<key>CFBundleVersion</key>\n"
3347 "\t<string>", out);
3348 write_string(out, docversion ? docversion : "0.0", OUTPUT_HTML);
3349 fputs("</string>\n"
3350 "\t<key>CFBundleShortVersionString</key>\n"
3351 "\t<string>", out);
3352 write_string(out, docversion ? docversion : "0.0", OUTPUT_HTML);
3353 fputs("</string>\n", out);
3354
3355 if (feedname)
3356 {
3357 fputs("\t<key>DocSetFeedName</key>\n"
3358 "\t<string>", out);
3359 write_string(out, feedname ? feedname : title, OUTPUT_HTML);
3360 fputs("</string>\n", out);
3361 }
3362
3363 if (feedurl)
3364 {
3365 fputs("\t<key>DocSetFeedURL</key>\n"
3366 "\t<string>", out);
3367 write_string(out, feedurl, OUTPUT_HTML);
3368 fputs("</string>\n", out);
3369 }
3370
3371 fputs("</dict>\n"
3372 "</plist>\n", out);
3373
3374 fclose(out);
3375
3376 /*
3377 * Next the Nodes.xml file...
3378 */
3379
3380 snprintf(filename, sizeof(filename), "%s/Contents/Resources/Nodes.xml",
3381 docset);
3382 if ((out = fopen(filename, "w")) == NULL)
3383 {
3384 fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename,
3385 strerror(errno));
3386 return;
3387 }
3388
3389 fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
3390 "<DocSetNodes version=\"1.0\">\n"
3391 "<TOC>\n"
3392 "<Node id=\"0\">\n"
3393 "<Name>", out);
3394 write_string(out, title, OUTPUT_HTML);
3395 fputs("</Name>\n"
3396 "<Path>Documentation/index.html</Path>\n"
3397 "<Subnodes>\n", out);
3398
3399 write_toc(out, doc, introfile, NULL, 1);
3400
3401 fputs("</Subnodes>\n"
3402 "</Node>\n"
3403 "</TOC>\n"
3404 "</DocSetNodes>\n", out);
3405
3406 fclose(out);
3407
3408 /*
3409 * Then the Tokens.xml file...
3410 */
3411
3412 snprintf(filename, sizeof(filename), "%s/Contents/Resources/Tokens.xml",
3413 docset);
3414 if ((out = fopen(filename, "w")) == NULL)
3415 {
3416 fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename,
3417 strerror(errno));
3418 return;
3419 }
3420
3421 fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
3422 "<Tokens version=\"1.0\">\n", out);
3423
3424 write_tokens(out, doc, "index.html");
3425
3426 fputs("</Tokens>\n", out);
3427
3428 fclose(out);
3429
3430 /*
3431 * Finally the HTML file...
3432 */
3433
3434 snprintf(filename, sizeof(filename),
3435 "%s/Contents/Resources/Documentation/index.html",
3436 docset);
3437 if ((out = fopen(filename, "w")) == NULL)
3438 {
3439 fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename,
3440 strerror(errno));
3441 return;
3442 }
3443
3444#else
3445 fputs("mxmldoc: Xcode documentation sets can only be created on "
3446 "Mac OS X.\n", stderr);
3447 return;
3448#endif /* __APPLE__ */
3449 }
3450 else
3451 out = stdout;
3452
3453 /*
3454 * Standard header...
3455 */
3456
3457 write_html_head(out, section, title, cssfile);
3458
3459 fputs("<div class='body'>\n", out);
3460
3461 /*
3462 * Header...
3463 */
3464
3465 if (headerfile)
3466 {
3467 /*
3468 * Use custom header...
3469 */
3470
3471 write_file(out, headerfile);
3472 }
3473 else
3474 {
3475 /*
3476 * Use standard header...
3477 */
3478
3479 fputs("<h1 class=\"title\">", out);
3480 write_string(out, title, OUTPUT_HTML);
3481 fputs("</h1>\n", out);
3482 }
3483
3484 /*
3485 * Table of contents...
3486 */
3487
3488 if (!framefile)
3489 write_toc(out, doc, introfile, NULL, 0);
3490
3491 /*
3492 * Intro...
3493 */
3494
3495 if (introfile)
3496 write_file(out, introfile);
3497
3498 /*
3499 * List of classes...
3500 */
3501
3502 if ((scut = find_public(doc, doc, "class")) != NULL)
3503 {
3504 fputs("<h2 class=\"title\"><a name=\"CLASSES\">Classes</a></h2>\n", out);
3505
3506 while (scut)
3507 {
3508 write_scu(out, doc, scut);
3509
3510 scut = find_public(scut, doc, "class");
3511 }
3512 }
3513
3514 /*
3515 * List of functions...
3516 */
3517
3518 if ((function = find_public(doc, doc, "function")) != NULL)
3519 {
3520 fputs("<h2 class=\"title\"><a name=\"FUNCTIONS\">Functions</a></h2>\n", out);
3521
3522 while (function)
3523 {
3524 write_function(out, doc, function, 3);
3525
3526 function = find_public(function, doc, "function");
3527 }
3528 }
3529
3530 /*
3531 * List of types...
3532 */
3533
3534 if ((scut = find_public(doc, doc, "typedef")) != NULL)
3535 {
3536 fputs("<h2 class=\"title\"><a name=\"TYPES\">Data Types</a></h2>\n", out);
3537
3538 while (scut)
3539 {
3540 name = mxmlElementGetAttr(scut, "name");
3541 description = mxmlFindElement(scut, scut, "description", NULL,
3542 NULL, MXML_DESCEND_FIRST);
3543 fprintf(out, "<h3 class=\"typedef\">%s<a name=\"%s\">%s</a></h3>\n",
3544 get_comment_info(description), name, name);
3545
3546 if (description)
3547 write_description(out, description, "p", 1);
3548
3549 fputs("<p class=\"code\">\n"
3550 "typedef ", out);
3551
3552 type = mxmlFindElement(scut, scut, "type", NULL, NULL,
3553 MXML_DESCEND_FIRST);
3554
3555 for (type = type->child; type; type = type->next)
3556 if (!strcmp(type->value.text.string, "("))
3557 break;
3558 else
3559 {
3560 if (type->value.text.whitespace)
3561 putc(' ', out);
3562
3563 if (mxmlFindElement(doc, doc, "class", "name",
3564 type->value.text.string, MXML_DESCEND) ||
3565 mxmlFindElement(doc, doc, "enumeration", "name",
3566 type->value.text.string, MXML_DESCEND) ||
3567 mxmlFindElement(doc, doc, "struct", "name",
3568 type->value.text.string, MXML_DESCEND) ||
3569 mxmlFindElement(doc, doc, "typedef", "name",
3570 type->value.text.string, MXML_DESCEND) ||
3571 mxmlFindElement(doc, doc, "union", "name",
3572 type->value.text.string, MXML_DESCEND))
3573 {
3574 fputs("<a href=\"#", out);
3575 write_string(out, type->value.text.string, OUTPUT_HTML);
3576 fputs("\">", out);
3577 write_string(out, type->value.text.string, OUTPUT_HTML);
3578 fputs("</a>", out);
3579 }
3580 else
3581 write_string(out, type->value.text.string, OUTPUT_HTML);
3582 }
3583
3584 if (type)
3585 {
3586 /*
3587 * Output function type...
3588 */
3589
3590 if (type->prev && type->prev->value.text.string[0] != '*')
3591 putc(' ', out);
3592
3593 fprintf(out, "(*%s", name);
3594
3595 for (type = type->next->next; type; type = type->next)
3596 {
3597 if (type->value.text.whitespace)
3598 putc(' ', out);
3599
3600 if (mxmlFindElement(doc, doc, "class", "name",
3601 type->value.text.string, MXML_DESCEND) ||
3602 mxmlFindElement(doc, doc, "enumeration", "name",
3603 type->value.text.string, MXML_DESCEND) ||
3604 mxmlFindElement(doc, doc, "struct", "name",
3605 type->value.text.string, MXML_DESCEND) ||
3606 mxmlFindElement(doc, doc, "typedef", "name",
3607 type->value.text.string, MXML_DESCEND) ||
3608 mxmlFindElement(doc, doc, "union", "name",
3609 type->value.text.string, MXML_DESCEND))
3610 {
3611 fputs("<a href=\"#", out);
3612 write_string(out, type->value.text.string, OUTPUT_HTML);
3613 fputs("\">", out);
3614 write_string(out, type->value.text.string, OUTPUT_HTML);
3615 fputs("</a>", out);
3616 }
3617 else
3618 write_string(out, type->value.text.string, OUTPUT_HTML);
3619 }
3620
3621 fputs(";\n", out);
3622 }
3623 else
3624 {
3625 type = mxmlFindElement(scut, scut, "type", NULL, NULL,
3626 MXML_DESCEND_FIRST);
3627 if (type->last_child->value.text.string[0] != '*')
3628 putc(' ', out);
3629
3630 fprintf(out, "%s;\n", name);
3631 }
3632
3633 fputs("</p>\n", out);
3634
3635 scut = find_public(scut, doc, "typedef");
3636 }
3637 }
3638
3639 /*
3640 * List of structures...
3641 */
3642
3643 if ((scut = find_public(doc, doc, "struct")) != NULL)
3644 {
3645 fputs("<h2 class=\"title\"><a name=\"STRUCTURES\">Structures</a></h2>\n",
3646 out);
3647
3648 while (scut)
3649 {
3650 write_scu(out, doc, scut);
3651
3652 scut = find_public(scut, doc, "struct");
3653 }
3654 }
3655
3656 /*
3657 * List of unions...
3658 */
3659
3660 if ((scut = find_public(doc, doc, "union")) != NULL)
3661 {
3662 fputs("<h2 class=\"title\"><a name=\"UNIONS\">Unions</a></h2>\n", out);
3663
3664 while (scut)
3665 {
3666 write_scu(out, doc, scut);
3667
3668 scut = find_public(scut, doc, "union");
3669 }
3670 }
3671
3672 /*
3673 * Variables...
3674 */
3675
3676 if ((arg = find_public(doc, doc, "variable")) != NULL)
3677 {
3678 fputs("<h2 class=\"title\"><a name=\"VARIABLES\">Variables</a></h2>\n",
3679 out);
3680
3681 while (arg)
3682 {
3683 name = mxmlElementGetAttr(arg, "name");
3684 description = mxmlFindElement(arg, arg, "description", NULL,
3685 NULL, MXML_DESCEND_FIRST);
3686 fprintf(out, "<h3 class=\"variable\">%s<a name=\"%s\">%s</a></h3>\n",
3687 get_comment_info(description), name, name);
3688
3689 if (description)
3690 write_description(out, description, "p", 1);
3691
3692 fputs("<p class=\"code\">", out);
3693
3694 write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL,
3695 NULL, MXML_DESCEND_FIRST),
3696 OUTPUT_HTML);
3697 fputs(mxmlElementGetAttr(arg, "name"), out);
3698 if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
3699 fprintf(out, " %s", defval);
3700 fputs(";</p>\n", out);
3701
3702 arg = find_public(arg, doc, "variable");
3703 }
3704 }
3705
3706 /*
3707 * List of enumerations...
3708 */
3709
3710 if ((scut = find_public(doc, doc, "enumeration")) != NULL)
3711 {
3712 fputs("<h2 class=\"title\"><a name=\"ENUMERATIONS\">Constants</a></h2>\n",
3713 out);
3714
3715 while (scut)
3716 {
3717 name = mxmlElementGetAttr(scut, "name");
3718 description = mxmlFindElement(scut, scut, "description", NULL,
3719 NULL, MXML_DESCEND_FIRST);
3720 fprintf(out, "<h3 class=\"enumeration\">%s<a name=\"%s\">%s</a></h3>\n",
3721 get_comment_info(description), name, name);
3722
3723 if (description)
3724 write_description(out, description, "p", 1);
3725
3726 fputs("<h4 class=\"constants\">Constants</h4>\n"
3727 "<dl>\n", out);
3728
3729 for (arg = mxmlFindElement(scut, scut, "constant", NULL, NULL,
3730 MXML_DESCEND_FIRST);
3731 arg;
3732 arg = mxmlFindElement(arg, scut, "constant", NULL, NULL,
3733 MXML_NO_DESCEND))
3734 {
3735 description = mxmlFindElement(arg, arg, "description", NULL,
3736 NULL, MXML_DESCEND_FIRST);
3737 fprintf(out, "<dt>%s %s</dt>\n",
3738 mxmlElementGetAttr(arg, "name"), get_comment_info(description));
3739
3740 write_description(out, description, "dd", 1);
3741 write_description(out, description, "dd", 0);
3742 }
3743
3744 fputs("</dl>\n", out);
3745
3746 scut = find_public(scut, doc, "enumeration");
3747 }
3748 }
3749
3750 /*
3751 * Footer...
3752 */
3753
3754 if (footerfile)
3755 {
3756 /*
3757 * Use custom footer...
3758 */
3759
3760 write_file(out, footerfile);
3761 }
3762
3763 fputs("</div>\n"
3764 "</body>\n"
3765 "</html>\n", out);
3766
3767 /*
3768 * Close output file as needed...
3769 */
3770
3771 if (out != stdout)
3772 fclose(out);
3773
3774#ifdef __APPLE__
3775 /*
3776 * When generating document sets, run the docsetutil program to index it...
3777 */
3778
3779 if (docset)
3780 {
3781 const char *args[4]; /* Argument array */
3782 pid_t pid; /* Process ID */
3783 int status; /* Exit status */
3784
3785
3786 args[0] = "/Developer/usr/bin/docsetutil";
3787 args[1] = "index";
3788 args[2] = docset;
3789 args[3] = NULL;
3790
3791 if (posix_spawn(&pid, args[0], NULL, NULL, (char **)args, environ))
3792 {
3793 fprintf(stderr, "mxmldoc: Unable to index documentation set \"%s\": %s\n",
3794 docset, strerror(errno));
3795 }
3796 else
3797 {
3798 while (wait(&status) != pid);
3799
3800 if (status)
3801 {
3802 if (WIFEXITED(status))
3803 fprintf(stderr, "mxmldoc: docsetutil exited with status %d\n",
3804 WEXITSTATUS(status));
3805 else
3806 fprintf(stderr, "mxmldoc: docsetutil crashed with signal %d\n",
3807 WTERMSIG(status));
3808 }
3809 else
3810 {
3811 /*
3812 * Remove unneeded temporary XML files...
3813 */
3814
3815 snprintf(filename, sizeof(filename), "%s/Contents/Resources/Nodes.xml",
3816 docset);
3817 unlink(filename);
3818
3819 snprintf(filename, sizeof(filename), "%s/Contents/Resources/Tokens.xml",
3820 docset);
3821 unlink(filename);
3822 }
3823 }
3824 }
3825#endif /* __APPLE__ */
3826}
3827
3828
3829/*
3830 * 'write_html_head()' - Write the standard HTML header.
3831 */
3832
3833static void
3834write_html_head(FILE *out, /* I - Output file */
3835 const char *section, /* I - Section */
3836 const char *title, /* I - Title */
3837 const char *cssfile) /* I - Stylesheet */
3838{
3839 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" "
3840 "\"http://www.w3.org/TR/html4/loose.dtd\">\n"
3841 "<html>\n", out);
3842
3843 if (section)
3844 fprintf(out, "<!-- SECTION: %s -->\n", section);
3845
3846 fputs("<head>\n"
3847 "\t<title>", out);
3848 write_string(out, title, OUTPUT_HTML);
3849 fputs("\t</title>\n", out);
3850
3851 if (section)
3852 fprintf(out, "\t<meta name=\"keywords\" content=\"%s\">\n", section);
3853
3854 fputs("\t<meta http-equiv=\"Content-Type\" "
3855 "content=\"text/html;charset=utf-8\">\n"
3856 "\t<meta name=\"creator\" content=\"" MXML_VERSION "\">\n"
3857 "<style type=\"text/css\"><!--\n", out);
3858
3859 if (cssfile)
3860 {
3861 /*
3862 * Use custom stylesheet file...
3863 */
3864
3865 write_file(out, cssfile);
3866 }
3867 else
3868 {
3869 /*
3870 * Use standard stylesheet...
3871 */
3872
3873 fputs("body, p, h1, h2, h3, h4 {\n"
3874 " font-family: \"lucida grande\", geneva, helvetica, arial, "
3875 "sans-serif;\n"
3876 "}\n"
3877 "div.body h1 {\n"
3878 " font-size: 250%;\n"
3879 " font-weight: bold;\n"
3880 " margin: 0;\n"
3881 "}\n"
3882 "div.body h2 {\n"
3883 " font-size: 250%;\n"
3884 " margin-top: 1.5em;\n"
3885 "}\n"
3886 "div.body h3 {\n"
3887 " font-size: 150%;\n"
3888 " margin-bottom: 0.5em;\n"
3889 " margin-top: 1.5em;\n"
3890 "}\n"
3891 "div.body h4 {\n"
3892 " font-size: 110%;\n"
3893 " margin-bottom: 0.5em;\n"
3894 " margin-top: 1.5em;\n"
3895 "}\n"
3896 "div.body h5 {\n"
3897 " font-size: 100%;\n"
3898 " margin-bottom: 0.5em;\n"
3899 " margin-top: 1.5em;\n"
3900 "}\n"
3901 "div.contents {\n"
3902 " background: #e8e8e8;\n"
3903 " border: solid thin black;\n"
3904 " padding: 10px;\n"
3905 "}\n"
3906 "div.contents h1 {\n"
3907 " font-size: 110%;\n"
3908 "}\n"
3909 "div.contents h2 {\n"
3910 " font-size: 100%;\n"
3911 "}\n"
3912 "div.contents ul.contents {\n"
3913 " font-size: 80%;\n"
3914 "}\n"
3915 ".class {\n"
3916 " border-bottom: solid 2px gray;\n"
3917 "}\n"
3918 ".constants {\n"
3919 "}\n"
3920 ".description {\n"
3921 " margin-top: 0.5em;\n"
3922 "}\n"
3923 ".discussion {\n"
3924 "}\n"
3925 ".enumeration {\n"
3926 " border-bottom: solid 2px gray;\n"
3927 "}\n"
3928 ".function {\n"
3929 " border-bottom: solid 2px gray;\n"
3930 " margin-bottom: 0;\n"
3931 "}\n"
3932 ".members {\n"
3933 "}\n"
3934 ".method {\n"
3935 "}\n"
3936 ".parameters {\n"
3937 "}\n"
3938 ".returnvalue {\n"
3939 "}\n"
3940 ".struct {\n"
3941 " border-bottom: solid 2px gray;\n"
3942 "}\n"
3943 ".typedef {\n"
3944 " border-bottom: solid 2px gray;\n"
3945 "}\n"
3946 ".union {\n"
3947 " border-bottom: solid 2px gray;\n"
3948 "}\n"
3949 ".variable {\n"
3950 "}\n"
3951 "code, p.code, pre, ul.code li {\n"
3952 " font-family: monaco, courier, monospace;\n"
3953 " font-size: 90%;\n"
3954 "}\n"
3955 "a:link, a:visited {\n"
3956 " text-decoration: none;\n"
3957 "}\n"
3958 "span.info {\n"
3959 " background: black;\n"
3960 " border: solid thin black;\n"
3961 " color: white;\n"
3962 " font-size: 80%;\n"
3963 " font-style: italic;\n"
3964 " font-weight: bold;\n"
3965 " white-space: nowrap;\n"
3966 "}\n"
3967 "h3 span.info, h4 span.info {\n"
3968 " float: right;\n"
3969 " font-size: 100%;\n"
3970 "}\n"
3971 "ul.code, ul.contents, ul.subcontents {\n"
3972 " list-style-type: none;\n"
3973 " margin: 0;\n"
3974 " padding-left: 0;\n"
3975 "}\n"
3976 "ul.code li {\n"
3977 " margin: 0;\n"
3978 "}\n"
3979 "ul.contents > li {\n"
3980 " margin-top: 1em;\n"
3981 "}\n"
3982 "ul.contents li ul.code, ul.contents li ul.subcontents {\n"
3983 " padding-left: 2em;\n"
3984 "}\n"
3985 "div.body dl {\n"
3986 " margin-top: 0;\n"
3987 "}\n"
3988 "div.body dt {\n"
3989 " font-style: italic;\n"
3990 " margin-top: 0;\n"
3991 "}\n"
3992 "div.body dd {\n"
3993 " margin-bottom: 0.5em;\n"
3994 "}\n"
3995 "h1.title {\n"
3996 "}\n"
3997 "h2.title {\n"
3998 " border-bottom: solid 2px black;\n"
3999 "}\n"
4000 "h3.title {\n"
4001 " border-bottom: solid 2px black;\n"
4002 "}\n", out);
4003 }
4004
4005 fputs("--></style>\n"
4006 "</head>\n"
4007 "<body>\n", out);
4008}
4009
4010
4011/*
4012 * 'write_man()' - Write manpage documentation.
4013 */
4014
4015static void
4016write_man(const char *man_name, /* I - Name of manpage */
4017 const char *section, /* I - Section */
4018 const char *title, /* I - Title */
4019 const char *footerfile, /* I - Footer file */
4020 const char *headerfile, /* I - Header file */
4021 const char *introfile, /* I - Intro file */
4022 mxml_node_t *doc) /* I - XML documentation */
4023{
4024 int i; /* Looping var */
4025 mxml_node_t *function, /* Current function */
4026 *scut, /* Struct/class/union/typedef */
4027 *arg, /* Current argument */
4028 *description, /* Description of function/var */
4029 *type; /* Type for argument */
4030 const char *name, /* Name of function/type */
4031 *cname, /* Class name */
4032 *defval, /* Default value */
4033 *parent; /* Parent class */
4034 int inscope; /* Variable/method scope */
4035 char prefix; /* Prefix character */
4036 time_t curtime; /* Current time */
4037 struct tm *curdate; /* Current date */
4038 char buffer[1024]; /* String buffer */
4039 static const char * const scopes[] = /* Scope strings */
4040 {
4041 "private",
4042 "protected",
4043 "public"
4044 };
4045
4046
4047 /*
4048 * Standard man page...
4049 */
4050
4051 curtime = time(NULL);
4052 curdate = localtime(&curtime);
4053 strftime(buffer, sizeof(buffer), "%x", curdate);
4054
4055 printf(".TH %s %s \"%s\" \"%s\" \"%s\"\n", man_name, section ? section : "3",
4056 title ? title : "", buffer, title ? title : "");
4057
4058 /*
4059 * Header...
4060 */
4061
4062 if (headerfile)
4063 {
4064 /*
4065 * Use custom header...
4066 */
4067
4068 write_file(stdout, headerfile);
4069 }
4070 else
4071 {
4072 /*
4073 * Use standard header...
4074 */
4075
4076 puts(".SH NAME");
4077 printf("%s \\- %s\n", man_name, title ? title : man_name);
4078 }
4079
4080 /*
4081 * Intro...
4082 */
4083
4084 if (introfile)
4085 write_file(stdout, introfile);
4086
4087 /*
4088 * List of classes...
4089 */
4090
4091 if (find_public(doc, doc, "class"))
4092 {
4093 puts(".SH CLASSES");
4094
4095 for (scut = find_public(doc, doc, "class");
4096 scut;
4097 scut = find_public(scut, doc, "class"))
4098 {
4099 cname = mxmlElementGetAttr(scut, "name");
4100 description = mxmlFindElement(scut, scut, "description", NULL,
4101 NULL, MXML_DESCEND_FIRST);
4102 printf(".SS %s\n", cname);
4103
4104 write_description(stdout, description, NULL, 1);
4105
4106 printf(".PP\n"
4107 ".nf\n"
4108 "class %s", cname);
4109 if ((parent = mxmlElementGetAttr(scut, "parent")) != NULL)
4110 printf(" %s", parent);
4111 puts("\n{");
4112
4113 for (i = 0; i < 3; i ++)
4114 {
4115 inscope = 0;
4116
4117 for (arg = mxmlFindElement(scut, scut, "variable", "scope", scopes[i],
4118 MXML_DESCEND_FIRST);
4119 arg;
4120 arg = mxmlFindElement(arg, scut, "variable", "scope", scopes[i],
4121 MXML_NO_DESCEND))
4122 {
4123 if (!inscope)
4124 {
4125 inscope = 1;
4126 printf(" %s:\n", scopes[i]);
4127 }
4128
4129 printf(" ");
4130 write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL,
4131 NULL, MXML_DESCEND_FIRST),
4132 OUTPUT_MAN);
4133 printf("%s;\n", mxmlElementGetAttr(arg, "name"));
4134 }
4135
4136 for (function = mxmlFindElement(scut, scut, "function", "scope",
4137 scopes[i], MXML_DESCEND_FIRST);
4138 function;
4139 function = mxmlFindElement(function, scut, "function", "scope",
4140 scopes[i], MXML_NO_DESCEND))
4141 {
4142 if (!inscope)
4143 {
4144 inscope = 1;
4145 printf(" %s:\n", scopes[i]);
4146 }
4147
4148 name = mxmlElementGetAttr(function, "name");
4149
4150 printf(" ");
4151
4152 arg = mxmlFindElement(function, function, "returnvalue", NULL,
4153 NULL, MXML_DESCEND_FIRST);
4154
4155 if (arg)
4156 write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL,
4157 NULL, MXML_DESCEND_FIRST),
4158 OUTPUT_MAN);
4159 else if (strcmp(cname, name) && strcmp(cname, name + 1))
4160 fputs("void ", stdout);
4161
4162 printf("%s", name);
4163
4164 for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
4165 MXML_DESCEND_FIRST), prefix = '(';
4166 arg;
4167 arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
4168 MXML_NO_DESCEND), prefix = ',')
4169 {
4170 type = mxmlFindElement(arg, arg, "type", NULL, NULL,
4171 MXML_DESCEND_FIRST);
4172
4173 putchar(prefix);
4174 if (prefix == ',')
4175 putchar(' ');
4176
4177 if (type->child)
4178 write_element(stdout, doc, type, OUTPUT_MAN);
4179 fputs(mxmlElementGetAttr(arg, "name"), stdout);
4180 if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
4181 printf(" %s", defval);
4182 }
4183
4184 if (prefix == '(')
4185 puts("(void);");
4186 else
4187 puts(");");
4188 }
4189 }
4190
4191 puts("};\n"
4192 ".fi");
4193
4194 write_description(stdout, description, NULL, 0);
4195 }
4196 }
4197
4198 /*
4199 * List of enumerations...
4200 */
4201
4202 if (find_public(doc, doc, "enumeration"))
4203 {
4204 puts(".SH ENUMERATIONS");
4205
4206 for (scut = find_public(doc, doc, "enumeration");
4207 scut;
4208 scut = find_public(scut, doc, "enumeration"))
4209 {
4210 name = mxmlElementGetAttr(scut, "name");
4211 description = mxmlFindElement(scut, scut, "description", NULL,
4212 NULL, MXML_DESCEND_FIRST);
4213 printf(".SS %s\n", name);
4214
4215 write_description(stdout, description, NULL, 1);
4216 write_description(stdout, description, NULL, 0);
4217
4218 for (arg = mxmlFindElement(scut, scut, "constant", NULL, NULL,
4219 MXML_DESCEND_FIRST);
4220 arg;
4221 arg = mxmlFindElement(arg, scut, "constant", NULL, NULL,
4222 MXML_NO_DESCEND))
4223 {
4224 description = mxmlFindElement(arg, arg, "description", NULL,
4225 NULL, MXML_DESCEND_FIRST);
4226 printf(".TP 5\n%s\n.br\n", mxmlElementGetAttr(arg, "name"));
4227 write_description(stdout, description, NULL, 1);
4228 }
4229 }
4230 }
4231
4232 /*
4233 * List of functions...
4234 */
4235
4236 if (find_public(doc, doc, "function"))
4237 {
4238 puts(".SH FUNCTIONS");
4239
4240 for (function = find_public(doc, doc, "function");
4241 function;
4242 function = find_public(function, doc, "function"))
4243 {
4244 name = mxmlElementGetAttr(function, "name");
4245 description = mxmlFindElement(function, function, "description", NULL,
4246 NULL, MXML_DESCEND_FIRST);
4247 printf(".SS %s\n", name);
4248
4249 write_description(stdout, description, NULL, 1);
4250
4251 puts(".PP\n"
4252 ".nf");
4253
4254 arg = mxmlFindElement(function, function, "returnvalue", NULL,
4255 NULL, MXML_DESCEND_FIRST);
4256
4257 if (arg)
4258 write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL,
4259 NULL, MXML_DESCEND_FIRST),
4260 OUTPUT_MAN);
4261 else
4262 fputs("void", stdout);
4263
4264 printf(" %s ", name);
4265 for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
4266 MXML_DESCEND_FIRST), prefix = '(';
4267 arg;
4268 arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
4269 MXML_NO_DESCEND), prefix = ',')
4270 {
4271 type = mxmlFindElement(arg, arg, "type", NULL, NULL,
4272 MXML_DESCEND_FIRST);
4273
4274 printf("%c\n ", prefix);
4275 if (type->child)
4276 write_element(stdout, doc, type, OUTPUT_MAN);
4277 fputs(mxmlElementGetAttr(arg, "name"), stdout);
4278 if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
4279 printf(" %s", defval);
4280 }
4281
4282 if (prefix == '(')
4283 puts("(void);");
4284 else
4285 puts("\n);");
4286
4287 puts(".fi");
4288
4289 write_description(stdout, description, NULL, 0);
4290 }
4291 }
4292
4293 /*
4294 * List of structures...
4295 */
4296
4297 if (find_public(doc, doc, "struct"))
4298 {
4299 puts(".SH STRUCTURES");
4300
4301 for (scut = find_public(doc, doc, "struct");
4302 scut;
4303 scut = find_public(scut, doc, "struct"))
4304 {
4305 cname = mxmlElementGetAttr(scut, "name");
4306 description = mxmlFindElement(scut, scut, "description", NULL,
4307 NULL, MXML_DESCEND_FIRST);
4308 printf(".SS %s\n", cname);
4309
4310 write_description(stdout, description, NULL, 1);
4311
4312 printf(".PP\n"
4313 ".nf\n"
4314 "struct %s\n{\n", cname);
4315 for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
4316 MXML_DESCEND_FIRST);
4317 arg;
4318 arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
4319 MXML_NO_DESCEND))
4320 {
4321 printf(" ");
4322 write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL,
4323 NULL, MXML_DESCEND_FIRST),
4324 OUTPUT_MAN);
4325 printf("%s;\n", mxmlElementGetAttr(arg, "name"));
4326 }
4327
4328 for (function = mxmlFindElement(scut, scut, "function", NULL, NULL,
4329 MXML_DESCEND_FIRST);
4330 function;
4331 function = mxmlFindElement(function, scut, "function", NULL, NULL,
4332 MXML_NO_DESCEND))
4333 {
4334 name = mxmlElementGetAttr(function, "name");
4335
4336 printf(" ");
4337
4338 arg = mxmlFindElement(function, function, "returnvalue", NULL,
4339 NULL, MXML_DESCEND_FIRST);
4340
4341 if (arg)
4342 write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL,
4343 NULL, MXML_DESCEND_FIRST),
4344 OUTPUT_MAN);
4345 else if (strcmp(cname, name) && strcmp(cname, name + 1))
4346 fputs("void ", stdout);
4347
4348 fputs(name, stdout);
4349
4350 for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
4351 MXML_DESCEND_FIRST), prefix = '(';
4352 arg;
4353 arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
4354 MXML_NO_DESCEND), prefix = ',')
4355 {
4356 type = mxmlFindElement(arg, arg, "type", NULL, NULL,
4357 MXML_DESCEND_FIRST);
4358
4359 putchar(prefix);
4360 if (prefix == ',')
4361 putchar(' ');
4362
4363 if (type->child)
4364 write_element(stdout, doc, type, OUTPUT_MAN);
4365 fputs(mxmlElementGetAttr(arg, "name"), stdout);
4366 if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
4367 printf(" %s", defval);
4368 }
4369
4370 if (prefix == '(')
4371 puts("(void);");
4372 else
4373 puts(");");
4374 }
4375
4376 puts("};\n"
4377 ".fi");
4378
4379 write_description(stdout, description, NULL, 0);
4380 }
4381 }
4382
4383 /*
4384 * List of types...
4385 */
4386
4387 if (find_public(doc, doc, "typedef"))
4388 {
4389 puts(".SH TYPES");
4390
4391 for (scut = find_public(doc, doc, "typedef");
4392 scut;
4393 scut = find_public(scut, doc, "typedef"))
4394 {
4395 name = mxmlElementGetAttr(scut, "name");
4396 description = mxmlFindElement(scut, scut, "description", NULL,
4397 NULL, MXML_DESCEND_FIRST);
4398 printf(".SS %s\n", name);
4399
4400 write_description(stdout, description, NULL, 1);
4401
4402 fputs(".PP\n"
4403 ".nf\n"
4404 "typedef ", stdout);
4405
4406 type = mxmlFindElement(scut, scut, "type", NULL, NULL,
4407 MXML_DESCEND_FIRST);
4408
4409 for (type = type->child; type; type = type->next)
4410 if (!strcmp(type->value.text.string, "("))
4411 break;
4412 else
4413 {
4414 if (type->value.text.whitespace)
4415 putchar(' ');
4416
4417 write_string(stdout, type->value.text.string, OUTPUT_MAN);
4418 }
4419
4420 if (type)
4421 {
4422 /*
4423 * Output function type...
4424 */
4425
4426 printf(" (*%s", name);
4427
4428 for (type = type->next->next; type; type = type->next)
4429 {
4430 if (type->value.text.whitespace)
4431 putchar(' ');
4432
4433 write_string(stdout, type->value.text.string, OUTPUT_MAN);
4434 }
4435
4436 puts(";");
4437 }
4438 else
4439 printf(" %s;\n", name);
4440
4441 puts(".fi");
4442
4443 write_description(stdout, description, NULL, 0);
4444 }
4445 }
4446
4447 /*
4448 * List of unions...
4449 */
4450
4451 if (find_public(doc, doc, "union"))
4452 {
4453 puts(".SH UNIONS");
4454
4455 for (scut = find_public(doc, doc, "union");
4456 scut;
4457 scut = find_public(scut, doc, "union"))
4458 {
4459 name = mxmlElementGetAttr(scut, "name");
4460 description = mxmlFindElement(scut, scut, "description", NULL,
4461 NULL, MXML_DESCEND_FIRST);
4462 printf(".SS %s\n", name);
4463
4464 write_description(stdout, description, NULL, 1);
4465
4466 printf(".PP\n"
4467 ".nf\n"
4468 "union %s\n{\n", name);
4469 for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
4470 MXML_DESCEND_FIRST);
4471 arg;
4472 arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
4473 MXML_NO_DESCEND))
4474 {
4475 printf(" ");
4476 write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL,
4477 NULL, MXML_DESCEND_FIRST),
4478 OUTPUT_MAN);
4479 printf("%s;\n", mxmlElementGetAttr(arg, "name"));
4480 }
4481
4482 puts("};\n"
4483 ".fi");
4484
4485 write_description(stdout, description, NULL, 0);
4486 }
4487 }
4488
4489 /*
4490 * Variables...
4491 */
4492
4493 if (find_public(doc, doc, "variable"))
4494 {
4495 puts(".SH VARIABLES");
4496
4497 for (arg = find_public(doc, doc, "variable");
4498 arg;
4499 arg = find_public(arg, doc, "variable"))
4500 {
4501 name = mxmlElementGetAttr(arg, "name");
4502 description = mxmlFindElement(arg, arg, "description", NULL,
4503 NULL, MXML_DESCEND_FIRST);
4504 printf(".SS %s\n", name);
4505
4506 write_description(stdout, description, NULL, 1);
4507
4508 puts(".PP\n"
4509 ".nf");
4510
4511 write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL,
4512 NULL, MXML_DESCEND_FIRST),
4513 OUTPUT_MAN);
4514 fputs(mxmlElementGetAttr(arg, "name"), stdout);
4515 if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
4516 printf(" %s", defval);
4517 puts(";\n"
4518 ".fi");
4519
4520 write_description(stdout, description, NULL, 0);
4521 }
4522 }
4523
4524 if (footerfile)
4525 {
4526 /*
4527 * Use custom footer...
4528 */
4529
4530 write_file(stdout, footerfile);
4531 }
4532}
4533
4534
4535/*
4536 * 'write_scu()' - Write a structure, class, or union.
4537 */
4538
4539static void
4540write_scu(FILE *out, /* I - Output file */
4541 mxml_node_t *doc, /* I - Document */
4542 mxml_node_t *scut) /* I - Structure, class, or union */
4543{
4544 int i; /* Looping var */
4545 mxml_node_t *function, /* Current function */
4546 *arg, /* Current argument */
4547 *description, /* Description of function/var */
4548 *type; /* Type for argument */
4549 const char *name, /* Name of function/type */
4550 *cname, /* Class name */
4551 *defval, /* Default value */
4552 *parent, /* Parent class */
4553 *scope; /* Scope for variable/function */
4554 int inscope, /* Variable/method scope */
4555 maxscope; /* Maximum scope */
4556 char prefix; /* Prefix character */
4557 static const char * const scopes[] = /* Scope strings */
4558 {
4559 "private",
4560 "protected",
4561 "public"
4562 };
4563
4564
4565 cname = mxmlElementGetAttr(scut, "name");
4566 description = mxmlFindElement(scut, scut, "description", NULL,
4567 NULL, MXML_DESCEND_FIRST);
4568
4569 fprintf(out, "<h3 class=\"%s\">%s<a name=\"%s\">%s</a></h3>\n",
4570 scut->value.element.name, get_comment_info(description), cname,
4571 cname);
4572
4573 if (description)
4574 write_description(out, description, "p", 1);
4575
4576 fprintf(out, "<p class=\"code\">%s %s", scut->value.element.name, cname);
4577 if ((parent = mxmlElementGetAttr(scut, "parent")) != NULL)
4578 fprintf(out, " %s", parent);
4579 fputs(" {<br>\n", out);
4580
4581 maxscope = !strcmp(scut->value.element.name, "class") ? 3 : 1;
4582
4583 for (i = 0; i < maxscope; i ++)
4584 {
4585 inscope = maxscope == 1;
4586
4587 for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
4588 MXML_DESCEND_FIRST);
4589 arg;
4590 arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
4591 MXML_NO_DESCEND))
4592 {
4593 if (maxscope > 1 &&
4594 ((scope = mxmlElementGetAttr(arg, "scope")) == NULL ||
4595 strcmp(scope, scopes[i])))
4596 continue;
4597
4598 if (!inscope)
4599 {
4600 inscope = 1;
4601 fprintf(out, "&nbsp;&nbsp;%s:<br>\n", scopes[i]);
4602 }
4603
4604 fputs("&nbsp;&nbsp;&nbsp;&nbsp;", out);
4605 write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL,
4606 NULL, MXML_DESCEND_FIRST),
4607 OUTPUT_HTML);
4608 fprintf(out, "%s;<br>\n", mxmlElementGetAttr(arg, "name"));
4609 }
4610
4611 for (function = mxmlFindElement(scut, scut, "function", NULL, NULL,
4612 MXML_DESCEND_FIRST);
4613 function;
4614 function = mxmlFindElement(function, scut, "function", NULL, NULL,
4615 MXML_NO_DESCEND))
4616 {
4617 if (maxscope > 1 &&
4618 ((scope = mxmlElementGetAttr(arg, "scope")) == NULL ||
4619 strcmp(scope, scopes[i])))
4620 continue;
4621
4622 if (!inscope)
4623 {
4624 inscope = 1;
4625 fprintf(out, "&nbsp;&nbsp;%s:<br>\n", scopes[i]);
4626 }
4627
4628 name = mxmlElementGetAttr(function, "name");
4629
4630 fputs("&nbsp;&nbsp;&nbsp;&nbsp;", out);
4631
4632 arg = mxmlFindElement(function, function, "returnvalue", NULL,
4633 NULL, MXML_DESCEND_FIRST);
4634
4635 if (arg)
4636 write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL,
4637 NULL, MXML_DESCEND_FIRST),
4638 OUTPUT_HTML);
4639 else if (strcmp(cname, name) && strcmp(cname, name + 1))
4640 fputs("void ", out);
4641
4642 fprintf(out, "<a href=\"#%s.%s\">%s</a>", cname, name, name);
4643
4644 for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
4645 MXML_DESCEND_FIRST), prefix = '(';
4646 arg;
4647 arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
4648 MXML_NO_DESCEND), prefix = ',')
4649 {
4650 type = mxmlFindElement(arg, arg, "type", NULL, NULL,
4651 MXML_DESCEND_FIRST);
4652
4653 putc(prefix, out);
4654 if (prefix == ',')
4655 putc(' ', out);
4656
4657 if (type->child)
4658 write_element(out, doc, type, OUTPUT_HTML);
4659
4660 fputs(mxmlElementGetAttr(arg, "name"), out);
4661 if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
4662 fprintf(out, " %s", defval);
4663 }
4664
4665 if (prefix == '(')
4666 fputs("(void);<br>\n", out);
4667 else
4668 fputs(");<br>\n", out);
4669 }
4670 }
4671
4672 fputs("};</p>\n"
4673 "<h4 class=\"members\">Members</h4>\n"
4674 "<dl>\n", out);
4675
4676 for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
4677 MXML_DESCEND_FIRST);
4678 arg;
4679 arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
4680 MXML_NO_DESCEND))
4681 {
4682 description = mxmlFindElement(arg, arg, "description", NULL,
4683 NULL, MXML_DESCEND_FIRST);
4684
4685 fprintf(out, "<dt>%s %s</dt>\n",
4686 mxmlElementGetAttr(arg, "name"), get_comment_info(description));
4687
4688 write_description(out, description, "dd", 1);
4689 write_description(out, description, "dd", 0);
4690 }
4691
4692 fputs("</dl>\n", out);
4693
4694 for (function = mxmlFindElement(scut, scut, "function", NULL, NULL,
4695 MXML_DESCEND_FIRST);
4696 function;
4697 function = mxmlFindElement(function, scut, "function", NULL, NULL,
4698 MXML_NO_DESCEND))
4699 {
4700 write_function(out, doc, function, 4);
4701 }
4702}
4703
4704
4705/*
4706 * 'write_string()' - Write a string, quoting HTML special chars as needed.
4707 */
4708
4709static void
4710write_string(FILE *out, /* I - Output file */
4711 const char *s, /* I - String to write */
4712 int mode) /* I - Output mode */
4713{
4714 switch (mode)
4715 {
4716 case OUTPUT_HTML :
4717 case OUTPUT_XML :
4718 while (*s)
4719 {
4720 if (*s == '&')
4721 fputs("&amp;", out);
4722 else if (*s == '<')
4723 fputs("&lt;", out);
4724 else if (*s == '>')
4725 fputs("&gt;", out);
4726 else if (*s == '\"')
4727 fputs("&quot;", out);
4728 else if (*s & 128)
4729 {
4730 /*
4731 * Convert UTF-8 to Unicode constant...
4732 */
4733
4734 int ch; /* Unicode character */
4735
4736
4737 ch = *s & 255;
4738
4739 if ((ch & 0xe0) == 0xc0)
4740 {
4741 ch = ((ch & 0x1f) << 6) | (s[1] & 0x3f);
4742 s ++;
4743 }
4744 else if ((ch & 0xf0) == 0xe0)
4745 {
4746 ch = ((((ch * 0x0f) << 6) | (s[1] & 0x3f)) << 6) | (s[2] & 0x3f);
4747 s += 2;
4748 }
4749
4750 if (ch == 0xa0)
4751 {
4752 /*
4753 * Handle non-breaking space as-is...
4754 */
4755
4756 fputs("&nbsp;", out);
4757 }
4758 else
4759 fprintf(out, "&#x%x;", ch);
4760 }
4761 else
4762 putc(*s, out);
4763
4764 s ++;
4765 }
4766 break;
4767
4768 case OUTPUT_MAN :
4769 while (*s)
4770 {
4771 if (*s == '\\' || *s == '-')
4772 putc('\\', out);
4773
4774 putc(*s++, out);
4775 }
4776 break;
4777 }
4778}
4779
4780
4781/*
4782 * 'write_toc()' - Write a table-of-contents.
4783 */
4784
4785static void
4786write_toc(FILE *out, /* I - Output file */
4787 mxml_node_t *doc, /* I - Document */
4788 const char *introfile, /* I - Introduction file */
4789 const char *target, /* I - Target name */
4790 int xml) /* I - Write XML nodes? */
4791{
4792 FILE *fp; /* Intro file */
4793 mxml_node_t *function, /* Current function */
4794 *scut, /* Struct/class/union/typedef */
4795 *arg, /* Current argument */
4796 *description; /* Description of function/var */
4797 const char *name, /* Name of function/type */
4798 *targetattr; /* Target attribute, if any */
4799 int xmlid = 1; /* Current XML node ID */
4800
4801
4802 /*
4803 * If target is set, it is the frame file that contains the body.
4804 * Otherwise, we are creating a single-file...
4805 */
4806
4807 if (target)
4808 targetattr = " target=\"body\"";
4809 else
4810 targetattr = "";
4811
4812 /*
4813 * The table-of-contents is a nested unordered list. Start by
4814 * reading any intro file to see if there are any headings there.
4815 */
4816
4817 if (!xml)
4818 fputs("<h2 class=\"title\">Contents</h2>\n"
4819 "<ul class=\"contents\">\n", out);
4820
4821 if (introfile && (fp = fopen(introfile, "r")) != NULL)
4822 {
4823 char line[8192], /* Line from file */
4824 *ptr, /* Pointer in line */
4825 *end, /* End of line */
4826 *anchor, /* Anchor name */
4827 quote, /* Quote character for value */
4828 level = '2', /* Current heading level */
4829 newlevel; /* New heading level */
4830 int inelement; /* In an element? */
4831
4832
4833 while (fgets(line, sizeof(line), fp))
4834 {
4835 /*
4836 * See if this line has a heading...
4837 */
4838
4839 if ((ptr = strstr(line, "<h")) == NULL &&
4840 (ptr = strstr(line, "<H")) == NULL)
4841 continue;
4842
4843 if (ptr[2] != '2' && ptr[2] != '3')
4844 continue;
4845
4846 newlevel = ptr[2];
4847
4848 /*
4849 * Make sure we have the whole heading...
4850 */
4851
4852 while (!strstr(line, "</h") && !strstr(line, "</H"))
4853 {
4854 end = line + strlen(line);
4855
4856 if (end == (line + sizeof(line) - 1) ||
4857 !fgets(end, (int)(sizeof(line) - (end - line)), fp))
4858 break;
4859 }
4860
4861 /*
4862 * Convert newlines and tabs to spaces...
4863 */
4864
4865 for (ptr = line; *ptr; ptr ++)
4866 if (isspace(*ptr & 255))
4867 *ptr = ' ';
4868
4869 /*
4870 * Find the anchor and text...
4871 */
4872
4873 for (ptr = strchr(line, '<'); ptr; ptr = strchr(ptr + 1, '<'))
4874 if (!strncmp(ptr, "<A NAME=", 8) || !strncmp(ptr, "<a name=", 8))
4875 break;
4876
4877 if (!ptr)
4878 continue;
4879
4880 ptr += 8;
4881 inelement = 1;
4882
4883 if (*ptr == '\'' || *ptr == '\"')
4884 {
4885 /*
4886 * Quoted anchor...
4887 */
4888
4889 quote = *ptr++;
4890 anchor = ptr;
4891
4892 while (*ptr && *ptr != quote)
4893 ptr ++;
4894
4895 if (!*ptr)
4896 continue;
4897
4898 *ptr++ = '\0';
4899 }
4900 else
4901 {
4902 /*
4903 * Non-quoted anchor...
4904 */
4905
4906 anchor = ptr;
4907
4908 while (*ptr && *ptr != '>' && !isspace(*ptr & 255))
4909 ptr ++;
4910
4911 if (!*ptr)
4912 continue;
4913
4914 if (*ptr == '>')
4915 inelement = 0;
4916
4917 *ptr++ = '\0';
4918 }
4919
4920 /*
4921 * Write text until we see "</A>"...
4922 */
4923
4924 if (xml)
4925 {
4926 if (newlevel < level)
4927 fputs("</Node>\n"
4928 "</Subnodes></Node>\n", out);
4929 else if (newlevel > level && newlevel == '3')
4930 fputs("<Subnodes>\n", out);
4931 else if (xmlid > 1)
4932 fputs("</Node>\n", out);
4933
4934 level = newlevel;
4935
4936 fprintf(out, "<Node id=\"%d\">\n"
4937 "<Path>Documentation/index.html</Path>\n"
4938 "<Anchor>%s</Anchor>\n"
4939 "<Name>", xmlid ++, anchor);
4940
4941 quote = 0;
4942
4943 while (*ptr)
4944 {
4945 if (inelement)
4946 {
4947 if (*ptr == quote)
4948 quote = 0;
4949 else if (*ptr == '>')
4950 inelement = 0;
4951 else if (*ptr == '\'' || *ptr == '\"')
4952 quote = *ptr;
4953 }
4954 else if (*ptr == '<')
4955 {
4956 if (!strncmp(ptr, "</A>", 4) || !strncmp(ptr, "</a>", 4))
4957 break;
4958
4959 inelement = 1;
4960 }
4961 else
4962 putc(*ptr, out);
4963
4964 ptr ++;
4965 }
4966
4967 fputs("</Name>\n", out);
4968 }
4969 else
4970 {
4971 if (newlevel < level)
4972 fputs("</li>\n"
4973 "</ul></li>\n", out);
4974 else if (newlevel > level)
4975 fputs("<ul class=\"subcontents\">\n", out);
4976 else if (xmlid > 1)
4977 fputs("</li>\n", out);
4978
4979 level = newlevel;
4980 xmlid ++;
4981
4982 fprintf(out, "%s<li><a href=\"%s#%s\"%s>", level > '2' ? "\t" : "",
4983 target ? target : "", anchor, targetattr);
4984
4985 quote = 0;
4986
4987 while (*ptr)
4988 {
4989 if (inelement)
4990 {
4991 if (*ptr == quote)
4992 quote = 0;
4993 else if (*ptr == '>')
4994 inelement = 0;
4995 else if (*ptr == '\'' || *ptr == '\"')
4996 quote = *ptr;
4997 }
4998 else if (*ptr == '<')
4999 {
5000 if (!strncmp(ptr, "</A>", 4) || !strncmp(ptr, "</a>", 4))
5001 break;
5002
5003 inelement = 1;
5004 }
5005 else
5006 putc(*ptr, out);
5007
5008 ptr ++;
5009 }
5010
5011 fputs("</a>", out);
5012 }
5013 }
5014
5015 if (level > '1')
5016 {
5017 if (xml)
5018 {
5019 fputs("</Node>\n", out);
5020
5021 if (level == '3')
5022 fputs("</Subnodes></Node>\n", out);
5023 }
5024 else
5025 {
5026 fputs("</li>\n", out);
5027
5028 if (level == '3')
5029 fputs("</ul></li>\n", out);
5030 }
5031 }
5032
5033 fclose(fp);
5034 }
5035
5036 /*
5037 * Next the classes...
5038 */
5039
5040 if ((scut = find_public(doc, doc, "class")) != NULL)
5041 {
5042 if (xml)
5043 fprintf(out, "<Node id=\"%d\">\n"
5044 "<Path>Documentation/index.html</Path>\n"
5045 "<Anchor>CLASSES</Anchor>\n"
5046 "<Name>Classes</Name>\n"
5047 "<Subnodes>\n", xmlid ++);
5048 else
5049 fprintf(out, "<li><a href=\"%s#CLASSES\"%s>Classes</a>"
5050 "<ul class=\"code\">\n",
5051 target ? target : "", targetattr);
5052
5053 while (scut)
5054 {
5055 name = mxmlElementGetAttr(scut, "name");
5056 description = mxmlFindElement(scut, scut, "description",
5057 NULL, NULL, MXML_DESCEND_FIRST);
5058
5059 if (xml)
5060 {
5061 fprintf(out, "<Node id=\"%d\">\n"
5062 "<Path>Documentation/index.html</Path>\n"
5063 "<Anchor>%s</Anchor>\n"
5064 "<Name>%s</Name>\n"
5065 "</Node>\n", xmlid ++, name, name);
5066 }
5067 else
5068 {
5069 fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"",
5070 target ? target : "", name, targetattr);
5071 write_description(out, description, "", 1);
5072 fprintf(out, "\">%s</a></li>\n", name);
5073 }
5074
5075 scut = find_public(scut, doc, "class");
5076 }
5077
5078 if (xml)
5079 fputs("</Subnodes></Node>\n", out);
5080 else
5081 fputs("</ul></li>\n", out);
5082 }
5083
5084 /*
5085 * Functions...
5086 */
5087
5088 if ((function = find_public(doc, doc, "function")) != NULL)
5089 {
5090 if (xml)
5091 fprintf(out, "<Node id=\"%d\">\n"
5092 "<Path>Documentation/index.html</Path>\n"
5093 "<Anchor>FUNCTIONS</Anchor>\n"
5094 "<Name>Functions</Name>\n"
5095 "<Subnodes>\n", xmlid ++);
5096 else
5097 fprintf(out, "<li><a href=\"%s#FUNCTIONS\"%s>Functions</a>"
5098 "<ul class=\"code\">\n", target ? target : "", targetattr);
5099
5100 while (function)
5101 {
5102 name = mxmlElementGetAttr(function, "name");
5103 description = mxmlFindElement(function, function, "description",
5104 NULL, NULL, MXML_DESCEND_FIRST);
5105
5106 if (xml)
5107 {
5108 fprintf(out, "<Node id=\"%d\">\n"
5109 "<Path>Documentation/index.html</Path>\n"
5110 "<Anchor>%s</Anchor>\n"
5111 "<Name>%s</Name>\n"
5112 "</Node>\n", xmlid ++, name, name);
5113 }
5114 else
5115 {
5116 fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"",
5117 target ? target : "", name, targetattr);
5118 write_description(out, description, "", 1);
5119 fprintf(out, "\">%s</a></li>\n", name);
5120 }
5121
5122 function = find_public(function, doc, "function");
5123 }
5124
5125 if (xml)
5126 fputs("</Subnodes></Node>\n", out);
5127 else
5128 fputs("</ul></li>\n", out);
5129 }
5130
5131 /*
5132 * Data types...
5133 */
5134
5135 if ((scut = find_public(doc, doc, "typedef")) != NULL)
5136 {
5137 if (xml)
5138 fprintf(out, "<Node id=\"%d\">\n"
5139 "<Path>Documentation/index.html</Path>\n"
5140 "<Anchor>TYPES</Anchor>\n"
5141 "<Name>Data Types</Name>\n"
5142 "<Subnodes>\n", xmlid ++);
5143 else
5144 fprintf(out, "<li><a href=\"%s#TYPES\"%s>Data Types</a>"
5145 "<ul class=\"code\">\n", target ? target : "", targetattr);
5146
5147 while (scut)
5148 {
5149 name = mxmlElementGetAttr(scut, "name");
5150 description = mxmlFindElement(scut, scut, "description",
5151 NULL, NULL, MXML_DESCEND_FIRST);
5152
5153 if (xml)
5154 {
5155 fprintf(out, "<Node id=\"%d\">\n"
5156 "<Path>Documentation/index.html</Path>\n"
5157 "<Anchor>%s</Anchor>\n"
5158 "<Name>%s</Name>\n"
5159 "</Node>\n", xmlid ++, name, name);
5160 }
5161 else
5162 {
5163 fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"",
5164 target ? target : "", name, targetattr);
5165 write_description(out, description, "", 1);
5166 fprintf(out, "\">%s</a></li>\n", name);
5167 }
5168
5169 scut = find_public(scut, doc, "typedef");
5170 }
5171
5172 if (xml)
5173 fputs("</Subnodes></Node>\n", out);
5174 else
5175 fputs("</ul></li>\n", out);
5176 }
5177
5178 /*
5179 * Structures...
5180 */
5181
5182 if ((scut = find_public(doc, doc, "struct")) != NULL)
5183 {
5184 if (xml)
5185 fprintf(out, "<Node id=\"%d\">\n"
5186 "<Path>Documentation/index.html</Path>\n"
5187 "<Anchor>STRUCTURES</Anchor>\n"
5188 "<Name>Structures</Name>\n"
5189 "<Subnodes>\n", xmlid ++);
5190 else
5191 fprintf(out, "<li><a href=\"%s#STRUCTURES\"%s>Structures</a>"
5192 "<ul class=\"code\">\n", target ? target : "", targetattr);
5193
5194 while (scut)
5195 {
5196 name = mxmlElementGetAttr(scut, "name");
5197 description = mxmlFindElement(scut, scut, "description",
5198 NULL, NULL, MXML_DESCEND_FIRST);
5199
5200 if (xml)
5201 {
5202 fprintf(out, "<Node id=\"%d\">\n"
5203 "<Path>Documentation/index.html</Path>\n"
5204 "<Anchor>%s</Anchor>\n"
5205 "<Name>%s</Name>\n"
5206 "</Node>\n", xmlid ++, name, name);
5207 }
5208 else
5209 {
5210 fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"",
5211 target ? target : "", name, targetattr);
5212 write_description(out, description, "", 1);
5213 fprintf(out, "\">%s</a></li>\n", name);
5214 }
5215
5216 scut = find_public(scut, doc, "struct");
5217 }
5218
5219 if (xml)
5220 fputs("</Subnodes></Node>\n", out);
5221 else
5222 fputs("</ul></li>\n", out);
5223 }
5224
5225 /*
5226 * Unions...
5227 */
5228
5229 if ((scut = find_public(doc, doc, "union")) != NULL)
5230 {
5231 if (xml)
5232 fprintf(out, "<Node id=\"%d\">\n"
5233 "<Path>Documentation/index.html</Path>\n"
5234 "<Anchor>UNIONS</Anchor>\n"
5235 "<Name>Unions</Name>\n"
5236 "<Subnodes>\n", xmlid ++);
5237 else
5238 fprintf(out,
5239 "<li><a href=\"%s#UNIONS\"%s>Unions</a><ul class=\"code\">\n",
5240 target ? target : "", targetattr);
5241
5242 while (scut)
5243 {
5244 name = mxmlElementGetAttr(scut, "name");
5245 description = mxmlFindElement(scut, scut, "description",
5246 NULL, NULL, MXML_DESCEND_FIRST);
5247
5248 if (xml)
5249 {
5250 fprintf(out, "<Node id=\"%d\">\n"
5251 "<Path>Documentation/index.html</Path>\n"
5252 "<Anchor>%s</Anchor>\n"
5253 "<Name>%s</Name>\n"
5254 "</Node>\n", xmlid ++, name, name);
5255 }
5256 else
5257 {
5258 fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"",
5259 target ? target : "", name, targetattr);
5260 write_description(out, description, "", 1);
5261 fprintf(out, "\">%s</a></li>\n", name);
5262 }
5263
5264 scut = find_public(scut, doc, "union");
5265 }
5266
5267 if (xml)
5268 fputs("</Subnodes></Node>\n", out);
5269 else
5270 fputs("</ul></li>\n", out);
5271 }
5272
5273 /*
5274 * Globals variables...
5275 */
5276
5277 if ((arg = find_public(doc, doc, "variable")) != NULL)
5278 {
5279 if (xml)
5280 fprintf(out, "<Node id=\"%d\">\n"
5281 "<Path>Documentation/index.html</Path>\n"
5282 "<Anchor>VARIABLES</Anchor>\n"
5283 "<Name>Variables</Name>\n"
5284 "<Subnodes>\n", xmlid ++);
5285 else
5286 fprintf(out, "<li><a href=\"%s#VARIABLES\"%s>Variables</a>"
5287 "<ul class=\"code\">\n", target ? target : "", targetattr);
5288
5289 while (arg)
5290 {
5291 name = mxmlElementGetAttr(arg, "name");
5292 description = mxmlFindElement(arg, arg, "description",
5293 NULL, NULL, MXML_DESCEND_FIRST);
5294
5295 if (xml)
5296 {
5297 fprintf(out, "<Node id=\"%d\">\n"
5298 "<Path>Documentation/index.html</Path>\n"
5299 "<Anchor>%s</Anchor>\n"
5300 "<Name>%s</Name>\n"
5301 "</Node>\n", xmlid ++, name, name);
5302 }
5303 else
5304 {
5305 fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"",
5306 target ? target : "", name, targetattr);
5307 write_description(out, description, "", 1);
5308 fprintf(out, "\">%s</a></li>\n", name);
5309 }
5310
5311 arg = find_public(arg, doc, "variable");
5312 }
5313
5314 if (xml)
5315 fputs("</Subnodes></Node>\n", out);
5316 else
5317 fputs("</ul></li>\n", out);
5318 }
5319
5320 /*
5321 * Enumerations/constants...
5322 */
5323
5324 if ((scut = find_public(doc, doc, "enumeration")) != NULL)
5325 {
5326 if (xml)
5327 fprintf(out, "<Node id=\"%d\">\n"
5328 "<Path>Documentation/index.html</Path>\n"
5329 "<Anchor>ENUMERATIONS</Anchor>\n"
5330 "<Name>Constants</Name>\n"
5331 "<Subnodes>\n", xmlid ++);
5332 else
5333 fprintf(out, "<li><a href=\"%s#ENUMERATIONS\"%s>Constants</a>"
5334 "<ul class=\"code\">\n", target ? target : "", targetattr);
5335
5336 while (scut)
5337 {
5338 name = mxmlElementGetAttr(scut, "name");
5339 description = mxmlFindElement(scut, scut, "description",
5340 NULL, NULL, MXML_DESCEND_FIRST);
5341
5342 if (xml)
5343 {
5344 fprintf(out, "<Node id=\"%d\">\n"
5345 "<Path>Documentation/index.html</Path>\n"
5346 "<Anchor>%s</Anchor>\n"
5347 "<Name>%s</Name>\n"
5348 "</Node>\n", xmlid ++, name, name);
5349 }
5350 else
5351 {
5352 fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"",
5353 target ? target : "", name, targetattr);
5354 write_description(out, description, "", 1);
5355 fprintf(out, "\">%s</a></li>\n", name);
5356 }
5357
5358 scut = find_public(scut, doc, "enumeration");
5359 }
5360
5361 if (xml)
5362 fputs("</Subnodes></Node>\n", out);
5363 else
5364 fputs("</ul></li>\n", out);
5365 }
5366
5367 /*
5368 * Close out the HTML table-of-contents list as needed...
5369 */
5370
5371 if (!xml)
5372 fputs("</ul>\n", out);
5373}
5374
5375
5376/*
5377 * 'write_tokens()' - Write <Token> nodes for all APIs.
5378 */
5379
5380static void
5381write_tokens(FILE *out, /* I - Output file */
5382 mxml_node_t *doc, /* I - Document */
5383 const char *path) /* I - Path to help file */
5384{
5385 mxml_node_t *function, /* Current function */
5386 *scut, /* Struct/class/union/typedef */
5387 *arg, /* Current argument */
5388 *description, /* Description of function/var */
5389 *type, /* Type node */
5390 *node; /* Current child node */
5391 const char *name, /* Name of function/type */
5392 *cename, /* Current class/enum name */
5393 *defval; /* Default value for argument */
5394 char prefix; /* Prefix for declarations */
5395
5396
5397 /*
5398 * Classes...
5399 */
5400
5401 if ((scut = find_public(doc, doc, "class")) != NULL)
5402 {
5403 while (scut)
5404 {
5405 cename = mxmlElementGetAttr(scut, "name");
5406 description = mxmlFindElement(scut, scut, "description",
5407 NULL, NULL, MXML_DESCEND_FIRST);
5408
5409 fprintf(out, "<Token>\n"
5410 "<Path>Documentation/%s</Path>\n"
5411 "<Anchor>%s</Anchor>\n"
5412 "<TokenIdentifier>//apple_ref/cpp/cl/%s</TokenIdentifier>\n"
5413 "<Abstract>", path, cename, cename);
5414 write_description(out, description, "", 1);
5415 fputs("</Abstract>\n"
5416 "</Token>\n", out);
5417
5418 if ((function = find_public(scut, scut, "function")) != NULL)
5419 {
5420 while (function)
5421 {
5422 name = mxmlElementGetAttr(function, "name");
5423 description = mxmlFindElement(function, function, "description",
5424 NULL, NULL, MXML_DESCEND_FIRST);
5425
5426 fprintf(out, "<Token>\n"
5427 "<Path>Documentation/%s</Path>\n"
5428 "<Anchor>%s.%s</Anchor>\n"
5429 "<TokenIdentifier>//apple_ref/cpp/clm/%s/%s", path,
5430 cename, name, cename, name);
5431
5432 arg = mxmlFindElement(function, function, "returnvalue", NULL,
5433 NULL, MXML_DESCEND_FIRST);
5434
5435 if (arg && (type = mxmlFindElement(arg, arg, "type", NULL,
5436 NULL, MXML_DESCEND_FIRST)) != NULL)
5437 {
5438 for (node = type->child; node; node = node->next)
5439 fputs(node->value.text.string, out);
5440 }
5441 else if (strcmp(cename, name) && strcmp(cename, name + 1))
5442 fputs("void", out);
5443
5444 fputs("/", out);
5445
5446 for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
5447 MXML_DESCEND_FIRST), prefix = '(';
5448 arg;
5449 arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
5450 MXML_NO_DESCEND), prefix = ',')
5451 {
5452 type = mxmlFindElement(arg, arg, "type", NULL, NULL,
5453 MXML_DESCEND_FIRST);
5454
5455 putc(prefix, out);
5456
5457 for (node = type->child; node; node = node->next)
5458 fputs(node->value.text.string, out);
5459
5460 fputs(mxmlElementGetAttr(arg, "name"), out);
5461 }
5462
5463 if (prefix == '(')
5464 fputs("(void", out);
5465
5466 fputs(")</TokenIdentifier>\n"
5467 "<Abstract>", out);
5468 write_description(out, description, "", 1);
5469 fputs("</Abstract>\n"
5470 "<Declaration>", out);
5471
5472 arg = mxmlFindElement(function, function, "returnvalue", NULL,
5473 NULL, MXML_DESCEND_FIRST);
5474
5475 if (arg)
5476 write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL,
5477 NULL, MXML_DESCEND_FIRST),
5478 OUTPUT_XML);
5479 else if (strcmp(cename, name) && strcmp(cename, name + 1))
5480 fputs("void ", out);
5481
5482 fputs(name, out);
5483
5484 for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
5485 MXML_DESCEND_FIRST), prefix = '(';
5486 arg;
5487 arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
5488 MXML_NO_DESCEND), prefix = ',')
5489 {
5490 type = mxmlFindElement(arg, arg, "type", NULL, NULL,
5491 MXML_DESCEND_FIRST);
5492
5493 putc(prefix, out);
5494 if (prefix == ',')
5495 putc(' ', out);
5496
5497 if (type->child)
5498 write_element(out, doc, type, OUTPUT_XML);
5499
5500 fputs(mxmlElementGetAttr(arg, "name"), out);
5501 if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
5502 fprintf(out, " %s", defval);
5503 }
5504
5505 if (prefix == '(')
5506 fputs("(void);", out);
5507 else
5508 fputs(");", out);
5509
5510 fputs("</Declaration>\n"
5511 "</Token>\n", out);
5512
5513 function = find_public(function, doc, "function");
5514 }
5515 }
5516 scut = find_public(scut, doc, "class");
5517 }
5518 }
5519
5520 /*
5521 * Functions...
5522 */
5523
5524 if ((function = find_public(doc, doc, "function")) != NULL)
5525 {
5526 while (function)
5527 {
5528 name = mxmlElementGetAttr(function, "name");
5529 description = mxmlFindElement(function, function, "description",
5530 NULL, NULL, MXML_DESCEND_FIRST);
5531
5532 fprintf(out, "<Token>\n"
5533 "<Path>Documentation/%s</Path>\n"
5534 "<Anchor>%s</Anchor>\n"
5535 "<TokenIdentifier>//apple_ref/c/func/%s</TokenIdentifier>\n"
5536 "<Abstract>", path, name, name);
5537 write_description(out, description, "", 1);
5538 fputs("</Abstract>\n"
5539 "<Declaration>", out);
5540
5541 arg = mxmlFindElement(function, function, "returnvalue", NULL,
5542 NULL, MXML_DESCEND_FIRST);
5543
5544 if (arg)
5545 write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL,
5546 NULL, MXML_DESCEND_FIRST),
5547 OUTPUT_XML);
5548 else // if (strcmp(cname, name) && strcmp(cname, name + 1))
5549 fputs("void ", out);
5550
5551 fputs(name, out);
5552
5553 for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
5554 MXML_DESCEND_FIRST), prefix = '(';
5555 arg;
5556 arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
5557 MXML_NO_DESCEND), prefix = ',')
5558 {
5559 type = mxmlFindElement(arg, arg, "type", NULL, NULL,
5560 MXML_DESCEND_FIRST);
5561
5562 putc(prefix, out);
5563 if (prefix == ',')
5564 putc(' ', out);
5565
5566 if (type->child)
5567 write_element(out, doc, type, OUTPUT_XML);
5568
5569 fputs(mxmlElementGetAttr(arg, "name"), out);
5570 if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
5571 fprintf(out, " %s", defval);
5572 }
5573
5574 if (prefix == '(')
5575 fputs("(void);", out);
5576 else
5577 fputs(");", out);
5578
5579 fputs("</Declaration>\n"
5580 "</Token>\n", out);
5581
5582 function = find_public(function, doc, "function");
5583 }
5584 }
5585
5586 /*
5587 * Data types...
5588 */
5589
5590 if ((scut = find_public(doc, doc, "typedef")) != NULL)
5591 {
5592 while (scut)
5593 {
5594 name = mxmlElementGetAttr(scut, "name");
5595 description = mxmlFindElement(scut, scut, "description",
5596 NULL, NULL, MXML_DESCEND_FIRST);
5597
5598 fprintf(out, "<Token>\n"
5599 "<Path>Documentation/%s</Path>\n"
5600 "<Anchor>%s</Anchor>\n"
5601 "<TokenIdentifier>//apple_ref/c/tdef/%s</TokenIdentifier>\n"
5602 "<Abstract>", path, name, name);
5603 write_description(out, description, "", 1);
5604 fputs("</Abstract>\n"
5605 "</Token>\n", out);
5606
5607 scut = find_public(scut, doc, "typedef");
5608 }
5609 }
5610
5611 /*
5612 * Structures...
5613 */
5614
5615 if ((scut = find_public(doc, doc, "struct")) != NULL)
5616 {
5617 while (scut)
5618 {
5619 name = mxmlElementGetAttr(scut, "name");
5620 description = mxmlFindElement(scut, scut, "description",
5621 NULL, NULL, MXML_DESCEND_FIRST);
5622
5623 fprintf(out, "<Token>\n"
5624 "<Path>Documentation/%s</Path>\n"
5625 "<Anchor>%s</Anchor>\n"
5626 "<TokenIdentifier>//apple_ref/c/tag/%s</TokenIdentifier>\n"
5627 "<Abstract>", path, name, name);
5628 write_description(out, description, "", 1);
5629 fputs("</Abstract>\n"
5630 "</Token>\n", out);
5631
5632 scut = find_public(scut, doc, "struct");
5633 }
5634 }
5635
5636 /*
5637 * Unions...
5638 */
5639
5640 if ((scut = find_public(doc, doc, "union")) != NULL)
5641 {
5642 while (scut)
5643 {
5644 name = mxmlElementGetAttr(scut, "name");
5645 description = mxmlFindElement(scut, scut, "description",
5646 NULL, NULL, MXML_DESCEND_FIRST);
5647
5648 fprintf(out, "<Token>\n"
5649 "<Path>Documentation/%s</Path>\n"
5650 "<Anchor>%s</Anchor>\n"
5651 "<TokenIdentifier>//apple_ref/c/tag/%s</TokenIdentifier>\n"
5652 "<Abstract>", path, name, name);
5653 write_description(out, description, "", 1);
5654 fputs("</Abstract>\n"
5655 "</Token>\n", out);
5656
5657 scut = find_public(scut, doc, "union");
5658 }
5659 }
5660
5661 /*
5662 * Globals variables...
5663 */
5664
5665 if ((arg = find_public(doc, doc, "variable")) != NULL)
5666 {
5667 while (arg)
5668 {
5669 name = mxmlElementGetAttr(arg, "name");
5670 description = mxmlFindElement(arg, arg, "description",
5671 NULL, NULL, MXML_DESCEND_FIRST);
5672
5673 fprintf(out, "<Token>\n"
5674 "<Path>Documentation/%s</Path>\n"
5675 "<Anchor>%s</Anchor>\n"
5676 "<TokenIdentifier>//apple_ref/c/data/%s</TokenIdentifier>\n"
5677 "<Abstract>", path, name, name);
5678 write_description(out, description, "", 1);
5679 fputs("</Abstract>\n"
5680 "</Token>\n", out);
5681
5682 arg = find_public(arg, doc, "variable");
5683 }
5684 }
5685
5686 /*
5687 * Enumerations/constants...
5688 */
5689
5690 if ((scut = find_public(doc, doc, "enumeration")) != NULL)
5691 {
5692 while (scut)
5693 {
5694 cename = mxmlElementGetAttr(scut, "name");
5695 description = mxmlFindElement(scut, scut, "description",
5696 NULL, NULL, MXML_DESCEND_FIRST);
5697
5698 fprintf(out, "<Token>\n"
5699 "<Path>Documentation/%s</Path>\n"
5700 "<Anchor>%s</Anchor>\n"
5701 "<TokenIdentifier>//apple_ref/c/tag/%s</TokenIdentifier>\n"
5702 "<Abstract>", path, cename, cename);
5703 write_description(out, description, "", 1);
5704 fputs("</Abstract>\n"
5705 "</Token>\n", out);
5706
5707 for (arg = mxmlFindElement(scut, scut, "constant", NULL, NULL,
5708 MXML_DESCEND_FIRST);
5709 arg;
5710 arg = mxmlFindElement(arg, scut, "constant", NULL, NULL,
5711 MXML_NO_DESCEND))
5712 {
5713 name = mxmlElementGetAttr(arg, "name");
5714 description = mxmlFindElement(arg, arg, "description", NULL,
5715 NULL, MXML_DESCEND_FIRST);
5716 fprintf(out, "<Token>\n"
5717 "<Path>Documentation/%s</Path>\n"
5718 "<Anchor>%s</Anchor>\n"
5719 "<TokenIdentifier>//apple_ref/c/econst/%s</TokenIdentifier>\n"
5720 "<Abstract>", path, cename, name);
5721 write_description(out, description, "", 1);
5722 fputs("</Abstract>\n"
5723 "</Token>\n", out);
5724 }
5725
5726 scut = find_public(scut, doc, "enumeration");
5727 }
5728 }
5729}
5730
5731
5732/*
5733 * 'ws_cb()' - Whitespace callback for saving.
5734 */
5735
5736static const char * /* O - Whitespace string or NULL for none */
5737ws_cb(mxml_node_t *node, /* I - Element node */
5738 int where) /* I - Where value */
5739{
5740 const char *name; /* Name of element */
5741 int depth; /* Depth of node */
5742 static const char *spaces = " ";
5743 /* Whitespace (40 spaces) for indent */
5744
5745
5746 name = node->value.element.name;
5747
5748 switch (where)
5749 {
5750 case MXML_WS_BEFORE_CLOSE :
5751 if (strcmp(name, "argument") &&
5752 strcmp(name, "class") &&
5753 strcmp(name, "constant") &&
5754 strcmp(name, "enumeration") &&
5755 strcmp(name, "function") &&
5756 strcmp(name, "mxmldoc") &&
5757 strcmp(name, "namespace") &&
5758 strcmp(name, "returnvalue") &&
5759 strcmp(name, "struct") &&
5760 strcmp(name, "typedef") &&
5761 strcmp(name, "union") &&
5762 strcmp(name, "variable"))
5763 return (NULL);
5764
5765 for (depth = -4; node; node = node->parent, depth += 2);
5766 if (depth > 40)
5767 return (spaces);
5768 else if (depth < 2)
5769 return (NULL);
5770 else
5771 return (spaces + 40 - depth);
5772
5773 case MXML_WS_AFTER_CLOSE :
5774 return ("\n");
5775
5776 case MXML_WS_BEFORE_OPEN :
5777 for (depth = -4; node; node = node->parent, depth += 2);
5778 if (depth > 40)
5779 return (spaces);
5780 else if (depth < 2)
5781 return (NULL);
5782 else
5783 return (spaces + 40 - depth);
5784
5785 default :
5786 case MXML_WS_AFTER_OPEN :
5787 if (strcmp(name, "argument") &&
5788 strcmp(name, "class") &&
5789 strcmp(name, "constant") &&
5790 strcmp(name, "enumeration") &&
5791 strcmp(name, "function") &&
5792 strcmp(name, "mxmldoc") &&
5793 strcmp(name, "namespace") &&
5794 strcmp(name, "returnvalue") &&
5795 strcmp(name, "struct") &&
5796 strcmp(name, "typedef") &&
5797 strcmp(name, "union") &&
5798 strcmp(name, "variable") &&
5799 strncmp(name, "?xml", 4))
5800 return (NULL);
5801 else
5802 return ("\n");
5803 }
5804}
5805
5806
5807/*
5808 * End of "$Id: mxmldoc.c 440 2011-08-11 18:51:26Z mike $".
5809 */