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 }