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 #include "libts.h"
00030
00031 #include "InkXml.h"
00032
00033
00034
00035
00036
00037 InkXmlAttr::InkXmlAttr(const char *tag, const char *value)
00038 {
00039 m_tag = ats_strdup(tag);
00040 m_value = ats_strdup(value);
00041 }
00042
00043 InkXmlAttr::~InkXmlAttr()
00044 {
00045 ats_free(m_tag);
00046 ats_free(m_value);
00047 }
00048
00049 void
00050 InkXmlAttr::display(FILE * fd)
00051 {
00052 fprintf(fd, " <%s,%s>\n", m_tag, m_value);
00053 }
00054
00055
00056
00057
00058
00059 InkXmlObject::InkXmlObject(const char *object_name, bool dup_attrs_allowed)
00060 {
00061 m_object_name = ats_strdup(object_name);
00062 m_dup_attrs_allowed = dup_attrs_allowed;
00063 }
00064
00065 InkXmlObject::~InkXmlObject()
00066 {
00067 ats_free(m_object_name);
00068 clear_tags();
00069 }
00070
00071 void
00072 InkXmlObject::clear_tags()
00073 {
00074 InkXmlAttr *attr;
00075 while ((attr = m_tags.dequeue())) {
00076 delete attr;
00077 }
00078 }
00079
00080 int
00081 InkXmlObject::add_tag(const char *tag, const char *value)
00082 {
00083 ink_assert(tag != NULL);
00084 ink_assert(value != NULL);
00085
00086 InkXmlAttr *attr = new InkXmlAttr(tag, value);
00087 return add_attr(attr);
00088 }
00089
00090 int
00091 InkXmlObject::add_attr(InkXmlAttr * attr)
00092 {
00093 ink_assert(attr != NULL);
00094
00095 if (!m_dup_attrs_allowed) {
00096 for (InkXmlAttr * a = first(); a; a = next(a)) {
00097 if (!strcmp(a->tag(), attr->tag())) {
00098 Debug("xml", "tag %s already exists & dups not allowed", attr->tag());
00099 return -1;
00100 }
00101 }
00102 }
00103 m_tags.enqueue(attr);
00104 return 0;
00105 }
00106
00107 char *
00108 InkXmlObject::tag_value(const char *tag_name)
00109 {
00110 ink_assert(tag_name != NULL);
00111
00112 for (InkXmlAttr * a = first(); a; a = next(a)) {
00113 if (!strcmp(a->tag(), tag_name)) {
00114 return a->value();
00115 }
00116 }
00117 return NULL;
00118 }
00119
00120 void
00121 InkXmlObject::display(FILE * fd)
00122 {
00123 fprintf(fd, "<%s>\n", m_object_name);
00124 for (InkXmlAttr * a = first(); a; a = next(a)) {
00125 a->display(fd);
00126 }
00127 }
00128
00129
00130
00131
00132
00133 InkXmlConfigFile::InkXmlConfigFile(const char *config_file):
00134 m_line(0),
00135 m_col(0)
00136 {
00137 m_config_file = ats_strdup(config_file);
00138 }
00139
00140 InkXmlConfigFile::~InkXmlConfigFile()
00141 {
00142 ats_free(m_config_file);
00143 clear_objects();
00144 }
00145
00146 void
00147 InkXmlConfigFile::clear_objects()
00148 {
00149 InkXmlObject *obj;
00150 while ((obj = m_objects.dequeue())) {
00151 delete obj;
00152 }
00153 }
00154
00155
00156 int
00157 InkXmlConfigFile::parse(int fd)
00158 {
00159 ink_assert(fd >= 0);
00160 Debug("log", "Parsing XML config info from memory..");
00161
00162 m_line = 1;
00163 m_col = 0;
00164
00165 InkXmlObject *obj;
00166 while ((obj = get_next_xml_object(fd)) != NULL) {
00167 Debug("log", "Adding XML object <%s>", obj->object_name());
00168 add_object(obj);
00169 }
00170
00171 return 0;
00172 }
00173
00174
00175
00176 int
00177 InkXmlConfigFile::parse()
00178 {
00179 ink_assert(m_config_file != NULL);
00180 Debug("xml", "Parsing XML config file %s ...", m_config_file);
00181
00182 int fd =::open(m_config_file, O_RDONLY);
00183 if (fd < 0) {
00184 Debug("xml", "Error opening %s: %d, %s", m_config_file, fd, strerror(errno));
00185 return -1;
00186 }
00187
00188 m_line = 1;
00189 m_col = 0;
00190
00191 InkXmlObject *obj;
00192 while ((obj = get_next_xml_object(fd)) != NULL) {
00193 Debug("xml", "Adding XML object <%s>", obj->object_name());
00194 add_object(obj);
00195 }
00196
00197 ::close(fd);
00198 return 0;
00199 }
00200
00201 InkXmlObject *
00202 InkXmlConfigFile::find_object(const char *object_name)
00203 {
00204 for (InkXmlObject * obj = first(); obj; obj = next(obj)) {
00205 if (!strcmp(object_name, obj->object_name())) {
00206 return obj;
00207 }
00208 }
00209 return NULL;
00210 }
00211
00212 void
00213 InkXmlConfigFile::display(FILE * fd)
00214 {
00215 size_t i;
00216
00217 fprintf(fd, "\n");
00218 for (i = 0; i < strlen(m_config_file) + 13; i++)
00219 fputc('-', fd);
00220 fprintf(fd, "\nConfig File: %s\n", m_config_file);
00221 for (i = 0; i < strlen(m_config_file) + 13; i++)
00222 fputc('-', fd);
00223 fprintf(fd, "\n");
00224 for (InkXmlObject * obj = first(); obj; obj = next(obj)) {
00225 obj->display(fd);
00226 fprintf(fd, "\n");
00227 }
00228 }
00229
00230 void
00231 InkXmlConfigFile::add_object(InkXmlObject * object)
00232 {
00233 ink_assert(object != NULL);
00234 m_objects.enqueue(object);
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244 InkXmlObject *
00245 InkXmlConfigFile::get_next_xml_object(int fd)
00246 {
00247 ink_assert(fd >= 0);
00248
00249 char token;
00250 bool start_object = false;
00251
00252 while ((token = next_token(fd)) != EOF) {
00253 switch (token) {
00254
00255 case '<':
00256 start_object = true;
00257 break;
00258
00259 case '!':
00260 if (!start_object)
00261 return parse_error();
00262 if ((token = scan_comment(fd)) == EOF) {
00263 return NULL;
00264 }
00265 Debug("xml", "comment scanned");
00266 start_object = false;
00267 break;
00268
00269 default:
00270 if (!start_object)
00271 return parse_error();
00272 return scan_object(fd, token);
00273 }
00274 }
00275 return NULL;
00276 }
00277
00278 InkXmlObject *
00279 InkXmlConfigFile::parse_error()
00280 {
00281 Debug("xml", "Invalid XML tag, line %u, col %u", m_line, m_col);
00282 return NULL;
00283 }
00284
00285 #define BAD_ATTR ((InkXmlAttr*)1)
00286
00287 InkXmlObject *
00288 InkXmlConfigFile::scan_object(int fd, char token)
00289 {
00290
00291
00292
00293 const int max_ident_len = 2048;
00294 char ident[max_ident_len];
00295 int ident_len = 0;
00296
00297 while (token != '>' && ident_len < max_ident_len) {
00298 ident[ident_len++] = token;
00299 token = next_token(fd);
00300 if (token == EOF)
00301 return parse_error();
00302 }
00303 if (!ident_len || ident_len >= max_ident_len) {
00304 return parse_error();
00305 }
00306
00307 ident[ident_len] = 0;
00308 InkXmlObject *obj = new InkXmlObject(ident);
00309 ink_assert(obj != NULL);
00310
00311 InkXmlAttr *attr;
00312 while ((attr = scan_attr(fd, ident)) != NULL) {
00313 if (attr == BAD_ATTR) {
00314 delete obj;
00315 return parse_error();
00316 }
00317 obj->add_attr(attr);
00318 }
00319
00320 return obj;
00321 }
00322
00323 InkXmlAttr *
00324 InkXmlConfigFile::scan_attr(int fd, const char *id)
00325 {
00326
00327
00328
00329
00330
00331
00332 char token, prev, next;
00333 const int buf_size = 2048;
00334 char name[buf_size];
00335 char value[buf_size];
00336 char ident[buf_size];
00337 char *write_to = NULL;
00338 int write_len = 0;
00339 bool start_attr = false;
00340 bool in_quotes = false;
00341 InkXmlAttr *attr = NULL;
00342
00343 prev = next = 0;
00344 while ((token = next_token(fd, !in_quotes)) != EOF) {
00345 switch (token) {
00346 case '<':
00347 if (in_quotes && write_to) {
00348 if (write_len >= buf_size)
00349 return BAD_ATTR;
00350 write_to[write_len++] = token;
00351 break;
00352 }
00353 start_attr = true;
00354 write_to = name;
00355 write_len = 0;
00356 break;
00357
00358 case '=':
00359 if (in_quotes && write_to) {
00360 if (write_len >= buf_size)
00361 return BAD_ATTR;
00362 write_to[write_len++] = token;
00363 break;
00364 }
00365 if (!start_attr)
00366 return BAD_ATTR;
00367 write_to[write_len] = 0;
00368 write_to = value;
00369 write_len = 0;
00370 break;
00371
00372 case '"':
00373 if (in_quotes) {
00374 if (prev == '\\') {
00375
00376
00377 write_to[write_len - 1] = token;
00378 break;
00379 }
00380 }
00381 in_quotes = !in_quotes;
00382 break;
00383
00384 case '/':
00385 if (in_quotes && write_to) {
00386 if (write_len >= buf_size)
00387 return BAD_ATTR;
00388 write_to[write_len++] = token;
00389 break;
00390 }
00391 if (!start_attr)
00392 return BAD_ATTR;
00393 if (prev == '<') {
00394 write_len = 0;
00395 token = next_token(fd, !in_quotes);
00396 while (token != '>' && write_len < buf_size) {
00397 ident[write_len++] = token;
00398 token = next_token(fd, !in_quotes);
00399 if (token == EOF)
00400 return BAD_ATTR;
00401 }
00402 if (!write_len || write_len >= buf_size) {
00403 return BAD_ATTR;
00404 }
00405 ident[write_len] = 0;
00406 if (strcmp(ident, id) != 0)
00407 return BAD_ATTR;
00408 return NULL;
00409 }
00410
00411 next = next_token(fd, !in_quotes);
00412 if (next != '>')
00413 return BAD_ATTR;
00414 write_to[write_len] = 0;
00415 attr = new InkXmlAttr(name, value);
00416 ink_assert(attr != NULL);
00417 return attr;
00418
00419 case '>':
00420 if (in_quotes && write_to) {
00421 if (write_len >= buf_size)
00422 return BAD_ATTR;
00423 write_to[write_len++] = token;
00424 break;
00425 }
00426
00427
00428 return BAD_ATTR;
00429
00430 default:
00431 if (!start_attr)
00432 return BAD_ATTR;
00433 if (write_len >= buf_size)
00434 return BAD_ATTR;
00435 write_to[write_len++] = token;
00436 break;
00437 }
00438 prev = token;
00439 }
00440 return BAD_ATTR;
00441 }
00442
00443 char
00444 InkXmlConfigFile::next_token(int fd, bool eat_whitespace)
00445 {
00446 char ch;
00447 while (read(fd, &ch, 1) == 1) {
00448 if (ch == '\n') {
00449 m_line++;
00450 m_col = 0;
00451 continue;
00452 }
00453 m_col++;
00454 if (eat_whitespace && ParseRules::is_space(ch))
00455 continue;
00456 return ch;
00457 }
00458 return EOF;
00459 }
00460
00461 char
00462 InkXmlConfigFile::scan_comment(int fd)
00463 {
00464
00465
00466
00467 int lt_stack = 1;
00468 char token;
00469 while ((token = next_token(fd)) != EOF) {
00470 switch (token) {
00471 case '<':
00472 lt_stack++;
00473 break;
00474 case '>':
00475 lt_stack--;
00476 if (lt_stack == 0) {
00477 return token;
00478 }
00479 break;
00480 default:
00481 break;
00482 }
00483 }
00484 return EOF;
00485 }