File indexing completed on 2024-04-28 15:35:13
0001 /*************************************************************************** 0002 * Copyright (C) 2004 by Tomas Mecir * 0003 * kmuddy@kmuddy.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU Library General Public License as * 0007 * published by the Free Software Foundation; either version 2 of the * 0008 * License, or (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU Library General Public License for more details. * 0014 ***************************************************************************/ 0015 0016 #include "celementmanager.h" 0017 0018 #include "centitymanager.h" 0019 #include "cmxpcolors.h" 0020 #include "cmxpparser.h" 0021 #include "cmxpstate.h" 0022 #include "cresulthandler.h" 0023 #include "stringops.h" 0024 0025 #include <stdlib.h> 0026 0027 cElementManager::cElementManager (cMXPState *st, cResultHandler *res, cEntityManager *enm) 0028 { 0029 state = st; 0030 results = res; 0031 entities = enm; 0032 0033 paramexpander = new cEntityManager (true); 0034 parser = new cMXPParser; 0035 0036 reset (); 0037 0038 createInternalElements (); 0039 } 0040 0041 cElementManager::~cElementManager () 0042 { 0043 delete paramexpander; 0044 paramexpander = 0; 0045 delete parser; 0046 parser = 0; 0047 0048 removeAll (); 0049 0050 //internal elements 0051 map<string, sInternalElement *>::iterator it; 0052 for (it = ielements.begin(); it != ielements.end(); ++it) 0053 { 0054 it->second->attlist.clear (); 0055 it->second->attdefault.clear (); 0056 delete it->second; 0057 } 0058 ielements.clear (); 0059 aliases.clear (); 0060 } 0061 0062 void cElementManager::reset () 0063 { 0064 lastLineTag = 0; 0065 removeAll (); 0066 } 0067 0068 void cElementManager::assignMXPState (cMXPState *st) 0069 { 0070 state = st; 0071 } 0072 0073 void cElementManager::createInternalElements () 0074 { 0075 //the list doesn't contain information on whether an argument is required or not 0076 //processor of the tag implements this functionality 0077 0078 //create all internal elements 0079 sInternalElement *e; 0080 0081 //!element 0082 e = new sInternalElement; 0083 e->empty = true; 0084 e->open = false; 0085 e->attlist.push_back ("name"); //this name is not in the spec! 0086 e->attlist.push_back ("definition"); //this name is not in the spec! 0087 e->attlist.push_back ("att"); 0088 e->attlist.push_back ("tag"); 0089 e->attlist.push_back ("flag"); 0090 e->attlist.push_back ("open"); 0091 e->attlist.push_back ("delete"); 0092 e->attlist.push_back ("empty"); 0093 e->attdefault["open"] = ""; //flags 0094 e->attdefault["delete"] = ""; 0095 e->attdefault["empty"] = ""; 0096 ielements["!element"] = e; 0097 0098 //!attlist 0099 e = new sInternalElement; 0100 e->empty = true; 0101 e->open = false; 0102 e->attlist.push_back ("name"); //this name is not in the spec! 0103 e->attlist.push_back ("att"); 0104 ielements["!attlist"] = e; 0105 0106 //!entity 0107 e = new sInternalElement; 0108 e->empty = true; 0109 e->open = false; 0110 e->attlist.push_back ("name"); //this name is not in the spec! 0111 e->attlist.push_back ("value"); //this name is not in the spec! 0112 e->attlist.push_back ("desc"); 0113 e->attlist.push_back ("private"); 0114 e->attlist.push_back ("publish"); 0115 e->attlist.push_back ("add"); 0116 e->attlist.push_back ("delete"); 0117 e->attlist.push_back ("remove"); 0118 e->attdefault["private"] = ""; //flags 0119 e->attdefault["publish"] = ""; 0120 e->attdefault["delete"] = ""; 0121 e->attdefault["add"] = ""; 0122 e->attdefault["remove"] = ""; 0123 ielements["!entity"] = e; 0124 0125 //var 0126 e = new sInternalElement; 0127 e->empty = false; 0128 e->open = false; 0129 e->attlist.push_back ("name"); //this name is not in the spec! 0130 e->attlist.push_back ("desc"); 0131 e->attlist.push_back ("private"); 0132 e->attlist.push_back ("publish"); 0133 e->attlist.push_back ("add"); 0134 e->attlist.push_back ("delete"); 0135 e->attlist.push_back ("remove"); 0136 e->attdefault["private"] = ""; //flags 0137 e->attdefault["publish"] = ""; 0138 e->attdefault["delete"] = ""; 0139 e->attdefault["add"] = ""; 0140 e->attdefault["remove"] = ""; 0141 ielements["var"] = e; 0142 0143 //b 0144 e = new sInternalElement; 0145 e->empty = false; 0146 e->open = true; 0147 ielements["b"] = e; 0148 0149 //i 0150 e = new sInternalElement; 0151 e->empty = false; 0152 e->open = true; 0153 ielements["i"] = e; 0154 0155 //u 0156 e = new sInternalElement; 0157 e->empty = false; 0158 e->open = true; 0159 ielements["u"] = e; 0160 0161 //s 0162 e = new sInternalElement; 0163 e->empty = false; 0164 e->open = true; 0165 ielements["s"] = e; 0166 0167 //c 0168 e = new sInternalElement; 0169 e->empty = false; 0170 e->open = true; 0171 e->attlist.push_back ("fore"); 0172 e->attlist.push_back ("back"); 0173 ielements["c"] = e; 0174 0175 //h 0176 e = new sInternalElement; 0177 e->empty = false; 0178 e->open = true; 0179 ielements["h"] = e; 0180 0181 //font 0182 e = new sInternalElement; 0183 e->empty = false; 0184 e->open = true; 0185 e->attlist.push_back ("face"); 0186 e->attlist.push_back ("size"); 0187 e->attlist.push_back ("color"); 0188 e->attlist.push_back ("back"); 0189 ielements["font"] = e; 0190 0191 //nobr 0192 e = new sInternalElement; 0193 e->empty = true; 0194 e->open = false; 0195 ielements["nobr"] = e; 0196 0197 //p 0198 e = new sInternalElement; 0199 e->empty = false; 0200 e->open = false; 0201 ielements["p"] = e; 0202 0203 //br 0204 e = new sInternalElement; 0205 e->empty = true; 0206 e->open = false; 0207 ielements["br"] = e; 0208 0209 //sbr 0210 e = new sInternalElement; 0211 e->empty = true; 0212 e->open = false; 0213 ielements["sbr"] = e; 0214 0215 //a 0216 e = new sInternalElement; 0217 e->empty = false; 0218 e->open = false; 0219 e->attlist.push_back ("href"); 0220 e->attlist.push_back ("hint"); 0221 e->attlist.push_back ("expire"); 0222 ielements["a"] = e; 0223 0224 //send 0225 e = new sInternalElement; 0226 e->empty = false; 0227 e->open = false; 0228 e->attlist.push_back ("href"); 0229 e->attlist.push_back ("hint"); 0230 e->attlist.push_back ("prompt"); 0231 e->attlist.push_back ("expire"); 0232 e->attdefault["prompt"] = ""; //flags 0233 ielements["send"] = e; 0234 0235 //expire 0236 e = new sInternalElement; 0237 e->empty = true; 0238 e->open = false; 0239 e->attlist.push_back ("name"); //this name is not in the spec! 0240 ielements["expire"] = e; 0241 0242 //version 0243 e = new sInternalElement; 0244 e->empty = true; 0245 e->open = false; 0246 ielements["version"] = e; 0247 0248 //support 0249 e = new sInternalElement; 0250 e->empty = true; 0251 e->open = false; 0252 ielements["support"] = e; 0253 0254 //h1 0255 e = new sInternalElement; 0256 e->empty = false; 0257 e->open = false; 0258 ielements["h1"] = e; 0259 0260 //h2 0261 e = new sInternalElement; 0262 e->empty = false; 0263 e->open = false; 0264 ielements["h2"] = e; 0265 0266 //h3 0267 e = new sInternalElement; 0268 e->empty = false; 0269 e->open = false; 0270 ielements["h3"] = e; 0271 0272 //h4 0273 e = new sInternalElement; 0274 e->empty = false; 0275 e->open = false; 0276 ielements["h4"] = e; 0277 0278 //h5 0279 e = new sInternalElement; 0280 e->empty = false; 0281 e->open = false; 0282 ielements["h5"] = e; 0283 0284 //h6 0285 e = new sInternalElement; 0286 e->empty = false; 0287 e->open = false; 0288 ielements["h6"] = e; 0289 0290 //hr 0291 e = new sInternalElement; 0292 e->empty = true; 0293 e->open = false; 0294 ielements["hr"] = e; 0295 0296 //small 0297 e = new sInternalElement; 0298 e->empty = false; 0299 e->open = false; 0300 ielements["small"] = e; 0301 0302 //tt 0303 e = new sInternalElement; 0304 e->empty = false; 0305 e->open = false; 0306 ielements["tt"] = e; 0307 0308 //sound 0309 e = new sInternalElement; 0310 e->empty = true; 0311 e->open = false; 0312 e->attlist.push_back ("fname"); 0313 e->attlist.push_back ("v"); 0314 e->attlist.push_back ("l"); 0315 e->attlist.push_back ("p"); 0316 e->attlist.push_back ("t"); 0317 e->attlist.push_back ("u"); 0318 e->attdefault["v"] = "100"; 0319 e->attdefault["l"] = "1"; 0320 e->attdefault["p"] = "50"; 0321 ielements["sound"] = e; 0322 0323 //music 0324 e = new sInternalElement; 0325 e->empty = true; 0326 e->open = false; 0327 e->attlist.push_back ("fname"); 0328 e->attlist.push_back ("v"); 0329 e->attlist.push_back ("l"); 0330 e->attlist.push_back ("c"); 0331 e->attlist.push_back ("t"); 0332 e->attlist.push_back ("u"); 0333 e->attdefault["v"] = "100"; 0334 e->attdefault["l"] = "1"; 0335 e->attdefault["c"] = "1"; 0336 ielements["music"] = e; 0337 0338 //gauge 0339 e = new sInternalElement; 0340 e->empty = true; 0341 e->open = false; 0342 e->attlist.push_back ("entity"); //this name is not in the spec! 0343 e->attlist.push_back ("max"); 0344 e->attlist.push_back ("caption"); 0345 e->attlist.push_back ("color"); 0346 ielements["gauge"] = e; 0347 0348 //stat 0349 e = new sInternalElement; 0350 e->empty = true; 0351 e->open = false; 0352 e->attlist.push_back ("entity"); //this name is not in the spec! 0353 e->attlist.push_back ("max"); 0354 e->attlist.push_back ("caption"); 0355 ielements["stat"] = e; 0356 0357 //frame 0358 e = new sInternalElement; 0359 e->empty = true; 0360 e->open = false; 0361 e->attlist.push_back ("name"); 0362 e->attlist.push_back ("action"); 0363 e->attlist.push_back ("title"); 0364 e->attlist.push_back ("internal"); 0365 e->attlist.push_back ("align"); 0366 e->attlist.push_back ("left"); 0367 e->attlist.push_back ("top"); 0368 e->attlist.push_back ("width"); 0369 e->attlist.push_back ("height"); 0370 e->attlist.push_back ("scrolling"); 0371 e->attlist.push_back ("floating"); 0372 e->attdefault["action"] = "open"; 0373 e->attdefault["align"] = "top"; 0374 e->attdefault["left"] = "0"; 0375 e->attdefault["top"] = "0"; 0376 e->attdefault["internal"] = ""; //flags 0377 e->attdefault["scrolling"] = ""; 0378 e->attdefault["floating"] = ""; 0379 ielements["frame"] = e; 0380 0381 //dest 0382 e = new sInternalElement; 0383 e->empty = false; 0384 e->open = false; 0385 e->attlist.push_back ("name"); //this name is not in the spec! 0386 e->attlist.push_back ("x"); 0387 e->attlist.push_back ("y"); 0388 e->attlist.push_back ("eol"); 0389 e->attlist.push_back ("eof"); 0390 e->attdefault["eol"] = ""; //flags 0391 e->attdefault["eof"] = ""; 0392 ielements["dest"] = e; 0393 0394 //relocate 0395 e = new sInternalElement; 0396 e->empty = true; 0397 e->open = false; 0398 e->attlist.push_back ("name"); //this name is not in the spec! 0399 e->attlist.push_back ("port"); //this name is not in the spec! 0400 ielements["relocate"] = e; 0401 0402 //user 0403 e = new sInternalElement; 0404 e->empty = true; 0405 e->open = false; 0406 ielements["user"] = e; 0407 0408 //password 0409 e = new sInternalElement; 0410 e->empty = true; 0411 e->open = false; 0412 ielements["password"] = e; 0413 0414 //image 0415 e = new sInternalElement; 0416 e->empty = true; 0417 e->open = false; 0418 e->attlist.push_back ("fname"); 0419 e->attlist.push_back ("url"); 0420 e->attlist.push_back ("t"); 0421 e->attlist.push_back ("h"); 0422 e->attlist.push_back ("w"); 0423 e->attlist.push_back ("hspace"); 0424 e->attlist.push_back ("vspace"); 0425 e->attlist.push_back ("align"); 0426 e->attlist.push_back ("ismap"); 0427 e->attdefault["align"] = "top"; 0428 e->attdefault["ismap"] = ""; //flags 0429 ielements["image"] = e; 0430 0431 //filter 0432 e = new sInternalElement; 0433 e->empty = true; 0434 e->open = false; 0435 e->attlist.push_back ("src"); 0436 e->attlist.push_back ("dest"); 0437 e->attlist.push_back ("name"); 0438 ielements["filter"] = e; 0439 0440 //finally, define some aliases for internal elements 0441 aliases["!el"] = "!element"; 0442 aliases["!at"] = "!attlist"; 0443 aliases["!en"] = "!entity"; 0444 aliases["v"] = "var"; 0445 aliases["bold"] = "b"; 0446 aliases["strong"] = "b"; 0447 aliases["italic"] = "i"; 0448 aliases["em"] = "i"; 0449 aliases["underline"] = "u"; 0450 aliases["strikeout"] = "s"; 0451 aliases["high"] = "h"; 0452 aliases["color"] = "c"; 0453 aliases["destination"] = "dest"; 0454 } 0455 0456 bool cElementManager::elementDefined (const string &name) 0457 { 0458 return ((elements.count (name) != 0) || (ielements.count (name) != 0) || 0459 (aliases.count (name) != 0)); 0460 } 0461 0462 bool cElementManager::internalElement (const string &name) 0463 { 0464 return ((ielements.count (name) != 0) || (aliases.count (name) != 0)); 0465 } 0466 0467 bool cElementManager::customElement (const string &name) 0468 { 0469 return (elements.count (name) != 0); 0470 } 0471 0472 bool cElementManager::openElement (const string &name) 0473 { 0474 if (!elementDefined (name)) 0475 return false; 0476 if (internalElement (name)) 0477 { 0478 string n = name; 0479 if (aliases.count (name)) 0480 n = aliases[name]; 0481 return ielements[n]->open; 0482 } 0483 else 0484 return elements[name]->open; 0485 } 0486 0487 bool cElementManager::emptyElement (const string &name) 0488 { 0489 if (!elementDefined (name)) 0490 return false; 0491 if (internalElement (name)) 0492 { 0493 string n = name; 0494 if (aliases.count (name)) 0495 n = aliases[name]; 0496 return ielements[n]->empty; 0497 } 0498 else 0499 return elements[name]->empty; 0500 } 0501 0502 enum tagParserState { 0503 tagBegin, 0504 tagName, 0505 tagParam, 0506 tagParamValue, 0507 tagQuotedParam, 0508 tagAfterQuotedParam, 0509 tagBetweenParams 0510 }; 0511 0512 void cElementManager::gotTag (const string &tag) 0513 { 0514 string tagname; 0515 list<sParam> params; 0516 sParam param; 0517 param.flag = false; 0518 char quote; 0519 tagParserState pstate = tagBegin; 0520 string::const_iterator it; 0521 for (it = tag.begin(); it != tag.end(); ++it) 0522 { 0523 char ch = *it; 0524 0525 //process character 0526 switch (pstate) { 0527 case tagBegin: { 0528 if (ch != ' ') 0529 { 0530 pstate = tagName; 0531 tagname += ch; 0532 } 0533 break; 0534 } 0535 case tagName: { 0536 if (ch == ' ') 0537 pstate = tagBetweenParams; 0538 else 0539 tagname += ch; 0540 break; 0541 } 0542 case tagParam: { 0543 if (ch == '=') 0544 pstate = tagParamValue; 0545 else if (ch == ' ') 0546 { 0547 //one parameter, value only (it could also be a flag, we'll check that later) 0548 param.value = param.name; 0549 param.name = ""; 0550 //add a new parameter :-) 0551 params.push_back (param); 0552 param.value = ""; 0553 pstate = tagBetweenParams; 0554 } 0555 else 0556 param.name += ch; 0557 break; 0558 } 0559 case tagParamValue: { 0560 if (ch == ' ') 0561 { 0562 //add a new parameter :-) 0563 params.push_back (param); 0564 param.name = ""; 0565 param.value = ""; 0566 pstate = tagBetweenParams; 0567 } 0568 else if (param.value.empty() && ((ch == '\'') || (ch == '"'))) 0569 { 0570 pstate = tagQuotedParam; 0571 quote = ch; 0572 } 0573 else 0574 param.value += ch; 0575 break; 0576 } 0577 case tagQuotedParam: { 0578 if (ch == quote) 0579 { 0580 //add a new parameter :-) 0581 params.push_back (param); 0582 param.name = ""; 0583 param.value = ""; 0584 pstate = tagAfterQuotedParam; 0585 } 0586 else 0587 param.value += ch; 0588 break; 0589 } 0590 case tagAfterQuotedParam: { 0591 if (ch == ' ') //ignore everything up to some space... 0592 pstate = tagBetweenParams; 0593 break; 0594 } 0595 case tagBetweenParams: { 0596 if (ch != ' ') 0597 { 0598 if ((ch == '\'') || (ch == '"')) 0599 { 0600 pstate = tagQuotedParam; 0601 param.name = ""; 0602 quote = ch; 0603 } 0604 else 0605 { 0606 pstate = tagParam; 0607 param.name += ch; 0608 } 0609 } 0610 break; 0611 } 0612 }; 0613 } 0614 0615 //last parameter... 0616 switch (pstate) { 0617 case tagBegin: 0618 results->addToList (results->createError ("Received a tag with no body!")); 0619 break; 0620 case tagParam: { 0621 param.value = param.name; 0622 param.name = ""; 0623 params.push_back (param); 0624 } 0625 break; 0626 case tagParamValue: 0627 params.push_back (param); 0628 break; 0629 case tagQuotedParam: 0630 results->addToList (results->createError ("Received tag " + tagname + 0631 " with unfinished quoted parameter!")); 0632 break; 0633 }; 0634 0635 //nothing more to do if the tag has no contents... 0636 if (pstate == tagBegin) return; 0637 0638 //convert tag name to lowercase 0639 tagname = lcase (tagname); 0640 0641 //handle closing tag... 0642 if (tagname[0] == '/') 0643 { 0644 if (!params.empty()) 0645 results->addToList (results->createError ("Received closing tag " + tagname + 0646 " with parametrs!")); 0647 //remove that '/' 0648 tagname.erase (tagname.begin()); 0649 //and call closing tag processing 0650 handleClosingTag (tagname); 0651 return; 0652 } 0653 0654 //convert all parameter names to lower-case 0655 list<sParam>::iterator parit; 0656 for (parit = params.begin(); parit != params.end(); ++parit) 0657 (*parit).name = lcase ((*parit).name); 0658 0659 //now we check the type of the tag and act accordingly 0660 if (!elementDefined (tagname)) 0661 { 0662 params.clear(); 0663 results->addToList (results->createError ("Received undefined tag " + tagname + "!")); 0664 return; 0665 } 0666 0667 mxpMode m = state->getMXPMode (); 0668 //mode can be open or secure; locked mode is not possible here (or we're in a bug) 0669 if (m == openMode) 0670 //open mode - only open tags allowed 0671 if (!openElement (tagname)) 0672 { 0673 params.clear(); 0674 results->addToList (results->createError ("Received secure tag " + tagname + 0675 " in open mode!")); 0676 return; 0677 } 0678 0679 if (internalElement (tagname)) 0680 { 0681 //if the name is an alias for another tag, change the name 0682 if (aliases.count (tagname)) 0683 tagname = aliases[tagname]; 0684 //the <support> tag has to be handled separately :( 0685 if (tagname == "support") 0686 { 0687 processSupport (params); 0688 return; 0689 } 0690 //identify all flags in the tag 0691 identifyFlags (ielements[tagname]->attdefault, params); 0692 //correctly identify all parameters (assign names where necessary) 0693 handleParams (tagname, params, ielements[tagname]->attlist, ielements[tagname]->attdefault); 0694 //separate out all the flags (flags are only valid for internal tags) 0695 list<string> flags; 0696 parit = params.begin(); 0697 while (parit != params.end()) 0698 { 0699 if ((*parit).flag) 0700 { 0701 flags.push_back ((*parit).name); 0702 parit = params.erase (parit); 0703 } 0704 else 0705 ++parit; 0706 } 0707 //okay, parsing done - send the tag for further processing 0708 processInternalTag (tagname, params, flags); 0709 } 0710 else 0711 { 0712 handleParams (tagname, params, elements[tagname]->attlist, elements[tagname]->attdefault); 0713 processCustomTag (tagname, params); 0714 } 0715 0716 params.clear (); 0717 } 0718 0719 void cElementManager::identifyFlags (const map<string, string> &attdefault, 0720 list<sParam> &args) 0721 { 0722 list<sParam>::iterator it; 0723 for (it = args.begin(); it != args.end(); ++it) 0724 if ((*it).name.empty()) 0725 { 0726 string s = lcase ((*it).value); 0727 if ((attdefault.count (s) != 0) && (attdefault.find(s)->second == "")) 0728 { 0729 //this one is a flag 0730 (*it).name = s; 0731 (*it).value = ""; 0732 (*it).flag = true; 0733 } 0734 } 0735 } 0736 0737 void cElementManager::handleParams (const string &tagname, list<sParam> &args, 0738 const list<string> &attlist, const map<string, string> &attdefault) 0739 { 0740 list<string>::const_iterator cur = attlist.begin(); 0741 list<sParam>::iterator it; 0742 for (it = args.begin(); it != args.end(); ++it) 0743 { 0744 //flag? 0745 if ((*it).flag) 0746 { 0747 //only advance parameter iterator 0748 cur++; 0749 } 0750 //not a flag 0751 else 0752 { 0753 //empty name? 0754 if ((*it).name.empty()) 0755 { 0756 //set the parameter name: 0757 0758 //find the correct attribute name, skipping all flags 0759 while (cur != attlist.end()) 0760 { 0761 if ((attdefault.count (*cur) != 0) && (attdefault.find(*cur)->second == "")) //flag 0762 cur++; 0763 else 0764 break; //okay, found the correct parameter 0765 } 0766 if (cur == attlist.end()) //ARGH! Parameter not found :( 0767 { 0768 results->addToList (results->createError ("Received too many parameters for tag " + 0769 tagname + "!")); 0770 continue; //continue with the next parameter... 0771 } 0772 } 0773 //non-empty name? 0774 else 0775 { 0776 //set "cur" to the parameter following the given one 0777 0778 //to speed things up a bit, first look if the iterator is pointing at the right parameter 0779 // (we won't need to traverse the whole list, if it does) 0780 if ((cur == attlist.end()) || ((*it).name != *cur)) 0781 { 0782 list<string>::const_iterator cur2 = cur; //remember old "cur" value 0783 for (cur = attlist.begin(); cur != attlist.end(); ++cur) 0784 if ((*it).name == *cur) 0785 break; 0786 if (cur == attlist.end()) //parameter name not found 0787 { 0788 //restore old iterator value 0789 cur = cur2; 0790 results->addToList (results->createError ("Received unknown parameter " + 0791 (*it).name + " in tag " + tagname + "!")); 0792 //clear name/value to avoid confusion in later stages 0793 (*it).name = ""; 0794 (*it).value = ""; 0795 //proceed with next parameter 0796 continue; 0797 } 0798 //if cur isn't attlist.end(), it's now set to the correct value... 0799 } 0800 } 0801 0802 //things common to all non-flag parameters... 0803 0804 //set parameter name 0805 (*it).name = *cur; 0806 //if parameter value is empty, set it to default value (if any) 0807 if ((*it).value.empty() && (attdefault.count (*cur) != 0)) 0808 (*it).value = attdefault.find(*cur)->second; 0809 //advance parameter iterator 0810 cur++; 0811 } 0812 } 0813 0814 //finally, we add default parameter values to the beginning of the list... these shall get 0815 //overridden by given values, if any (those shall be later in the list) 0816 sParam s; 0817 map<string, string>::const_iterator mit; 0818 for (mit = attdefault.begin(); mit != attdefault.end(); ++mit) 0819 if (mit->second != "") //not a flag 0820 { 0821 s.flag = false; 0822 s.name = mit->first; 0823 s.value = mit->second; 0824 args.push_front (s); 0825 } 0826 } 0827 0828 void cElementManager::gotLineTag (int number) 0829 { 0830 if ((number < 20) || (number > 99)) 0831 { 0832 lastLineTag = 0; 0833 return; 0834 } 0835 if (lineTags.count (number) == 0) 0836 { 0837 lastLineTag = 0; 0838 return; 0839 } 0840 string tag = lineTags[number]; 0841 lastLineTag = number; 0842 //behave as if we've just gotten the appropriate tag 0843 gotTag (tag); 0844 } 0845 0846 void cElementManager::gotNewLine () 0847 { 0848 if ((lastLineTag < 20) || (lastLineTag > 99)) 0849 { 0850 lastLineTag = 0; 0851 return; 0852 } 0853 if (lineTags.count (lastLineTag) == 0) 0854 { 0855 lastLineTag = 0; 0856 return; 0857 } 0858 string tag = lineTags[lastLineTag]; 0859 lastLineTag = 0; 0860 if (emptyElement (tag)) 0861 //no closing tag needed 0862 return; 0863 //okay, send out the appropriate closing tag 0864 handleClosingTag (tag); 0865 } 0866 0867 void cElementManager::handleClosingTag (const string &name) 0868 { 0869 string n = lcase (name); 0870 if (!elementDefined (n)) 0871 { 0872 results->addToList (results->createError ("Received unknown closing tag </" + n + ">!")); 0873 return; 0874 } 0875 if (emptyElement (n)) 0876 { 0877 results->addToList (results->createError ("Received closing tag for tag " + n + 0878 ", which doesn't need a closing tag!")); 0879 return; 0880 } 0881 if (internalElement (n)) 0882 { 0883 //if the name is an alias for another tag, change the name 0884 if (aliases.count (n)) 0885 n = aliases[n]; 0886 state->gotClosingTag (n); 0887 } 0888 else 0889 { 0890 //send closing flag, if needed 0891 if (!elements[n]->flag.empty()) 0892 state->gotFlag (false, elements[n]->flag); 0893 0894 //expand the closing tag... 0895 list<string>::iterator cit; 0896 for (cit = elements[n]->closingseq.begin(); cit != elements[n]->closingseq.end(); ++cit) 0897 handleClosingTag (*cit); 0898 } 0899 } 0900 0901 void cElementManager::processInternalTag (const string &name, const list<sParam> ¶ms, 0902 const list<string> &flags) 0903 { 0904 list<sParam>::const_iterator it; 0905 list<string>::const_iterator it2; 0906 if (name == "!element") 0907 { 0908 string name, definition, att, flag; 0909 int tag; 0910 bool fopen = false, fdelete = false, fempty = false; 0911 for (it = params.begin(); it != params.end(); ++it) 0912 { 0913 string s = (*it).name; 0914 if (s == "name") name = lcase ((*it).value); 0915 if (s == "definition") definition = (*it).value; 0916 if (s == "att") att = (*it).value; 0917 if (s == "flag") flag = (*it).value; 0918 if (s == "tag") tag = atoi ((*it).value.c_str()); 0919 } 0920 for (it2 = flags.begin(); it2 != flags.end(); ++it2) 0921 { 0922 if (*it2 == "open") fopen = true; 0923 if (*it2 == "delete") fdelete = true; 0924 if (*it2 == "empty") fempty = true; 0925 } 0926 0927 if (name.empty()) 0928 { 0929 results->addToList (results->createError ( 0930 "Received an <!element> tag with no element name!")); 0931 return; 0932 } 0933 //definition can be empty, that's no problem... 0934 0935 //if we want to delete the tag... 0936 if (fdelete) 0937 { 0938 //sanity check 0939 if (!elements.count (name)) 0940 { 0941 results->addToList (results->createWarning ( 0942 "Received request to remove an undefined tag " + name + "!")); 0943 return; 0944 } 0945 removeElement (name); 0946 return; 0947 } 0948 0949 //parse tag definition 0950 parser->simpleParse (definition); 0951 list<sElementPart *> tagcontents; 0952 while (parser->hasNext ()) 0953 { 0954 chunk ch = parser->getNext (); 0955 if (ch.chk == chunkError) 0956 results->addToList (results->createError (ch.text)); 0957 else 0958 { 0959 //create a new element part 0960 sElementPart *part = new sElementPart; 0961 part->text = ch.text; 0962 part->istag = (ch.chk == chunkTag) ? true : false; 0963 tagcontents.push_back (part); 0964 } 0965 } 0966 0967 //parse attribute list 0968 list<string> attlist; 0969 map<string, string> attdefault; 0970 processParamList (att, attlist, attdefault); 0971 0972 //and do the real work 0973 addElement (name, tagcontents, attlist, attdefault, fopen, fempty, tag, flag); 0974 } 0975 else if (name == "!attlist") 0976 { 0977 string name, att; 0978 for (it = params.begin(); it != params.end(); ++it) 0979 { 0980 string s = (*it).name; 0981 if (s == "name") name = (*it).value; 0982 if (s == "att") att = (*it).value; 0983 } 0984 0985 if (name.empty()) 0986 { 0987 results->addToList (results->createError ( 0988 "Received an <!attlist> tag with no element name!")); 0989 return; 0990 } 0991 0992 //parse attribute list 0993 list<string> attlist; 0994 map<string, string> attdefault; 0995 processParamList (att, attlist, attdefault); 0996 0997 //and do the real work 0998 setAttList (name, attlist, attdefault); 0999 } 1000 else if (name == "!entity") 1001 { 1002 string name, value, desc; 1003 bool fpriv = false, fpub = false, fadd = false, fdel = false, frem = false; 1004 for (it = params.begin(); it != params.end(); ++it) 1005 { 1006 string s = (*it).name; 1007 if (s == "name") name = (*it).value; 1008 if (s == "value") value = (*it).value; 1009 if (s == "desc") desc = (*it).value; 1010 } 1011 for (it2 = flags.begin(); it2 != flags.end(); ++it2) 1012 { 1013 if (*it2 == "private") fpriv = true; 1014 if (*it2 == "publish") fpub = true; 1015 if (*it2 == "delete") fdel = true; 1016 if (*it2 == "add") fadd = true; 1017 if (*it2 == "remove") frem = true; 1018 } 1019 1020 if (name.empty()) 1021 { 1022 results->addToList (results->createError ( 1023 "Received an <!entity> tag with no variable name!")); 1024 return; 1025 } 1026 1027 //fpub is IGNORED... 1028 //fadd and frem is IGNORED... 1029 if (!(fadd) && !(frem)) 1030 { 1031 if (fdel) 1032 { 1033 entities->deleteEntity (name); 1034 if (!fpriv) //do not announce PRIVATE entities 1035 state->gotVariable (name, "", true); 1036 } 1037 else 1038 { 1039 //we now have a new variable... 1040 entities->addEntity (name, value); 1041 if (!fpriv) //do not announce PRIVATE entities 1042 state->gotVariable (name, value); 1043 } 1044 } 1045 else 1046 results->addToList (results->createWarning ( 1047 "Ignored <!ENTITY> tag with ADD or REMOVE flag.")); 1048 } 1049 else if (name == "var") 1050 { 1051 //this is very similar to the !entity handler above... 1052 1053 string name, desc; 1054 bool fpriv = false, fpub = false, fadd = false, fdel = false, frem = false; 1055 for (it = params.begin(); it != params.end(); ++it) 1056 { 1057 string s = (*it).name; 1058 if (s == "name") name = (*it).value; 1059 if (s == "desc") desc = (*it).value; 1060 } 1061 for (it2 = flags.begin(); it2 != flags.end(); ++it2) 1062 { 1063 if (*it2 == "private") fpriv = true; 1064 if (*it2 == "publish") fpub = true; 1065 if (*it2 == "add") fadd = true; 1066 if (*it2 == "delete") fdel = true; 1067 if (*it2 == "remove") frem = true; 1068 } 1069 1070 if (name.empty()) 1071 { 1072 results->addToList (results->createError ( 1073 "Received an <var> tag with no variable name!")); 1074 return; 1075 } 1076 1077 //fpriv and fpub is IGNORED... 1078 //fadd and fdel is IGNORED... 1079 if (!(fadd) && !(fdel)) 1080 state->gotVAR (name); 1081 else 1082 results->addToList (results->createWarning ("Ignored <VAR> tag with ADD or REMOVE flag.")); 1083 } 1084 else if (name == "b") 1085 state->gotBOLD(); 1086 else if (name == "i") 1087 state->gotITALIC(); 1088 else if (name == "u") 1089 state->gotUNDERLINE(); 1090 else if (name == "s") 1091 state->gotSTRIKEOUT(); 1092 else if (name == "c") 1093 { 1094 string fore, back; 1095 for (it = params.begin(); it != params.end(); ++it) 1096 { 1097 string s = (*it).name; 1098 if (s == "fore") fore = (*it).value; 1099 if (s == "back") back = (*it).value; 1100 } 1101 RGB fg = state->fgColor(); 1102 RGB bg = state->bgColor(); 1103 if (!fore.empty()) 1104 fg = cMXPColors::self()->color (fore); 1105 if (!back.empty()) 1106 bg = cMXPColors::self()->color (back); 1107 state->gotCOLOR (fg, bg); 1108 } 1109 else if (name == "h") 1110 state->gotHIGH(); 1111 else if (name == "font") 1112 { 1113 string face, fore, back; 1114 int size = 0; 1115 for (it = params.begin(); it != params.end(); ++it) 1116 { 1117 string s = (*it).name; 1118 if (s == "face") face = (*it).value; 1119 if (s == "size") size = atoi ((*it).value.c_str()); 1120 if (s == "color") fore = (*it).value; 1121 if (s == "back") back = (*it).value; 1122 } 1123 if (face.empty()) 1124 face = state->fontFace(); 1125 if (size == 0) 1126 size = state->fontSize(); 1127 RGB fg = state->fgColor(); 1128 RGB bg = state->bgColor(); 1129 if (!fore.empty()) 1130 fg = cMXPColors::self()->color (fore); 1131 if (!back.empty()) 1132 bg = cMXPColors::self()->color (back); 1133 state->gotFONT (face, size, fg, bg); 1134 } 1135 else if (name == "p") 1136 state->gotP(); 1137 else if (name == "br") 1138 state->gotBR(); 1139 else if (name == "nobr") 1140 state->gotNOBR(); 1141 else if (name == "sbr") 1142 state->gotSBR(); 1143 else if (name == "a") 1144 { 1145 string href, hint, expire; 1146 for (it = params.begin(); it != params.end(); ++it) 1147 { 1148 string s = (*it).name; 1149 if (s == "href") href = (*it).value; 1150 if (s == "hint") hint = (*it).value; 1151 if (s == "expire") expire = (*it).value; 1152 } 1153 state->gotA (href, hint, expire); 1154 } 1155 else if (name == "send") 1156 { 1157 string href, hint, expire; 1158 bool prompt = false; 1159 for (it = params.begin(); it != params.end(); ++it) 1160 { 1161 string s = (*it).name; 1162 if (s == "href") href = (*it).value; 1163 if (s == "hint") hint = (*it).value; 1164 if (s == "expire") expire = (*it).value; 1165 } 1166 for (it2 = flags.begin(); it2 != flags.end(); ++it2) 1167 if (*it2 == "prompt") prompt = true; 1168 state->gotSEND (href, hint, prompt, expire); 1169 } 1170 else if (name == "expire") 1171 { 1172 string name; 1173 for (it = params.begin(); it != params.end(); ++it) 1174 { 1175 string s = (*it).name; 1176 if (s == "name") name = (*it).value; 1177 } 1178 //name can be empty - all named links shall then expire 1179 state->gotEXPIRE (name); 1180 } 1181 else if (name == "version") 1182 state->gotVERSION(); 1183 else if (name == "h1") 1184 state->gotHtag (1); 1185 else if (name == "h2") 1186 state->gotHtag (2); 1187 else if (name == "h3") 1188 state->gotHtag (3); 1189 else if (name == "h4") 1190 state->gotHtag (4); 1191 else if (name == "h5") 1192 state->gotHtag (5); 1193 else if (name == "h6") 1194 state->gotHtag (6); 1195 else if (name == "hr") 1196 state->gotHR(); 1197 else if (name == "small") 1198 state->gotSMALL(); 1199 else if (name == "tt") 1200 state->gotTT(); 1201 else if (name == "sound") 1202 { 1203 string fname, t, u; 1204 int v = 0, l = 0, p = 0; //shall be overridden by defaults... 1205 for (it = params.begin(); it != params.end(); ++it) 1206 { 1207 string s = (*it).name; 1208 if (s == "fname") fname = (*it).value; 1209 if (s == "t") t = (*it).value; 1210 if (s == "u") u = (*it).value; 1211 if (s == "v") v = atoi ((*it).value.c_str()); 1212 if (s == "l") l = atoi ((*it).value.c_str()); 1213 if (s == "p") p = atoi ((*it).value.c_str()); 1214 } 1215 if (fname.empty()) 1216 { 1217 results->addToList (results->createError ("Received SOUND tag with no file name!")); 1218 return; 1219 } 1220 if ((v < 0) || (v > 100)) 1221 { 1222 results->addToList (results->createWarning ("Ignoring incorrect V param for SOUND tag.")); 1223 v = 100; //set default value 1224 } 1225 if ((l < -1) || (l > 100) || (l == 0)) 1226 { 1227 results->addToList (results->createWarning ("Ignoring incorrect L param for SOUND tag.")); 1228 l = 1; //set default value 1229 } 1230 if ((p < 0) || (p > 100)) 1231 { 1232 results->addToList (results->createWarning ("Ignoring incorrect P param for SOUND tag.")); 1233 p = 50; //set default value 1234 } 1235 state->gotSOUND (fname, v, l, p, t, u); 1236 } 1237 else if (name == "music") 1238 { 1239 string fname, t, u; 1240 int v = 0, l = 0, c = 0; //shall be overridden by defaults... 1241 for (it = params.begin(); it != params.end(); ++it) 1242 { 1243 string s = (*it).name; 1244 if (s == "fname") fname = (*it).value; 1245 if (s == "t") t = (*it).value; 1246 if (s == "u") u = (*it).value; 1247 if (s == "v") v = atoi ((*it).value.c_str()); 1248 if (s == "l") l = atoi ((*it).value.c_str()); 1249 if (s == "c") c = atoi ((*it).value.c_str()); 1250 } 1251 if (fname.empty()) 1252 { 1253 results->addToList (results->createError ("Received MUSIC tag with no file name!")); 1254 return; 1255 } 1256 if ((v < 0) || (v > 100)) 1257 { 1258 results->addToList (results->createWarning ("Ignoring incorrect V param for MUSIC tag.")); 1259 v = 100; //set default value 1260 } 1261 if ((l < -1) || (l > 100) || (l == 0)) 1262 { 1263 results->addToList (results->createWarning ("Ignoring incorrect L param for MUSIC tag.")); 1264 l = 1; //set default value 1265 } 1266 if ((c != 0) && (c != 1)) 1267 { 1268 results->addToList (results->createWarning ("Ignoring incorrect C param for MUSIC tag.")); 1269 c = 1; //set default value 1270 } 1271 state->gotMUSIC (fname, v, l, (c!=0), t, u); 1272 } 1273 else if (name == "gauge") 1274 { 1275 string entity, max, caption, color; 1276 for (it = params.begin(); it != params.end(); ++it) 1277 { 1278 string s = (*it).name; 1279 if (s == "entity") entity = (*it).value; 1280 if (s == "max") max = (*it).value; 1281 if (s == "caption") caption = (*it).value; 1282 if (s == "color") color = (*it).value; 1283 } 1284 if (entity.empty()) 1285 { 1286 results->addToList (results->createError ("Received GAUGE with no entity name!")); 1287 return; 1288 } 1289 RGB c; 1290 if (color.empty()) color = "white"; 1291 c = cMXPColors::self()->color (color); 1292 state->gotGAUGE (entity, max, caption, c); 1293 } 1294 else if (name == "stat") 1295 { 1296 string entity, max, caption; 1297 for (it = params.begin(); it != params.end(); ++it) 1298 { 1299 string s = (*it).name; 1300 if (s == "entity") entity = (*it).value; 1301 if (s == "max") max = (*it).value; 1302 if (s == "caption") caption = (*it).value; 1303 } 1304 if (entity.empty()) 1305 { 1306 results->addToList (results->createError ("Received STAT with no entity name!")); 1307 return; 1308 } 1309 state->gotSTAT (entity, max, caption); 1310 } 1311 else if (name == "frame") 1312 { 1313 string name, action, title, align; 1314 int left = 0, top = 0, width = 0, height = 0; 1315 bool finternal = false, fscroll = false, ffloat = false; 1316 for (it = params.begin(); it != params.end(); ++it) 1317 { 1318 string s = (*it).name; 1319 if (s == "name") name = (*it).value; 1320 if (s == "action") action = (*it).value; 1321 if (s == "title") title = (*it).value; 1322 if (s == "align") align = (*it).value; 1323 if (s == "left") left = state->computeCoord ((*it).value.c_str(), true); 1324 if (s == "top") top = state->computeCoord ((*it).value.c_str(), false); 1325 if (s == "width") width = state->computeCoord ((*it).value.c_str(), true); 1326 if (s == "height") height = state->computeCoord ((*it).value.c_str(), false); 1327 } 1328 for (it2 = flags.begin(); it2 != flags.end(); ++it2) 1329 { 1330 if (*it2 == "internal") finternal = true; 1331 if (*it2 == "scrolling") fscroll = true; 1332 if (*it2 == "floating") ffloat = true; 1333 } 1334 if (name.empty()) 1335 { 1336 results->addToList (results->createError ("Received FRAME tag with no frame name!")); 1337 return; 1338 } 1339 state->gotFRAME (name, action, title, finternal, align, left, top, width, height, 1340 fscroll, ffloat); 1341 } 1342 else if (name == "dest") 1343 { 1344 string name; 1345 int x = 0, y = 0; 1346 bool feol = false, feof = false; 1347 for (it = params.begin(); it != params.end(); ++it) 1348 { 1349 string s = (*it).name; 1350 if (s == "name") name = (*it).value; 1351 if (s == "x") x = atoi ((*it).value.c_str()); 1352 if (s == "y") y = atoi ((*it).value.c_str()); 1353 } 1354 for (it2 = flags.begin(); it2 != flags.end(); ++it2) 1355 { 1356 if (*it2 == "eol") feol = true; 1357 if (*it2 == "eof") feof = true; 1358 } 1359 if (name.empty()) 1360 { 1361 results->addToList (results->createError ("Received DEST tag with no frame name!")); 1362 return; 1363 } 1364 state->gotDEST (name, x, y, feol, feof); 1365 } 1366 else if (name == "relocate") 1367 { 1368 string name; 1369 int port = 0; 1370 for (it = params.begin(); it != params.end(); ++it) 1371 { 1372 string s = (*it).name; 1373 if (s == "name") name = (*it).value; 1374 if (s == "port") port = atoi ((*it).value.c_str()); 1375 } 1376 if (name.empty()) 1377 { 1378 results->addToList (results->createError ("Received RELOCATE tag with no server name!")); 1379 return; 1380 } 1381 if (port == 0) 1382 { 1383 results->addToList (results->createError ("Received RELOCATE tag with no server port!")); 1384 return; 1385 } 1386 state->gotRELOCATE (name, port); 1387 } 1388 else if (name == "user") 1389 state->gotUSER(); 1390 else if (name == "password") 1391 state->gotPASSWORD(); 1392 else if (name == "image") 1393 { 1394 string name, url, t, align; 1395 int h = 0, w = 0, hspace = 0, vspace = 0; 1396 bool fismap = false; 1397 for (it = params.begin(); it != params.end(); ++it) 1398 { 1399 string s = (*it).name; 1400 if (s == "fname") name = (*it).value; 1401 if (s == "url") url = (*it).value; 1402 if (s == "t") t = (*it).value; 1403 if (s == "align") align = (*it).value; 1404 if (s == "h") h = state->computeCoord ((*it).value.c_str(), true, true); 1405 if (s == "w") w = state->computeCoord ((*it).value.c_str(), false, true); 1406 if (s == "hspace") hspace = atoi ((*it).value.c_str()); 1407 if (s == "vspace") vspace = atoi ((*it).value.c_str()); 1408 } 1409 for (it2 = flags.begin(); it2 != flags.end(); ++it2) 1410 if (*it2 == "ismap") fismap = true; 1411 if (name.empty()) 1412 { 1413 results->addToList (results->createError ("Received IMAGE tag with no image name!")); 1414 return; 1415 } 1416 state->gotIMAGE (name, url, t, h, w, hspace, vspace, align, fismap); 1417 } 1418 else if (name == "filter") 1419 { 1420 /* 1421 string src, dest, name; 1422 for (it = params.begin(); it != params.end(); ++it) 1423 { 1424 string s = (*it).name; 1425 if (s == "src") src = (*it).value; 1426 if (s == "dest") dest = (*it).value; 1427 if (s == "name") name = (*it).value; 1428 } 1429 state->gotFILTER (src, dest, name); 1430 */ 1431 results->addToList (results->createWarning ("Ignoring unsupported FILTER tag.")); 1432 } 1433 } 1434 1435 void cElementManager::processSupport (const list<sParam> ¶ms) 1436 { 1437 list<string> pars; 1438 list<sParam>::const_iterator it; 1439 for (it = params.begin(); it != params.end(); ++it) 1440 pars.push_back ((*it).value); 1441 state->gotSUPPORT (pars); 1442 } 1443 1444 void cElementManager::processCustomTag (const string &name, const list<sParam> ¶ms) 1445 { 1446 //generate a mapping with all parameter values 1447 paramexpander->reset(); 1448 list<sParam>::const_iterator itp; 1449 for (itp = params.begin(); itp != params.end(); ++itp) 1450 //assign parameter value... default values and stuff were already expanded 1451 paramexpander->addEntity ((*itp).name, /*"'" +*/ (*itp).value /*+ "'"*/); 1452 1453 //process tag contents one by one 1454 list<sElementPart *>::iterator it; 1455 for (it = elements[name]->element.begin(); it != elements[name]->element.end(); ++it) 1456 { 1457 sElementPart *sep = *it; 1458 string part = sep->text; 1459 1460 //expand tag parameters first 1461 part = paramexpander->expandEntities (part, true); 1462 1463 //parameters are expanded, process this part 1464 if (sep->istag) 1465 //this part is another tag - expand it recursively 1466 gotTag (part); 1467 else 1468 //this part is regular text 1469 state->gotText (part); 1470 } 1471 1472 //tag processed, send flag information, is any 1473 if (!elements[name]->flag.empty()) 1474 state->gotFlag (true, elements[name]->flag); 1475 } 1476 1477 enum paramParserState { 1478 parNone, 1479 parName, 1480 parValue, 1481 parQuotedValue 1482 }; 1483 1484 1485 void cElementManager::processParamList (const string ¶ms, list<string> &attlist, 1486 map<string, string> &attdefault) 1487 { 1488 //this is similar to the parser in gotTag(), but it's a bit simpler... 1489 1490 string name, value; 1491 char quote; 1492 paramParserState state = parNone; 1493 string::const_iterator it; 1494 for (it = params.begin(); it != params.end(); ++it) 1495 { 1496 char ch = *it; 1497 1498 //process character 1499 switch (state) { 1500 case parNone: { 1501 if (ch != ' ') 1502 { 1503 state = parName; 1504 name += ch; 1505 } 1506 break; 1507 } 1508 case parName: { 1509 if (ch == '=') 1510 state = parValue; 1511 else if (ch == ' ') 1512 { 1513 //new parameter, no default value 1514 attlist.push_back (lcase (name)); 1515 name = ""; 1516 state = parNone; 1517 } 1518 else 1519 name += ch; 1520 break; 1521 } 1522 case parValue: { 1523 if (ch == ' ') 1524 { 1525 //new parameter, with default value 1526 attlist.push_back (lcase (name)); 1527 attdefault[name] = value; 1528 name = ""; 1529 value = ""; 1530 state = parNone; 1531 } 1532 else if (value.empty() && ((ch == '\'') || (ch == '"'))) 1533 { 1534 state = parQuotedValue; 1535 quote = ch; 1536 } 1537 else 1538 value += ch; 1539 break; 1540 } 1541 case parQuotedValue: { 1542 if (ch == quote) 1543 { 1544 //new parameter, with default value 1545 attlist.push_back (lcase (name)); 1546 attdefault[name] = value; 1547 name = ""; 1548 value = ""; 1549 state = parNone; 1550 } 1551 else 1552 value += ch; 1553 break; 1554 } 1555 }; 1556 } 1557 1558 //last parameter... 1559 switch (state) { 1560 case parName: { 1561 //new parameter, no default value 1562 attlist.push_back (lcase (name)); 1563 } 1564 break; 1565 case parValue: { 1566 //new parameter, with default value 1567 attlist.push_back (lcase (name)); 1568 attdefault[name] = value; 1569 break; 1570 } 1571 case parQuotedValue: 1572 results->addToList (results->createWarning ( 1573 "Received tag definition with unfinished quoted default parameter value!")); 1574 //new parameter, with default value (unfinished, but hey...) 1575 attlist.push_back (lcase (name)); 1576 attdefault[name] = value; 1577 break; 1578 }; 1579 1580 //everything done... 1581 } 1582 1583 void cElementManager::addElement (const string &name, list<sElementPart *> contents, 1584 list<string> attlist, map<string, string> attdefault, bool open, bool empty, 1585 int tag, string flag) 1586 { 1587 //sanity checks 1588 if (elementDefined (name)) 1589 { 1590 results->addToList (results->createError ("Multiple definition of element " + name + "!")); 1591 return; 1592 } 1593 1594 sElement *e = new sElement; 1595 e->open = open; 1596 e->empty = empty; 1597 if ((tag >= 20) && (tag <= 99)) 1598 { 1599 e->tag = tag; 1600 if (lineTags.count (tag)) 1601 results->addToList (results->createError ("Element " + name + 1602 " uses an already assigned line tag!")); 1603 lineTags[tag] = name; 1604 } 1605 else 1606 e->tag = 0; 1607 e->flag = flag; 1608 1609 //assign element contents, generating the list of closing tags 1610 e->element.clear(); 1611 list<sElementPart *>::iterator it; 1612 for (it = contents.begin(); it != contents.end(); ++it) 1613 { 1614 sElementPart *ep = *it; 1615 if (ep->istag) 1616 { 1617 string tag = lcase (firstword (ep->text)); 1618 if (elementDefined (tag)) 1619 { 1620 if (open && !(openElement (tag))) 1621 { 1622 delete ep; 1623 results->addToList (results->createError ("Definition of open " + name + 1624 " tag contains secure tag " + tag + "!")); 1625 } 1626 else if (empty && !(emptyElement (tag))) 1627 { 1628 delete ep; 1629 results->addToList (results->createError ("Definition of empty " + name + 1630 " tag contains non-empty tag " + tag + "!")); 1631 } 1632 else 1633 { 1634 e->element.push_back (ep); 1635 if (!emptyElement(tag)) e->closingseq.push_front (tag); 1636 } 1637 } 1638 else 1639 { 1640 //element doesn't exist yet - we must believe that it's correct 1641 e->element.push_back (ep); 1642 if (!empty) e->closingseq.push_front (tag); 1643 results->addToList (results->createWarning ("Definition of element " + name + 1644 " contains undefined element " + tag + "!")); 1645 } 1646 } 1647 else 1648 e->element.push_back (ep); 1649 } 1650 1651 //assign the element definition 1652 elements[name] = e; 1653 1654 //set attribute list 1655 setAttList (name, attlist, attdefault); 1656 } 1657 1658 void cElementManager::setAttList (const string &name, list<string> attlist, 1659 map<string, string> attdefault) 1660 { 1661 //sanity check 1662 if (!elements.count (name)) 1663 { 1664 results->addToList (results->createWarning ("Received attribute list for undefined tag " + 1665 name + "!")); 1666 return; 1667 } 1668 1669 sElement *e = elements[name]; 1670 e->attlist.clear(); 1671 e->attdefault.clear(); 1672 e->attlist = attlist; 1673 e->attdefault = attdefault; 1674 } 1675 1676 void cElementManager::removeElement (const string &name) 1677 { 1678 //external elements only 1679 if (elements.count (name)) 1680 { 1681 sElement *e = elements[name]; 1682 list<sElementPart *>::iterator it; 1683 for (it = e->element.begin(); it != e->element.end(); ++it) 1684 delete *it; 1685 e->element.clear(); 1686 e->attlist.clear(); 1687 e->attdefault.clear(); 1688 e->closingseq.clear(); 1689 if (e->tag) 1690 lineTags.erase (e->tag); 1691 delete e; 1692 elements.erase (name); 1693 } 1694 } 1695 1696 void cElementManager::removeAll () 1697 { 1698 //external elements only 1699 1700 list<string> names; 1701 //we cannot delete definitions directly, because that would invalidate our iterator 1702 map<string, sElement *>::iterator it; 1703 for (it = elements.begin(); it != elements.end(); ++it) 1704 names.push_back (it->first); 1705 list<string>::iterator it2; 1706 for (it2 = names.begin(); it2 != names.end(); ++it2) 1707 removeElement (*it2); 1708 names.clear (); 1709 }