1 /* 2 * Copyright (C) 2003-2005 Tommi Maekitalo 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * As a special exception, you may use this file as part of a free 10 * software library without restriction. Specifically, if other files 11 * instantiate templates or use macros or inline functions from this 12 * file, or you compile this file and link it with other files to 13 * produce an executable, this file does not by itself cause the 14 * resulting executable to be covered by the GNU General Public 15 * License. This exception does not however invalidate any other 16 * reasons why the executable file might be covered by the GNU Library 17 * General Public License. 18 * 19 * This library is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 * Lesser General Public License for more details. 23 * 24 * You should have received a copy of the GNU Lesser General Public 25 * License along with this library; if not, write to the Free Software 26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 27 */ 28 29 30 #include "tnt/ecpp/parser.h" 31 #include "tnt/ecpp/parsehandler.h" 32 #include <sstream> 33 #include <fstream> 34 #include <cctype> 35 #include <cxxtools/log.h> 36 37 log_define("tntnet.parser") 38 39 namespace tnt 40 { 41 namespace 42 { isVariableNameChar(char ch)43 inline bool isVariableNameChar(char ch) 44 { 45 return std::isalnum(ch) || ch == '_'; 46 } 47 } 48 49 namespace ecpp 50 { 51 static const char split_start = '{'; 52 static const char split_end = '}'; 53 doInclude(const std::string & file)54 void Parser::doInclude(const std::string& file) 55 { 56 log_debug("include \"" << file << '"'); 57 58 std::string fullname = file; 59 std::ifstream inp(file.c_str()); 60 61 for (includes_type::const_iterator it = includes.begin(); 62 !inp && it != includes.end(); ++it) 63 { 64 fullname = *it + '/' + file; 65 log_debug("try include \"" << fullname << '"'); 66 inp.open(fullname.c_str()); 67 } 68 69 if (!inp) 70 { 71 std::ostringstream msg; 72 throw std::runtime_error("cannot open include file \"" + file + '"'); 73 } 74 75 std::string curfileSave = curfile; 76 unsigned curlineSave = curline; 77 curfile = fullname; 78 curline = 0; 79 80 log_debug("onInclude(\"" << fullname << "\")"); 81 handler.onInclude(fullname); 82 83 parsePriv(inp); 84 85 curfile = curfileSave; 86 curline = curlineSave; 87 88 log_debug("onIncludeEnd(\"" << fullname << "\")"); 89 handler.onIncludeEnd(fullname); 90 } 91 parsePriv(std::istream & in)92 void Parser::parsePriv(std::istream& in) 93 { 94 enum state_type { 95 state_html0, // 0 96 state_html, 97 state_htmlesc, 98 state_tagstart, 99 state_expr, 100 state_expre0, 101 state_tag, 102 state_tagarg0, 103 state_tagarg, 104 state_tagarge, 105 state_defarg0, // 10 106 state_defarg, 107 state_defargdefval0, 108 state_defargdefval, 109 state_defarg_end, 110 state_cpp, 111 state_cppse, 112 state_cppe0, 113 state_cppe1, 114 state_cppetag, 115 state_cppstring, // 20 116 state_cppstringesc, 117 state_cppchar, 118 state_cppcharesc, 119 state_cppchare, 120 state_cppcomment0, 121 state_cppcomment, 122 state_cppcommentc, 123 state_cppcommentce, 124 state_nl, 125 state_cpp1, 126 state_args0, 127 state_args0comment, 128 state_argsvar, // 30 129 state_argsvare, 130 state_argsval, 131 state_argsvalstring, 132 state_argscomment0, 133 state_argscomment, 134 state_argsvalcomment0, 135 state_attr0, 136 state_attr0comment, 137 state_attrvar, 138 state_attrvare, // 40 139 state_attrval, 140 state_attrvalstring, 141 state_attrcomment0, 142 state_attrcomment, 143 state_attrvalcomment0, 144 state_call0, 145 state_callname_expr, 146 state_callname_string, 147 state_callname, 148 state_call_cpparg0, // 50 149 state_call_cpparg1, 150 state_call_cpparg_pe, 151 state_call_cpparg_sp, 152 state_call_cpparg_e, 153 state_callend, 154 state_callarg0, 155 state_callarg, 156 state_callarge, 157 state_callval_expr, 158 state_callval_string, // 60 159 state_callval_word, 160 state_callval0, 161 state_callvale, 162 state_comment, 163 state_commente, 164 state_compe0, 165 state_compe, 166 state_cond0, 167 state_cond, 168 state_condexpr, 169 state_condexpre, // 70 170 state_include0, 171 state_include1, 172 state_scopearg0, 173 state_scopearg, 174 state_scopeargeq, 175 state_scopeargval0, 176 state_scopeargval, 177 state_scopevale, 178 state_scope0, 179 state_scope, // 80 180 state_scopeinit, 181 state_scopeiniteq, 182 state_scopee, 183 state_scopee0, 184 state_scopecomment0, 185 state_scopecomment, 186 state_endcall0, 187 state_endcall, 188 state_endcalle, 189 state_doc, // 90 190 state_doce 191 }; 192 193 state_type state = state_nl; 194 std::string tag, etag, tagarg; 195 std::string html, code, arg, argtype, value; 196 std::string comp; 197 std::string cond, expr; 198 comp_args_type comp_args; 199 std::string pass_cgi; 200 std::string defarg, defval, paramname; 201 cppargs_type cppargs; 202 paramargs_type paramargs; 203 unsigned bracket_count = 0; 204 std::string scopetype, scopevar, scopeinit; 205 scope_container_type scope_container = application_container; 206 scope_type scope = global_scope; 207 bool inComp = false; 208 bool inClose = false; 209 bool htmlExpr = false; 210 bool splitBar = false; 211 212 handler.start(); 213 214 char ch; 215 while (in.get(ch)) 216 { 217 if (ch == '\n') 218 ++curline; 219 220 switch(state) 221 { 222 case state_html0: 223 if (ch == ' ' || ch == '\t') 224 std::cerr << curfile << ':' << curline + 1 << ": warning: trailing white space after closing tag" << std::endl; 225 else if (ch == '\r') 226 std::cerr << curfile << ':' << curline + 1 << ": warning: trailing cr after closing tag (dos format?)" << std::endl; 227 // no break - continue with state_html 228 229 case state_html: 230 if (ch == '<') 231 { 232 state = state_tagstart; 233 } 234 else if (ch == '\n') 235 { 236 if (state == state_html || !html.empty()) 237 html += ch; 238 state = state_nl; 239 } 240 else if (splitBar && (ch == split_start|| ch == split_end)) 241 { 242 if (!html.empty() || ch == split_end) 243 { 244 log_debug("onHtml(\"" << html << "\")"); 245 handler.onHtml(html); 246 html.clear(); 247 } 248 handler.tokenSplit(ch == split_start); 249 } 250 else if (ch == '\\') 251 state = state_htmlesc; 252 else 253 { 254 html += ch; 255 state = state_html; 256 } 257 break; 258 259 case state_htmlesc: 260 if (ch != '\n') 261 html += ch; 262 state = state_html; 263 break; 264 265 case state_tagstart: 266 if (ch == '%') 267 { 268 if (!html.empty()) 269 { 270 log_debug("onHtml(\"" << html << "\")"); 271 handler.onHtml(html); 272 html.clear(); 273 } 274 tag.clear(); 275 handler.onLine(curline, curfile); //# 276 state = state_tag; 277 } 278 else if (ch == '$') 279 { 280 if (!html.empty()) 281 { 282 log_debug("onHtml(\"" << html << "\")"); 283 handler.onHtml(html); 284 html.clear(); 285 } 286 handler.onLine(curline, curfile); //# 287 state = state_expr; 288 } 289 else if (ch == '&') 290 { 291 if (!html.empty()) 292 { 293 log_debug("onHtml(\"" << html << "\")"); 294 handler.onHtml(html); 295 html.clear(); 296 } 297 handler.onLine(curline, curfile); //# 298 state = state_call0; 299 } 300 else if (ch == '#') 301 { 302 if (!html.empty()) 303 { 304 log_debug("onHtml(\"" << html << "\")"); 305 handler.onHtml(html); 306 html.clear(); 307 } 308 state = state_comment; 309 } 310 else if (ch == '{') 311 { 312 if (!html.empty()) 313 { 314 log_debug("onHtml(\"" << html << "\")"); 315 handler.onHtml(html); 316 html.clear(); 317 } 318 handler.onLine(curline, curfile); //# 319 state = state_cpp; 320 } 321 else if (ch == '?') 322 { 323 if (!html.empty()) 324 { 325 handler.onHtml(html); 326 html.clear(); 327 } 328 handler.onLine(curline, curfile); //# 329 state = state_cond0; 330 } 331 else if (ch == '/') 332 { 333 state = state_compe0; 334 } 335 else if (ch == '\\') 336 { 337 html += '<'; 338 state = state_html; 339 } 340 else 341 { 342 html += '<'; 343 html += ch; 344 state = state_html; 345 } 346 break; 347 348 case state_expr: 349 if (ch == '$') 350 { 351 if (!htmlExpr && code.empty()) 352 // <$$ ... $> 353 htmlExpr = true; 354 else 355 // expression might end 356 state = state_expre0; 357 } 358 else 359 code += ch; 360 break; 361 362 case state_expre0: 363 if (ch == '>') 364 { 365 // expression ends, html continues 366 if (htmlExpr) 367 { 368 log_debug("onHtmlExpression(\"" << code << "\")"); 369 handler.onHtmlExpression(code); 370 htmlExpr = false; 371 } 372 else 373 { 374 log_debug("onExpression(\"" << code << "\")"); 375 handler.onExpression(code); 376 } 377 code.clear(); 378 state = state_html; 379 } 380 else 381 { 382 // expression does not end 383 code += '$'; 384 code += ch; 385 if (ch != '$') 386 state = state_expr; 387 } 388 break; 389 390 case state_tag: 391 if (ch == '>') 392 { 393 if (tag == "args" || tag == "get" || tag == "post" || tag == "config") 394 state = state_args0; 395 else if (tag == "attr") 396 state = state_attr0; 397 else if (tag == "include") 398 state = state_include0; 399 else if (tag == "application") 400 { 401 scope_container = application_container; 402 scope = component_scope; 403 state = state_scope0; 404 } 405 else if (tag == "thread") 406 { 407 scope_container = thread_container; 408 scope = component_scope; 409 state = state_scope0; 410 } 411 else if (tag == "session") 412 { 413 scope_container = session_container; 414 scope = component_scope; 415 state = state_scope0; 416 } 417 else if (tag == "securesession") 418 { 419 scope_container = secure_session_container; 420 scope = component_scope; 421 state = state_scope0; 422 } 423 else if (tag == "request") 424 { 425 scope_container = request_container; 426 scope = component_scope; 427 state = state_scope0; 428 } 429 else if (tag == "param") 430 { 431 scope_container = param_container; 432 scope = component_scope; 433 state = state_scope0; 434 } 435 else if (!inClose && tag == "close") 436 { 437 handler.startClose(); 438 state = state_html0; 439 inClose = true; 440 } 441 else if (tag == "i18n") 442 { 443 splitBar = true; 444 handler.startI18n(); 445 state = state_html0; 446 } 447 else if (tag == "doc") 448 state = state_doc; 449 else 450 state = state_cpp; 451 } 452 else if (!inComp && tag == "def" && std::isspace(ch)) 453 state = state_tagarg0; 454 else if (std::isspace(ch)) 455 { 456 if (tag == "application") 457 { 458 scope_container = application_container; 459 state = state_scopearg0; 460 } 461 else if (tag == "thread") 462 { 463 scope_container = thread_container; 464 state = state_scopearg0; 465 } 466 else if (tag == "session") 467 { 468 scope_container = session_container; 469 state = state_scopearg0; 470 } 471 else if (tag == "securesession") 472 { 473 scope_container = secure_session_container; 474 state = state_scopearg0; 475 } 476 else if (tag == "request") 477 { 478 scope_container = request_container; 479 state = state_scopearg0; 480 } 481 else if (tag == "param") 482 { 483 scope_container = param_container; 484 state = state_scopearg0; 485 } 486 else 487 { 488 state_type s = state; 489 state = state_html0; 490 throw parse_error("unknown tag " + tag, s, curfile, curline); 491 } 492 } 493 else 494 tag += ch; 495 break; 496 497 case state_tagarg0: 498 if (ch == '>') 499 state = state_cpp; 500 else if (!std::isspace(ch)) 501 { 502 tagarg = ch; 503 state = state_tagarg; 504 } 505 break; 506 507 case state_tagarg: 508 if (std::isspace(ch)) 509 state = state_tagarge; 510 else if (tag == "def" && ch == '(') 511 state = state_defarg0; 512 else if (ch == '>') 513 { 514 if (tag == "args" || tag == "get" || tag == "post") 515 state = state_args0; 516 else if (tag == "attr") 517 state = state_attr0; 518 else if (tag == "def") 519 { 520 handler.startComp(tagarg, cppargs); 521 state = state_html0; 522 inComp = true; 523 } 524 else if (tag == "close") 525 { 526 handler.startClose(); 527 state = state_html0; 528 inClose = true; 529 } 530 else if (tag == "i18n") 531 { 532 splitBar = true; 533 handler.startI18n(); 534 state = state_html0; 535 } 536 else 537 state = state_cpp; 538 } 539 else 540 tagarg += ch; 541 break; 542 543 case state_tagarge: 544 if (ch == '>') 545 { 546 if (tag == "args" || tag == "get" || tag == "post") 547 state = state_args0; 548 else if (tag == "attr") 549 state = state_attr0; 550 else if (tag == "def") 551 { 552 handler.startComp(tagarg, cppargs); 553 state = state_html0; 554 inComp = true; 555 } 556 else if (tag == "close") 557 { 558 handler.startClose(); 559 state = state_html0; 560 inClose = true; 561 } 562 else if (tag == "i18n") 563 { 564 splitBar = true; 565 handler.startI18n(); 566 state = state_html0; 567 } 568 else 569 state = state_cpp; 570 } 571 else if (tag == "def" && ch == '(') 572 state = state_defarg0; 573 break; 574 575 case state_defarg0: 576 if (ch == ')') 577 state = state_defarg_end; 578 else if (!std::isspace(ch)) 579 { 580 defarg += ch; 581 state = state_defarg; 582 } 583 break; 584 585 case state_defarg: 586 if (ch == '=') 587 state = state_defargdefval0; 588 else if (ch == ')') 589 { 590 cppargs.push_back(std::make_pair(defarg, std::string())); 591 defarg.clear(); 592 state = state_defarg_end; 593 } 594 else if (ch == ',') 595 { 596 cppargs.push_back(std::make_pair(defarg, std::string())); 597 defarg.clear(); 598 state = state_defarg0; 599 } 600 else 601 defarg += ch; 602 break; 603 604 case state_defargdefval0: 605 if (!std::isspace(ch)) 606 { 607 defval = ch; 608 state = state_defargdefval; 609 } 610 break; 611 612 case state_defargdefval: 613 if (ch == ')') 614 { 615 cppargs.push_back(std::make_pair(defarg, defval)); 616 defarg.clear(); 617 defval.clear(); 618 state = state_defarg_end; 619 } 620 else if (ch == ',') 621 { 622 cppargs.push_back(std::make_pair(defarg, defval)); 623 defarg.clear(); 624 defval.clear(); 625 state = state_defarg; 626 } 627 else 628 defval += ch; 629 break; 630 631 case state_defarg_end: 632 if (ch == '>') 633 { 634 handler.startComp(tagarg, cppargs); 635 inComp = true; 636 cppargs.clear(); 637 state = state_html0; 638 } 639 else if (!std::isspace(ch)) 640 { 641 state_type s = state; 642 state = state_html0; 643 throw parse_error("def", s, curfile, curline); 644 } 645 break; 646 647 case state_cppcomment0: 648 if (ch == '/') 649 { 650 code += "//"; 651 state = state_cppcomment; 652 break; 653 } 654 else if (state == '*') 655 { 656 code += "/*"; 657 state = state_cppcommentc; 658 break; 659 } 660 661 code += '/'; 662 state = state_cpp; 663 664 // no break 665 666 case state_cpp: 667 if (ch == '<') 668 state = state_cppe0; 669 else if (ch == '}') 670 state = state_cppse; 671 else if (ch == '/') 672 state = state_cppcomment0; 673 else 674 { 675 code += ch; 676 if (ch == '"') 677 state = state_cppstring; 678 else if (ch == '\'') 679 state = state_cppchar; 680 } 681 break; 682 683 case state_cppstring: 684 code += ch; 685 if (ch == '"') 686 state = state_cpp; 687 else if (ch == '\\') 688 state = state_cppstringesc; 689 break; 690 691 case state_cppstringesc: 692 code += ch; 693 state = state_cppstring; 694 break; 695 696 case state_cppchar: 697 code += ch; 698 if (ch == '\\') 699 state = state_cppcharesc; 700 else 701 state = state_cppchare; 702 break; 703 704 case state_cppcharesc: 705 code += ch; 706 state = state_cppchare; 707 break; 708 709 case state_cppchare: 710 code += ch; 711 if (ch == '\'') 712 state = state_cpp; 713 break; 714 715 case state_cppcomment: 716 code += ch; 717 if (ch == '\n') 718 state = state_cpp; 719 break; 720 721 case state_cppcommentc: 722 code += ch; 723 if (ch == '*') 724 state = state_cppcommentce; 725 break; 726 727 case state_cppcommentce: 728 code += ch; 729 if (ch == '/') 730 state = state_cpp; 731 break; 732 733 case state_cppse: 734 if (ch == '>') 735 { 736 log_debug("onCpp(\"" << code << "\")"); 737 handler.onCpp(code); 738 code.clear(); 739 state = state_html; 740 } 741 else 742 { 743 code += '}'; 744 code += ch; 745 state = state_cpp; 746 } 747 break; 748 749 case state_cppe0: 750 if (ch == '/') 751 { 752 etag.clear(); 753 state = state_cppe1; 754 } 755 else 756 { 757 code += '<'; 758 code += ch; 759 state = state_cpp; 760 } 761 break; 762 763 case state_cppe1: 764 if (ch == '%') 765 state = state_cppetag; 766 else 767 { 768 code += "</"; 769 code += ch; 770 state = state_cpp; 771 } 772 break; 773 774 case state_cppetag: 775 if (ch == '>') 776 { 777 if (tag != etag) 778 { 779 state_type s = state; 780 state = state_html0; 781 throw parse_error("invalid end-tag - " 782 + tag + " expected, " 783 + etag + " found", s, curfile, curline); 784 } 785 else if (tag == "pre") 786 { 787 log_debug("onPre(\"" << code << "\")"); 788 handler.onPre(code); 789 } 790 else if (tag == "init") 791 { 792 log_debug("onInit(\"" << code << "\")"); 793 handler.onInit(code); 794 } 795 else if (tag == "cleanup") 796 { 797 log_debug("onCleanup(\"" << code << "\")"); 798 handler.onCleanup(code); 799 } 800 else if (tag == "shared") 801 { 802 log_debug("onShared(\"" << code << "\")"); 803 handler.onShared(code); 804 } 805 else if (tag == "cpp") 806 { 807 log_debug("onCpp(\"" << code << "\")"); 808 handler.onCpp(code); 809 } 810 else if (tag == "out") 811 { 812 handler.onHtmlExpression(code); 813 } 814 else if (tag == "sout") 815 { 816 handler.onExpression(code); 817 } 818 else if (tag == "args" 819 || tag == "get" 820 || tag == "post" 821 || tag == "attr" 822 || tag == "config" 823 || tag == "include" 824 || tag == "session" 825 || tag == "securesession" 826 || tag == "application" 827 || tag == "thread" 828 || tag == "request" 829 || tag == "param" 830 || tag == "doc") 831 ; 832 else 833 { 834 state_type s = state; 835 state = state_html0; 836 throw parse_error("unknown tag " + tag, s, curfile, curline); 837 } 838 code.clear(); 839 state = state_html0; 840 } 841 else 842 { 843 etag += ch; 844 } 845 break; 846 847 case state_nl: 848 if (ch == '<') 849 { 850 state = state_tagstart; 851 } 852 else if (ch == '%') 853 { 854 // start of oneline-cpp 855 handler.onLine(curline, curfile); //# 856 if (!html.empty()) 857 { 858 log_debug("onHtml(\"" << html << "\")"); 859 handler.onHtml(html); 860 html.clear(); 861 } 862 state = state_cpp1; 863 } 864 else if (ch == '\\') 865 state = state_htmlesc; 866 else if (splitBar && (ch == split_start|| ch == split_end)) 867 { 868 if (!html.empty()) 869 { 870 log_debug("onHtml(\"" << html << "\")"); 871 handler.onHtml(html); 872 html.clear(); 873 } 874 handler.tokenSplit(ch == split_start); 875 state = state_html; 876 } 877 else 878 { 879 html += ch; 880 if (ch != '\n') 881 state = state_html; 882 } 883 break; 884 885 case state_cpp1: 886 if (ch == '\n') 887 { 888 code += '\n'; 889 log_debug("onCpp(\"" << code << "\")"); 890 handler.onCpp(code); 891 code.clear(); 892 state = state_nl; 893 } 894 else 895 { 896 code += ch; 897 } 898 break; 899 900 case state_args0: 901 if (ch == '<') 902 state = state_cppe0; 903 else if (ch == '/') 904 state = state_args0comment; 905 else if (!std::isspace(ch)) 906 { 907 arg = ch; 908 state = state_argsvar; 909 } 910 break; 911 912 case state_args0comment: 913 if (ch == '/') 914 state = state_argscomment; 915 else 916 throw parse_error("7", state, curfile, curline); 917 break; 918 919 case state_argsvar: 920 if (ch == '=') 921 { 922 value.clear(); 923 state = state_argsval; 924 } 925 else if (ch == '/') 926 { 927 processNV(tag, arg, std::string()); 928 arg.clear(); 929 state = state_argscomment0; 930 } 931 else if (ch == ';') 932 { 933 processNV(tag, arg, std::string()); 934 arg.clear(); 935 state = state_args0; 936 } 937 else 938 arg += ch; 939 break; 940 941 case state_argsvare: 942 if (ch == '=') 943 { 944 value.clear(); 945 state = state_argsval; 946 } 947 else if (ch == '\n' || ch == ';') 948 { 949 processNV(tag, arg, std::string()); 950 arg.clear(); 951 state = state_args0; 952 if (ch == '\n') 953 std::cerr << curfile << ':' << curline + 1 << ": warning: old syntax: ';' missing" << std::endl; 954 } 955 else if (!std::isspace(ch)) 956 { 957 processNV(tag, arg, std::string()); 958 arg.clear(); 959 960 if (ch == '<') 961 state = state_cppe0; 962 else if (ch == '/') 963 state = state_argscomment0; 964 else 965 { 966 arg = ch; 967 state = state_argsvar; 968 } 969 } 970 break; 971 972 case state_argsval: 973 if (ch == '\n' || ch == ';') 974 { 975 processNV(tag, arg, value); 976 arg.clear(); 977 value.clear(); 978 state = state_args0; 979 if (ch == '\n') 980 std::cerr << curfile << ':' << curline << ": warning: old syntax: ';' missing" << std::endl; 981 } 982 else if (ch == '"') 983 { 984 value += ch; 985 state = state_argsvalstring; 986 } 987 else if (ch == '/') 988 state = state_argsvalcomment0; 989 else 990 value += ch; 991 break; 992 993 case state_argsvalstring: 994 if (ch == '"') 995 state = state_argsval; 996 value += ch; 997 break; 998 999 case state_argscomment0: 1000 if (ch == '/') 1001 state = state_argscomment; 1002 else 1003 throw parse_error("6", state, curfile, curline); 1004 break; 1005 1006 case state_argscomment: 1007 if (ch == '\n') 1008 state = state_args0; 1009 break; 1010 1011 case state_argsvalcomment0: 1012 if (ch == '/') 1013 { 1014 processNV(tag, arg, value); 1015 arg.clear(); 1016 value.clear(); 1017 state = state_argscomment; 1018 if (ch == '\n') 1019 std::cerr << curfile << ':' << curline << ": warning: old syntax: ';' missing" << std::endl; 1020 } 1021 else 1022 { 1023 value += '/'; 1024 value += ch; 1025 state = state_argsval; 1026 } 1027 break; 1028 1029 case state_attr0: 1030 if (ch == '<') 1031 state = state_cppe0; 1032 else if (ch == '/') 1033 state = state_attr0comment; 1034 else if (!std::isspace(ch)) 1035 { 1036 arg = ch; 1037 state = state_attrvar; 1038 } 1039 break; 1040 1041 case state_attr0comment: 1042 if (ch == '/') 1043 state = state_attrcomment; 1044 else 1045 throw parse_error("7", state, curfile, curline); 1046 break; 1047 1048 case state_attrvar: 1049 if (ch == '=') 1050 { 1051 value.clear(); 1052 state = state_attrval; 1053 } 1054 else if (std::isspace(ch)) 1055 state = state_attrvare; 1056 else 1057 arg += ch; 1058 break; 1059 1060 case state_attrvare: 1061 if (ch == '=') 1062 { 1063 if (arg.empty()) 1064 throw parse_error("name expected", state, curfile, curline); 1065 value.clear(); 1066 state = state_attrval; 1067 } 1068 else if (!std::isspace(ch)) 1069 throw parse_error("'=' expected", state, curfile, curline); 1070 break; 1071 1072 case state_attrval: 1073 if (ch == '\n' || ch == ';') 1074 { 1075 if (value.empty()) 1076 throw parse_error("value expected", state, curfile, curline); 1077 log_debug("onAttr(\"" << arg << "\", \"" << value << "\")"); 1078 handler.onAttr(arg, value); 1079 arg.clear(); 1080 value.clear(); 1081 state = state_attr0; 1082 if (ch == '\n') 1083 std::cerr << curfile << ':' << curline << ": warning: old syntax: ';' missing" << std::endl; 1084 } 1085 else if (ch == '"') 1086 { 1087 value += ch; 1088 state = state_attrvalstring; 1089 } 1090 else if (ch == '/') 1091 state = state_attrvalcomment0; 1092 else 1093 value += ch; 1094 break; 1095 1096 case state_attrvalstring: 1097 if (ch == '"') 1098 state = state_attrval; 1099 value += ch; 1100 break; 1101 1102 case state_attrcomment0: 1103 if (ch == '/') 1104 state = state_attrcomment; 1105 else 1106 throw parse_error("6", state, curfile, curline); 1107 break; 1108 1109 case state_attrcomment: 1110 if (ch == '\n') 1111 state = state_attr0; 1112 break; 1113 1114 case state_attrvalcomment0: 1115 if (ch == '/') 1116 { 1117 if (value.empty()) 1118 throw parse_error("value expected", state, curfile, curline); 1119 log_debug("onAttr(\"" << arg << "\", \"" << value << "\")"); 1120 handler.onAttr(arg, value); 1121 arg.clear(); 1122 value.clear(); 1123 state = state_attrcomment; 1124 } 1125 else 1126 { 1127 value += '/'; 1128 value += ch; 1129 state = state_attrval; 1130 } 1131 break; 1132 1133 case state_call0: 1134 if (ch == '(') 1135 { 1136 comp = ch; 1137 bracket_count = 1; 1138 state = state_callname_expr; 1139 } 1140 else if (ch == '"') 1141 { 1142 comp = ch; 1143 state = state_callname_string; 1144 } 1145 else if (!std::isspace(ch)) 1146 { 1147 comp = ch; 1148 state = state_callname; 1149 } 1150 break; 1151 1152 case state_callname_expr: 1153 comp += ch; 1154 if (ch == '(') 1155 ++bracket_count; 1156 else if (ch == ')' && --bracket_count == 0) 1157 state = state_callarg0; 1158 break; 1159 1160 case state_callname_string: 1161 comp += ch; 1162 if (ch == '"') 1163 state = state_callarg0; 1164 else if (std::isspace(ch)) 1165 throw parse_error("invalid componentname", state, curfile, curline); 1166 break; 1167 1168 case state_callname: 1169 if (ch == '&' || ch == '>') 1170 { 1171 log_debug("onCall(\"" << comp << "comp_args (" << comp_args.size() << "), \"" << pass_cgi << "\", paramargs (" << paramargs.size() << "), defarg (" << defarg.size() << "))"); 1172 handler.onCall(comp, comp_args, pass_cgi, paramargs, defarg); 1173 comp.clear(); 1174 comp_args.clear(); 1175 pass_cgi.clear(); 1176 paramargs.clear(); 1177 defarg.clear(); 1178 state = ch == '>' ? state_html : state_callend; 1179 } 1180 else if (std::isspace(ch)) 1181 state = state_callarg0; 1182 else if (ch == '(') 1183 { 1184 state = state_call_cpparg0; 1185 expr.clear(); 1186 paramargs.clear(); 1187 } 1188 else 1189 comp += ch; 1190 break; 1191 1192 case state_call_cpparg0: 1193 if (ch == ')') 1194 state = state_callarg; 1195 else if (std::isalpha(ch) || ch == '_') 1196 { 1197 expr = ch; 1198 state = state_call_cpparg_pe; 1199 } 1200 else if (!std::isspace(ch)) 1201 { 1202 expr = ch; 1203 if (ch == '(') 1204 bracket_count = 1; 1205 state = state_call_cpparg_e; 1206 } 1207 break; 1208 1209 case state_call_cpparg1: 1210 if (ch == ')') 1211 throw parse_error("')' unexpected", state, curfile, curline); 1212 else if (std::isalpha(ch) || ch == '_') 1213 { 1214 expr = ch; 1215 state = state_call_cpparg_pe; 1216 } 1217 else if (!std::isspace(ch)) 1218 { 1219 expr = ch; 1220 if (ch == '(') 1221 bracket_count = 1; 1222 state = state_call_cpparg_e; 1223 } 1224 break; 1225 1226 case state_call_cpparg_pe: 1227 if (isVariableNameChar(ch)) 1228 expr += ch; 1229 else if (std::isspace(ch)) 1230 { 1231 paramname = expr; 1232 state = state_call_cpparg_sp; 1233 } 1234 else if (ch == '=') 1235 { 1236 paramname = expr; 1237 expr.clear(); 1238 bracket_count = 0; 1239 state = state_call_cpparg_e; 1240 } 1241 else if (ch == ')') 1242 { 1243 if (!defarg.empty()) 1244 defarg += ','; 1245 defarg += expr; 1246 expr.clear(); 1247 state = state_callarg0; 1248 } 1249 else 1250 { 1251 expr += ch; 1252 if (ch == '(') 1253 bracket_count = 1; 1254 state = state_call_cpparg_e; 1255 } 1256 break; 1257 1258 case state_call_cpparg_sp: 1259 if (std::isspace(ch)) 1260 expr += ch; 1261 else if (ch == '=') 1262 { 1263 expr.clear(); 1264 bracket_count = 0; 1265 state = state_call_cpparg_e; 1266 } 1267 else 1268 { 1269 expr += ch; 1270 paramname.clear(); 1271 if (ch == '(') 1272 bracket_count = 1; 1273 state = state_call_cpparg_e; 1274 } 1275 break; 1276 1277 case state_call_cpparg_e: 1278 if (ch == ')' && bracket_count > 0) 1279 { 1280 --bracket_count; 1281 expr += ch; 1282 } 1283 else if (ch == ',' || ch == ')') 1284 { 1285 if (paramname.empty()) 1286 { 1287 if (!defarg.empty()) 1288 defarg += ','; 1289 defarg += expr; 1290 expr.clear(); 1291 state = ch == ',' ? state_call_cpparg1 : state_callarg0; 1292 } 1293 else 1294 { 1295 if (paramargs.find(paramname) != paramargs.end()) 1296 throw parse_error("duplicate parameter " + paramname, state, curfile, curline); 1297 paramargs[paramname] = expr; 1298 paramname.clear(); 1299 expr.clear(); 1300 state = ch == ',' ? state_call_cpparg1 : state_callarg0; 1301 } 1302 } 1303 else 1304 { 1305 if (ch == '(') 1306 ++bracket_count; 1307 expr += ch; 1308 } 1309 break; 1310 1311 case state_callend: 1312 if (ch == '>') 1313 state = state_html; 1314 else 1315 throw parse_error("3", state, curfile, curline); 1316 break; 1317 1318 case state_callarg0: 1319 if (std::isalpha(ch) || ch == '_') 1320 { 1321 arg = ch; 1322 state = state_callarg; 1323 } 1324 else if (ch == '&' || ch == '/' || ch == '>') 1325 { 1326 log_debug("onCall(\"" << comp << "comp_args (" << comp_args.size() << "), \"" << pass_cgi << "\", paramargs (" << paramargs.size() << "), defarg (" << defarg.size() << "))"); 1327 handler.onCall(comp, comp_args, pass_cgi, paramargs, defarg); 1328 arg.clear(); 1329 comp.clear(); 1330 comp_args.clear(); 1331 pass_cgi.clear(); 1332 paramargs.clear(); 1333 defarg.clear(); 1334 state = ch == '>' ? state_html : state_callend; 1335 } 1336 else if (ch == '(' && arg.empty() && pass_cgi.empty()) 1337 state = state_call_cpparg0; 1338 else if (!std::isspace(ch)) 1339 throw parse_error(std::string("invalid argumentname (") + ch + ')', state, curfile, curline); 1340 break; 1341 1342 case state_callarg: 1343 if (isVariableNameChar(ch)) 1344 arg += ch; 1345 else if (std::isspace(ch)) 1346 state = state_callarge; 1347 else if (ch == '=') 1348 state = state_callval0; 1349 else if ((pass_cgi.empty() && ch == '&') || ch == '/' || ch == '>') 1350 { 1351 log_debug("onCall(\"" << comp << "comp_args (" << comp_args.size() << "), \"" << pass_cgi << "\", paramargs (" << paramargs.size() << "), defarg (" << defarg.size() << "))"); 1352 handler.onCall(comp, comp_args, arg, paramargs, defarg); 1353 arg.clear(); 1354 comp.clear(); 1355 comp_args.clear(); 1356 paramargs.clear(); 1357 defarg.clear(); 1358 state = ch == '>' ? state_html : state_callend; 1359 } 1360 else 1361 throw parse_error(std::string("invalid argumentname (") + ch + ')', state, curfile, curline); 1362 break; 1363 1364 case state_callarge: 1365 if (ch == '=') 1366 state = state_callval0; 1367 else if (pass_cgi.empty() && (isVariableNameChar(ch))) 1368 { 1369 pass_cgi = arg; 1370 arg = ch; 1371 state = state_callarg; 1372 } 1373 else if ((pass_cgi.empty() && ch == '&') || ch == '/' || ch == '>') 1374 { 1375 log_debug("onCall(\"" << comp << "comp_args (" << comp_args.size() << "), \"" << pass_cgi << "\", paramargs (" << paramargs.size() << "), defarg (" << defarg.size() << "))"); 1376 handler.onCall(comp, comp_args, arg, paramargs, defarg); 1377 arg.clear(); 1378 comp.clear(); 1379 comp_args.clear(); 1380 paramargs.clear(); 1381 defarg.clear(); 1382 state = ch == '>' ? state_html : state_callend; 1383 } 1384 else if (!std::isspace(ch)) 1385 throw parse_error("5", state, curfile, curline); 1386 break; 1387 1388 case state_callval0: 1389 if (ch == '(') 1390 { 1391 value = ch; 1392 state = state_callval_expr; 1393 bracket_count = 1; 1394 } 1395 else if (ch == '"') 1396 { 1397 value = ch; 1398 state = state_callval_string; 1399 } 1400 else if (!std::isspace(ch)) 1401 { 1402 value = ch; 1403 state = state_callval_word; 1404 } 1405 break; 1406 1407 case state_callval_expr: 1408 value += ch; 1409 if (ch == '(') 1410 ++bracket_count; 1411 else if (ch == ')' && --bracket_count == 0) 1412 { 1413 comp_args.insert(comp_args_type::value_type(arg, value)); 1414 arg.clear(); 1415 value.clear(); 1416 state = state_callarg0; 1417 } 1418 break; 1419 1420 case state_callval_string: 1421 value += ch; 1422 if (ch == '"') 1423 { 1424 comp_args.insert(comp_args_type::value_type(arg, value)); 1425 arg.clear(); 1426 value.clear(); 1427 state = state_callarg0; 1428 } 1429 break; 1430 1431 case state_callval_word: 1432 if (std::isspace(ch)) 1433 { 1434 comp_args.insert(comp_args_type::value_type(arg, value)); 1435 arg.clear(); 1436 value.clear(); 1437 state = state_callarg0; 1438 } 1439 else 1440 value += ch; 1441 break; 1442 1443 case state_callvale: 1444 if (ch == '>') 1445 { 1446 comp_args.insert(comp_args_type::value_type(arg, value)); 1447 arg.clear(); 1448 value.clear(); 1449 1450 log_debug("onCall(\"" << comp << "comp_args (" << comp_args.size() << "), \"" << pass_cgi << "\", paramargs (" << paramargs.size() << "), defarg (" << defarg.size() << "))"); 1451 handler.onCall(comp, comp_args, pass_cgi, paramargs, defarg); 1452 comp.clear(); 1453 comp_args.clear(); 1454 pass_cgi.clear(); 1455 paramargs.clear(); 1456 defarg.clear(); 1457 state = state_html; 1458 } 1459 else 1460 throw parse_error("ivalid value", state, curfile, curline); 1461 break; 1462 1463 case state_comment: 1464 if (ch == '#') 1465 state = state_commente; 1466 break; 1467 1468 case state_commente: 1469 if (ch == '>') 1470 state = state_html; 1471 else if (ch != '#') 1472 state = state_comment; 1473 break; 1474 1475 case state_compe0: 1476 if (ch == '%') 1477 { 1478 if (!html.empty()) 1479 { 1480 log_debug("onHtml(\"" << html << "\")"); 1481 handler.onHtml(html); 1482 html.clear(); 1483 } 1484 state = state_compe; 1485 tag.clear(); 1486 } 1487 else if (ch == '&') 1488 { 1489 state = state_endcall0; 1490 } 1491 else 1492 { 1493 html += "</"; 1494 html += ch; 1495 state = state_html; 1496 } 1497 break; 1498 1499 case state_compe: 1500 if (ch == '>') 1501 { 1502 if (inComp && tag == "def") 1503 { 1504 log_debug("onComp(\"" << code << "\")"); 1505 handler.onComp(code); 1506 inComp = false; 1507 state = state_html0; 1508 } 1509 else if (inClose && tag == "close") 1510 { 1511 handler.endClose(); 1512 inClose = false; 1513 state = state_html0; 1514 } 1515 else if (splitBar && tag == "i18n") 1516 { 1517 splitBar = false; 1518 handler.endI18n(); 1519 state = state_html0; 1520 } 1521 else 1522 { 1523 html += "</%"; 1524 html += tag; 1525 state = state_html; 1526 } 1527 } 1528 else 1529 { 1530 tag += ch; 1531 if (tag.size() > 5) 1532 { 1533 html += "</%"; 1534 html += tag; 1535 state = state_html; 1536 } 1537 } 1538 break; 1539 1540 case state_cond0: 1541 if (ch == '?') 1542 htmlExpr = true; 1543 else 1544 cond += ch; 1545 state = state_cond; 1546 break; 1547 1548 case state_cond: 1549 if (ch == '?') 1550 state = state_condexpr; 1551 else 1552 cond += ch; 1553 break; 1554 1555 case state_condexpr: 1556 if (ch == '?') 1557 state = state_condexpre; 1558 else if (expr.empty() && ch == '>') 1559 { 1560 // special case for xml-header (<?xml ... ?>) 1561 handler.onHtml("<?" + cond + "?>"); 1562 cond.clear(); 1563 state = state_html; 1564 } 1565 else 1566 expr += ch; 1567 break; 1568 1569 case state_condexpre: 1570 if (ch == '>') 1571 { 1572 log_debug("onCondExpression(\"" << cond << ", " << code << "\")"); 1573 handler.onCondExpr(cond, expr, htmlExpr); 1574 htmlExpr = false; 1575 cond.clear(); 1576 expr.clear(); 1577 state = state_html; 1578 } 1579 else 1580 { 1581 expr += '?'; 1582 expr += ch; 1583 state = state_condexpr; 1584 } 1585 break; 1586 1587 case state_include0: 1588 if (ch == '<') 1589 state = state_cppe0; 1590 else if (!std::isspace(ch)) 1591 { 1592 expr = ch; 1593 state = state_include1; 1594 } 1595 break; 1596 1597 case state_include1: 1598 if (std::isspace(ch) || ch == '<') 1599 { 1600 doInclude(expr); 1601 expr.clear(), 1602 state = (ch == '<' ? state_cppe0 : state_include0); 1603 } 1604 else 1605 expr += ch; 1606 break; 1607 1608 case state_scopearg0: 1609 if (ch == '>') 1610 { 1611 state = state_scope0; 1612 scope = component_scope; 1613 } 1614 else if (!std::isspace(ch)) 1615 { 1616 tagarg = ch; 1617 state = state_scopearg; 1618 } 1619 break; 1620 1621 case state_scopearg: 1622 if (ch == '=') 1623 { 1624 state = state_scopeargval0; 1625 if (tagarg != "scope") 1626 throw parse_error("argument \"scope\" expected", state, curfile, curline); 1627 tagarg.clear(); 1628 } 1629 else if (std::isspace(ch)) 1630 { 1631 state = state_scopeargeq; 1632 if (tagarg != "scope") 1633 throw parse_error("argument \"scope\" expected", state, curfile, curline); 1634 tagarg.clear(); 1635 } 1636 else 1637 tagarg += ch; 1638 break; 1639 1640 case state_scopeargeq: 1641 if (ch == '=') 1642 state = state_scopeargval0; 1643 else if (!std::isspace(ch)) 1644 throw parse_error("\"=\" expected", state, curfile, curline); 1645 break; 1646 1647 case state_scopeargval0: 1648 if (ch == '"') 1649 state = state_scopeargval; 1650 else if (!std::isspace(ch)) 1651 throw parse_error("argument expected", state, curfile, curline); 1652 break; 1653 1654 case state_scopeargval: 1655 if (ch == '"') 1656 { 1657 if (value == "global") 1658 scope = global_scope; 1659 else if (value == "page") 1660 scope = page_scope; 1661 else if (value == "component") 1662 scope = component_scope; 1663 else 1664 throw parse_error("global|page|component expected", state, curfile, curline); 1665 1666 value.clear(); 1667 state = state_scopevale; 1668 } 1669 else if (ch == '\n') 1670 throw parse_error("'\"' expected", state, curfile, curline); 1671 else 1672 value += ch; 1673 break; 1674 1675 case state_scopevale: 1676 if (ch == '>') 1677 state = state_scope0; 1678 else if (!std::isspace(ch)) 1679 throw parse_error("'>' expected", state, curfile, curline); 1680 break; 1681 1682 case state_scope0: 1683 if (ch == '<') 1684 state = state_scopee; 1685 else if (ch == '/') 1686 state = state_scopecomment0; 1687 else if (!std::isspace(ch)) 1688 { 1689 handler.onLine(curline, curfile); //# 1690 scopevar = ch; 1691 state = state_scope; 1692 } 1693 break; 1694 1695 case state_scope: 1696 if (ch == ';') 1697 { 1698 // scopetype contains type-definition 1699 // scopevar contains variable-definition 1700 // scopeinit is empty 1701 if (scopetype.size() > 0 1702 && std::isspace(scopetype.at(scopetype.size() - 1))) 1703 scopetype.erase(scopetype.size() - 1); 1704 log_debug("onScope(" << scope_container << ", " << scope << ", " 1705 << scopetype << ", " << scopevar << ", " << scopeinit << ')'); 1706 handler.onScope(scope_container, scope, scopetype, scopevar, scopeinit); 1707 1708 scopetype.clear(); 1709 scopevar.clear(); 1710 state = state_scope0; 1711 } 1712 else if (ch == '(') 1713 { 1714 state = state_scopeinit; 1715 bracket_count = 0; 1716 } 1717 else if (ch == '=') 1718 { 1719 state = state_scopeiniteq; 1720 bracket_count = 0; 1721 } 1722 else if (std::isspace(ch)) 1723 scopevar += ch; 1724 else if (!isVariableNameChar(scopevar.at(scopevar.size() - 1))) 1725 { 1726 scopetype += scopevar; 1727 scopevar = ch; 1728 } 1729 else 1730 scopevar += ch; 1731 break; 1732 1733 case state_scopee: 1734 if (ch == '/') 1735 { 1736 etag.clear(); 1737 state = state_cppe1; 1738 } 1739 else 1740 { 1741 scopevar += '<'; 1742 scopevar += ch; 1743 state = state_scope; 1744 } 1745 break; 1746 1747 case state_scopeinit: 1748 if (bracket_count == 0 && ch == ')') 1749 { 1750 // scopevar contains variable-definition 1751 // scopeinit contains constructorparameter 1752 while (scopetype.size() > 0 1753 && std::isspace(scopetype.at(scopetype.size() - 1))) 1754 scopetype.erase(scopetype.size() - 1); 1755 while (scopevar.size() > 0 1756 && std::isspace(scopevar.at(scopevar.size() - 1))) 1757 scopevar.erase(scopevar.size() - 1); 1758 log_debug("onScope(" << scope_container << ", " << scope << ", " 1759 << scopetype << ", " << scopevar << ", " << scopeinit << ')'); 1760 handler.onScope(scope_container, scope, scopetype, scopevar, scopeinit); 1761 1762 scopetype.clear(); 1763 scopevar.clear(); 1764 scopeinit.clear(); 1765 state = state_scopee0; 1766 } 1767 else 1768 { 1769 scopeinit += ch; 1770 if (ch == '(') 1771 ++bracket_count; 1772 else if (ch == ')') 1773 { 1774 if (bracket_count == 0) 1775 throw parse_error("unexpected ')'", state, curfile, curline); 1776 --bracket_count; 1777 } 1778 } 1779 break; 1780 1781 case state_scopeiniteq: 1782 if (bracket_count == 0 && ch == ';') 1783 { 1784 // scopevar contains variable-definition 1785 // scopeinit contains constructorparameter 1786 while (scopetype.size() > 0 1787 && std::isspace(scopetype.at(scopetype.size() - 1))) 1788 scopetype.erase(scopetype.size() - 1); 1789 while (scopevar.size() > 0 1790 && std::isspace(scopevar.at(scopevar.size() - 1))) 1791 scopevar.erase(scopevar.size() - 1); 1792 log_debug("onScope(" << scope_container << ", " << scope << ", " 1793 << scopetype << ", " << scopevar << ", " << scopeinit << ')'); 1794 handler.onScope(scope_container, scope, scopetype, scopevar, scopeinit); 1795 1796 scopetype.clear(); 1797 scopevar.clear(); 1798 scopeinit.clear(); 1799 state = state_scope0; 1800 } 1801 else 1802 { 1803 scopeinit += ch; 1804 if (ch == '(') 1805 ++bracket_count; 1806 else if (ch == ')') 1807 { 1808 if (bracket_count == 0) 1809 throw parse_error("unexpected ')'", state, curfile, curline); 1810 --bracket_count; 1811 } 1812 } 1813 break; 1814 1815 case state_scopee0: 1816 if (ch == ';') 1817 state = state_scope0; 1818 else if (!std::isspace(ch)) 1819 throw parse_error("invalid scopedefinition", state, curfile, curline); 1820 break; 1821 1822 case state_scopecomment0: 1823 if (ch == '/') 1824 state = state_scopecomment; 1825 else 1826 throw parse_error("invalid scopedefinition - '/' expexted", state, curfile, curline); 1827 break; 1828 1829 case state_scopecomment: 1830 if (ch == '\n') 1831 state = state_scope0; 1832 break; 1833 1834 case state_endcall0: 1835 if (isVariableNameChar(ch)) 1836 { 1837 comp = ch; 1838 state = state_endcall; 1839 } 1840 else if ('>') 1841 { 1842 if (!html.empty()) 1843 { 1844 log_debug("onHtml(\"" << html << "\")"); 1845 handler.onHtml(html); 1846 html.clear(); 1847 } 1848 log_debug("onEndCall(\"" << comp << "\")"); 1849 handler.onEndCall(comp); 1850 comp.clear(); 1851 state = state_html; 1852 } 1853 else if (!std::isspace(ch)) 1854 throw parse_error(std::string("character expected, \'") + ch 1855 + "\' found", state, curfile, curline); 1856 break; 1857 1858 case state_endcall: 1859 if (ch == '>') 1860 { 1861 if (!html.empty()) 1862 { 1863 log_debug("onHtml(\"" << html << "\")"); 1864 handler.onHtml(html); 1865 html.clear(); 1866 } 1867 log_debug("onEndCall(\"" << comp << "\")"); 1868 handler.onEndCall(comp); 1869 comp.clear(); 1870 state = state_html; 1871 } 1872 else if (std::isspace(ch)) 1873 { 1874 log_debug("onEndCall(\"" << comp << "\")"); 1875 handler.onEndCall(comp); 1876 comp.clear(); 1877 state = state_endcalle; 1878 } 1879 else if (isVariableNameChar(ch) || ch == '@') 1880 comp += ch; 1881 else 1882 throw parse_error("character expected", state, curfile, curline); 1883 break; 1884 1885 case state_endcalle: 1886 if (ch == '>') 1887 state = state_html; 1888 else if (!std::isspace(ch)) 1889 throw parse_error("'>' expected", state, curfile, curline); 1890 break; 1891 1892 case state_doc: 1893 if (ch == '<') 1894 { 1895 etag.clear(); 1896 state = state_doce; 1897 } 1898 break; 1899 1900 case state_doce: 1901 if (ch == '>') 1902 { 1903 if (etag == "/%doc") 1904 state = state_html0; 1905 else 1906 state = state_doc; 1907 } 1908 else if (ch == '<') 1909 etag.clear(); 1910 else 1911 etag += ch; 1912 break; 1913 1914 } // switch(state) 1915 1916 log_debug("line " << curline << " char " << ch << " state " << state << " bc " << bracket_count); 1917 } // while(in.get(ch)) 1918 1919 if (state != state_html && state != state_html0 && state != state_nl) 1920 throw parse_error("parse error", state, curfile, curline); 1921 1922 if (inComp) 1923 throw parse_error("</%def> missing", state, curfile, curline); 1924 1925 if (inClose) 1926 throw parse_error("</%close> missing", state, curfile, curline); 1927 1928 if (!html.empty()) 1929 { 1930 log_debug("onHtml(\"" << html << "\")"); 1931 handler.onHtml(html); 1932 } 1933 } 1934 parse(std::istream & in)1935 void Parser::parse(std::istream& in) 1936 { 1937 parsePriv(in); 1938 handler.end(); 1939 } 1940 processNV(const std::string & tag,const std::string & name,const std::string & value)1941 void Parser::processNV(const std::string& tag, const std::string& name, 1942 const std::string& value) 1943 { 1944 if (tag == "args") 1945 handler.onArg(name, value); 1946 if (tag == "get") 1947 handler.onGet(name, value); 1948 if (tag == "post") 1949 handler.onPost(name, value); 1950 else if (tag == "config") 1951 handler.onConfig(name, value); 1952 } 1953 parse_error(const std::string & txt,int state,const std::string & file,unsigned curline)1954 parse_error::parse_error(const std::string& txt, int state, const std::string& file, unsigned curline) 1955 : runtime_error(std::string()) 1956 { 1957 std::ostringstream m; 1958 m << file << ':' << (curline + 1) << ": error: " << txt << " (state " << state << ')'; 1959 msg = m.str(); 1960 } 1961 what() const1962 const char* parse_error::what() const throw() 1963 { 1964 return msg.c_str(); 1965 } 1966 } 1967 } 1968