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