00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "stdafx.h"
00035
00036 #include <ctype.h>
00037 #include <string.h>
00038 #include <stdarg.h>
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041
00042 #include "xlist.h"
00043
00044 #undef XTAG_DEBUG
00045
00046 #undef FALSE
00047 #undef TRUE
00048
00049 #define FALSE (0)
00050 #define TRUE (!FALSE)
00051
00052 #undef MIN
00053 #define MIN(a,b) ((a)<(b)?(a):(b))
00054
00055 #undef MAX
00056 #define MAX(a,b) ((a)>(b)?(a):(b))
00057
00058 typedef struct _XTag XTag;
00059 typedef struct _XAttribute XAttribute;
00060 typedef struct _XTagParser XTagParser;
00061
00062 #define XTAG_INTERNAL
00063 #include "xtag.h"
00064
00065
00066
00067
00068
00069
00070
00071 struct _XTag {
00072 char * name;
00073 char * pcdata;
00074 XTag * parent;
00075 XList * attributes;
00076 XList * children;
00077 XList * current_child;
00078 };
00079
00080 struct _XAttribute {
00081 char * name;
00082 char * value;
00083 };
00084
00085 struct _XTagParser {
00086 int valid;
00087 XTag * current_tag;
00088 char * start;
00089 char * end;
00090 };
00091
00092
00093 #define X_NONE 0
00094 #define X_WHITESPACE 1<<0
00095 #define X_OPENTAG 1<<1
00096 #define X_CLOSETAG 1<<2
00097 #define X_DQUOTE 1<<3
00098 #define X_SQUOTE 1<<4
00099 #define X_EQUAL 1<<5
00100 #define X_SLASH 1<<6
00101
00102 static int
00103 xtag_cin (char c, int char_class)
00104 {
00105 if (char_class & X_WHITESPACE)
00106 if (isspace(c)) return TRUE;
00107
00108 if (char_class & X_OPENTAG)
00109 if (c == '<') return TRUE;
00110
00111 if (char_class & X_CLOSETAG)
00112 if (c == '>') return TRUE;
00113
00114 if (char_class & X_DQUOTE)
00115 if (c == '"') return TRUE;
00116
00117 if (char_class & X_SQUOTE)
00118 if (c == '\'') return TRUE;
00119
00120 if (char_class & X_EQUAL)
00121 if (c == '=') return TRUE;
00122
00123 if (char_class & X_SLASH)
00124 if (c == '/') return TRUE;
00125
00126 return FALSE;
00127 }
00128
00129 static int
00130 xtag_index (XTagParser * parser, int char_class)
00131 {
00132 char * s;
00133 int i;
00134
00135 s = parser->start;
00136
00137 for (i = 0; s[i] && s != parser->end; i++) {
00138 if (xtag_cin(s[i], char_class)) return i;
00139 }
00140
00141 return -1;
00142 }
00143
00144 static void
00145 xtag_skip_over (XTagParser * parser, int char_class)
00146 {
00147 char * s;
00148 int i;
00149
00150 if (!parser->valid) return;
00151
00152 s = (char *)parser->start;
00153
00154 for (i = 0; s[i] && s != parser->end; i++) {
00155 if (!xtag_cin(s[i], char_class)) {
00156 parser->start = &s[i];
00157 return;
00158 }
00159 }
00160
00161 return;
00162 }
00163
00164 static void
00165 xtag_skip_whitespace (XTagParser * parser)
00166 {
00167 xtag_skip_over (parser, X_WHITESPACE);
00168 }
00169
00170 #if 0
00171 static void
00172 xtag_skip_to (XTagParser * parser, int char_class)
00173 {
00174 char * s;
00175 int i;
00176
00177 if (!parser->valid) return;
00178
00179 s = (char *)parser->start;
00180
00181 for (i = 0; s[i] && s != parser->end; i++) {
00182 if (xtag_cin(s[i], char_class)) {
00183 parser->start = &s[i];
00184 return;
00185 }
00186 }
00187
00188 return;
00189 }
00190 #endif
00191
00192 static char *
00193 xtag_slurp_to (XTagParser * parser, int good_end, int bad_end)
00194 {
00195 char * s, * ret;
00196 int xi;
00197
00198 if (!parser->valid) return NULL;
00199
00200 s = parser->start;
00201
00202 xi = xtag_index (parser, good_end | bad_end);
00203
00204 if (xi > 0 && xtag_cin (s[xi], good_end)) {
00205 ret = malloc ((xi+1) * sizeof(char));
00206 strncpy (ret, s, xi);
00207 ret[xi] = '\0';
00208 parser->start = &s[xi];
00209 return ret;
00210 }
00211
00212 return NULL;
00213 }
00214
00215 static int
00216 xtag_assert_and_pass (XTagParser * parser, int char_class)
00217 {
00218 char * s;
00219
00220 if (!parser->valid) return FALSE;
00221
00222 s = parser->start;
00223
00224 if (!xtag_cin (s[0], char_class)) {
00225 parser->valid = FALSE;
00226 return FALSE;
00227 }
00228
00229 parser->start = &s[1];
00230
00231 return TRUE;
00232 }
00233
00234 static char *
00235 xtag_slurp_quoted (XTagParser * parser)
00236 {
00237 char * s, * ret;
00238 int quote = X_DQUOTE;
00239 int xi;
00240
00241 if (!parser->valid) return NULL;
00242
00243 xtag_skip_whitespace (parser);
00244
00245 s = parser->start;
00246
00247 if (xtag_cin (s[0], X_SQUOTE)) quote = X_SQUOTE;
00248
00249 if (!xtag_assert_and_pass (parser, quote)) return NULL;
00250
00251 s = parser->start;
00252
00253 for (xi = 0; s[xi]; xi++) {
00254 if (xtag_cin (s[xi], quote)) {
00255 if (!(xi > 1 && s[xi-1] == '\\')) break;
00256 }
00257 }
00258
00259 ret = malloc ((xi+1) * sizeof(char));
00260 strncpy (ret, s, xi);
00261 ret[xi] = '\0';
00262 parser->start = &s[xi];
00263
00264 if (!xtag_assert_and_pass (parser, quote)) return NULL;
00265
00266 return ret;
00267 }
00268
00269 static XAttribute *
00270 xtag_parse_attribute (XTagParser * parser)
00271 {
00272 XAttribute * attr;
00273 char * name, * value;
00274 char * s;
00275
00276 if (!parser->valid) return NULL;
00277
00278 xtag_skip_whitespace (parser);
00279
00280 name = xtag_slurp_to (parser, X_WHITESPACE | X_EQUAL, X_SLASH | X_CLOSETAG);
00281
00282 if (name == NULL) return NULL;
00283
00284 xtag_skip_whitespace (parser);
00285 s = parser->start;
00286
00287 if (!xtag_assert_and_pass (parser, X_EQUAL)) {
00288 #ifdef XTAG_DEBUG
00289 printf ("xtag: attr failed EQUAL on <%s>\n", name);
00290 #endif
00291 goto err_free_name;
00292 }
00293
00294 xtag_skip_whitespace (parser);
00295
00296 value = xtag_slurp_quoted (parser);
00297
00298 if (value == NULL) {
00299 #ifdef XTAG_DEBUG
00300 printf ("Got NULL quoted attribute value\n");
00301 #endif
00302 goto err_free_name;
00303 }
00304
00305 attr = malloc (sizeof (*attr));
00306 attr->name = name;
00307 attr->value = value;
00308
00309 return attr;
00310
00311 err_free_name:
00312 free (name);
00313
00314 parser->valid = FALSE;
00315
00316 return NULL;
00317 }
00318
00319 static XTag *
00320 xtag_parse_tag (XTagParser * parser)
00321 {
00322 XTag * tag, * inner;
00323 XAttribute * attr;
00324 char * name;
00325 char * pcdata;
00326 char * s;
00327
00328 if (!parser->valid) return NULL;
00329
00330 if ((pcdata = xtag_slurp_to (parser, X_OPENTAG, X_NONE)) != NULL) {
00331 tag = malloc (sizeof (*tag));
00332 tag->name = NULL;
00333 tag->pcdata = pcdata;
00334 tag->parent = parser->current_tag;
00335 tag->attributes = NULL;
00336 tag->children = NULL;
00337 tag->current_child = NULL;
00338
00339 return tag;
00340 }
00341
00342 s = parser->start;
00343
00344
00345 if (xtag_cin (s[0], X_OPENTAG) && xtag_cin (s[1], X_SLASH))
00346 return NULL;
00347
00348 if (!xtag_assert_and_pass (parser, X_OPENTAG)) return NULL;
00349
00350 name = xtag_slurp_to (parser, X_WHITESPACE | X_SLASH | X_CLOSETAG, X_NONE);
00351
00352 if (name == NULL) return NULL;
00353
00354 #ifdef XTAG_DEBUG
00355 printf ("<%s ...\n", name);
00356 #endif
00357
00358 tag = malloc (sizeof (*tag));
00359 tag->name = name;
00360 tag->pcdata = NULL;
00361 tag->parent = parser->current_tag;
00362 tag->attributes = NULL;
00363 tag->children = NULL;
00364 tag->current_child = NULL;
00365
00366 s = parser->start;
00367
00368 if (xtag_cin (s[0], X_WHITESPACE)) {
00369 while ((attr = xtag_parse_attribute (parser)) != NULL) {
00370 tag->attributes = xlist_append (tag->attributes, attr);
00371 }
00372 }
00373
00374 xtag_skip_whitespace (parser);
00375
00376 s = parser->start;
00377
00378 if (xtag_cin (s[0], X_CLOSETAG)) {
00379 parser->current_tag = tag;
00380
00381 xtag_assert_and_pass (parser, X_CLOSETAG);
00382
00383 while ((inner = xtag_parse_tag (parser)) != NULL) {
00384 tag->children = xlist_append (tag->children, inner);
00385 }
00386
00387 xtag_skip_whitespace (parser);
00388
00389 xtag_assert_and_pass (parser, X_OPENTAG);
00390 xtag_assert_and_pass (parser, X_SLASH);
00391 name = xtag_slurp_to (parser, X_WHITESPACE | X_CLOSETAG, X_NONE);
00392 if (name) {
00393 if (name && tag->name && strcmp (name, tag->name)) {
00394 #ifdef XTAG_DEBUG
00395 printf ("got %s expected %s\n", name, tag->name);
00396 #endif
00397 parser->valid = FALSE;
00398 }
00399 free (name);
00400 }
00401
00402 xtag_skip_whitespace (parser);
00403 xtag_assert_and_pass (parser, X_CLOSETAG);
00404
00405 } else {
00406 xtag_assert_and_pass (parser, X_SLASH);
00407 xtag_assert_and_pass (parser, X_CLOSETAG);
00408 }
00409
00410
00411 return tag;
00412 }
00413
00414 XTag *
00415 xtag_free (XTag * xtag)
00416 {
00417 XList * l;
00418 XAttribute * attr;
00419 XTag * child;
00420
00421 if (xtag == NULL) return NULL;
00422
00423 if (xtag->name) free (xtag->name);
00424 if (xtag->pcdata) free (xtag->pcdata);
00425
00426 for (l = xtag->attributes; l; l = l->next) {
00427 if ((attr = (XAttribute *)l->data) != NULL) {
00428 if (attr->name) free (attr->name);
00429 if (attr->value) free (attr->value);
00430 free (attr);
00431 }
00432 }
00433 xlist_free (xtag->attributes);
00434
00435 for (l = xtag->children; l; l = l->next) {
00436 child = (XTag *)l->data;
00437 xtag_free (child);
00438 }
00439 xlist_free (xtag->children);
00440
00441 free (xtag);
00442
00443 return NULL;
00444 }
00445
00446 XTag *
00447 xtag_new_parse (const char * s, int n, int* ErrorOffset)
00448 {
00449 XTagParser parser;
00450 XTag * tag, * ttag, * wrapper;
00451
00452 parser.valid = TRUE;
00453 parser.current_tag = NULL;
00454 parser.start = (char *)s;
00455
00456 if (n == -1)
00457 parser.end = NULL;
00458 else if (n == 0)
00459 return NULL;
00460 else
00461 parser.end = (char *)&s[n];
00462
00463 tag = xtag_parse_tag (&parser);
00464
00465 if (!parser.valid) {
00466 xtag_free (tag);
00467 *ErrorOffset = (int)(parser.start - s);
00468 return NULL;
00469 }
00470
00471 if ((ttag = xtag_parse_tag (&parser)) != NULL) {
00472
00473 if (!parser.valid) {
00474 xtag_free (ttag);
00475 *ErrorOffset = (int)(parser.start - s);
00476 return tag;
00477 }
00478
00479 wrapper = malloc (sizeof (XTag));
00480 wrapper->name = NULL;
00481 wrapper->pcdata = NULL;
00482 wrapper->parent = NULL;
00483 wrapper->attributes = NULL;
00484 wrapper->children = NULL;
00485 wrapper->current_child = NULL;
00486
00487 wrapper->children = xlist_append (wrapper->children, tag);
00488 wrapper->children = xlist_append (wrapper->children, ttag);
00489
00490 while ((ttag = xtag_parse_tag (&parser)) != NULL) {
00491
00492 if (!parser.valid) {
00493 xtag_free (ttag);
00494 *ErrorOffset = (int)(parser.start - s);
00495 return wrapper;
00496 }
00497
00498 wrapper->children = xlist_append (wrapper->children, ttag);
00499 }
00500
00501 *ErrorOffset = (int)(parser.start - s);
00502 return wrapper;
00503 }
00504
00505 *ErrorOffset = (int)(parser.start - s);
00506 return tag;
00507 }
00508
00509 char *
00510 xtag_get_name (XTag * xtag)
00511 {
00512 return xtag ? xtag->name : NULL;
00513 }
00514
00515 char *
00516 xtag_get_pcdata (XTag * xtag)
00517 {
00518 XList * l;
00519 XTag * child;
00520
00521 if (xtag == NULL) return NULL;
00522
00523 for (l = xtag->children; l; l = l->next) {
00524 child = (XTag *)l->data;
00525 if (child->pcdata != NULL) {
00526 return child->pcdata;
00527 }
00528 }
00529
00530 return NULL;
00531 }
00532
00533 char *
00534 xtag_get_attribute (XTag * xtag, char * attribute)
00535 {
00536 XList * l;
00537 XAttribute * attr;
00538
00539 if (xtag == NULL) return NULL;
00540
00541 for (l = xtag->attributes; l; l = l->next) {
00542 if ((attr = (XAttribute *)l->data) != NULL) {
00543 if (attr->name && attribute && !strcmp (attr->name, attribute))
00544 return attr->value;
00545 }
00546 }
00547
00548 return NULL;
00549 }
00550
00551 XTag *
00552 xtag_first_child (XTag * xtag, char * name)
00553 {
00554 XList * l;
00555 XTag * child;
00556
00557 if (xtag == NULL) return NULL;
00558
00559 if ((l = xtag->children) == NULL) return NULL;
00560
00561 if (name == NULL) {
00562 xtag->current_child = l;
00563 return (XTag *)l->data;
00564 }
00565
00566 for (; l; l = l->next) {
00567 child = (XTag *)l->data;
00568
00569 if (child->name && name && !strcmp(child->name, name)) {
00570 xtag->current_child = l;
00571 return child;
00572 }
00573 }
00574
00575 xtag->current_child = NULL;
00576
00577 return NULL;
00578 }
00579
00580 XTag *
00581 xtag_next_child (XTag * xtag, char * name)
00582 {
00583 XList * l;
00584 XTag * child;
00585
00586 if (xtag == NULL) return NULL;
00587
00588 if ((l = xtag->current_child) == NULL)
00589 return xtag_first_child (xtag, name);
00590
00591 if ((l = l->next) == NULL)
00592 return NULL;
00593
00594 if (name == NULL) {
00595 xtag->current_child = l;
00596 return (XTag *)l->data;
00597 }
00598
00599 for (; l; l = l->next) {
00600 child = (XTag *)l->data;
00601
00602 if (child->name && name && !strcmp(child->name, name)) {
00603 xtag->current_child = l;
00604 return child;
00605 }
00606 }
00607
00608 xtag->current_child = NULL;
00609
00610 return NULL;
00611 }
00612
00613
00614
00615
00616
00617
00618
00619 static int
00620 xtag_snprints (char * buf, int n, ...)
00621 {
00622 va_list ap;
00623 char * s;
00624 int len, to_copy, total = 0;
00625
00626 va_start (ap, n);
00627
00628 for (s = va_arg (ap, char *); s; s = va_arg (ap, char *)) {
00629 len = (int) strlen (s);
00630
00631 if ((to_copy = MIN (n, len)) > 0) {
00632 memcpy (buf, s, to_copy);
00633 buf += to_copy;
00634 n -= to_copy;
00635 }
00636
00637 total += len;
00638 }
00639
00640 va_end (ap);
00641
00642 return total;
00643 }
00644
00645 int
00646 xtag_snprint (char * buf, int n, XTag * xtag)
00647 {
00648 int nn, written = 0;
00649 XList * l;
00650 XAttribute * attr;
00651 XTag * child;
00652
00653 #define FORWARD(N) \
00654 buf += MIN (n, N); \
00655 n = MAX (n-N, 0); \
00656 written += N;
00657
00658 if (xtag == NULL) {
00659 if (n > 0) buf[0] = '\0';
00660 return 0;
00661 }
00662
00663 if (xtag->pcdata) {
00664 nn = xtag_snprints (buf, n, xtag->pcdata, NULL);
00665 FORWARD(nn);
00666
00667 return written;
00668 }
00669
00670 if (xtag->name) {
00671 nn = xtag_snprints (buf, n, "<", xtag->name, NULL);
00672 FORWARD(nn);
00673
00674 for (l = xtag->attributes; l; l = l->next) {
00675 attr = (XAttribute *)l->data;
00676
00677 nn = xtag_snprints (buf, n, " ", attr->name, "=\"", attr->value, "\"",
00678 NULL);
00679 FORWARD(nn);
00680 }
00681
00682 if (xtag->children == NULL) {
00683 nn = xtag_snprints (buf, n, "/>", NULL);
00684 FORWARD(nn);
00685
00686 return written;
00687 }
00688
00689 nn = xtag_snprints (buf, n, ">", NULL);
00690 FORWARD(nn);
00691 }
00692
00693 for (l = xtag->children; l; l = l->next) {
00694 child = (XTag *)l->data;
00695
00696 nn = xtag_snprint (buf, n, child);
00697 FORWARD(nn);
00698 }
00699
00700 if (xtag->name) {
00701 nn = xtag_snprints (buf, n, "</", xtag->name, ">", NULL);
00702 FORWARD(nn);
00703 }
00704
00705 return written;
00706 }
00707