1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include <precomp.h> 29 #include <s2_dsapi/docu_pe2.hxx> 30 31 32 // NOT FULLY DEFINED SERVICES 33 #include <cctype> 34 #include <ary/doc/d_oldidldocu.hxx> 35 #include <ary_i/d_token.hxx> 36 #include <parser/parserinfo.hxx> 37 #include <adc_cl.hxx> 38 #include <adc_msg.hxx> 39 #include <../parser/inc/x_docu.hxx> 40 #include <s2_dsapi/dsapitok.hxx> 41 #include <s2_dsapi/tk_atag2.hxx> 42 #include <s2_dsapi/tk_html.hxx> 43 #include <s2_dsapi/tk_docw2.hxx> 44 #include <s2_dsapi/tk_xml.hxx> 45 46 47 #ifdef UNX 48 #define strnicmp strncasecmp 49 #endif 50 51 52 namespace csi 53 { 54 namespace dsapi 55 { 56 57 58 const char * AtTagTitle( 59 const Tok_AtTag & i_rToken ); 60 61 62 SapiDocu_PE::SapiDocu_PE(ParserInfo & io_rPositionInfo) 63 : pDocu(0), 64 eState(e_none), 65 pPositionInfo(&io_rPositionInfo), 66 fCurTokenAddFunction(&SapiDocu_PE::AddDocuToken2Void), 67 pCurAtTag(0), 68 sCurDimAttribute(), 69 sCurAtSeeType_byXML(200) 70 { 71 } 72 73 SapiDocu_PE::~SapiDocu_PE() 74 { 75 } 76 77 void 78 SapiDocu_PE::ProcessToken( DYN csi::dsapi::Token & let_drToken ) 79 { 80 if (IsComplete()) 81 { 82 pDocu = 0; 83 eState = e_none; 84 } 85 86 if ( eState == e_none ) 87 { 88 pDocu = new ary::doc::OldIdlDocu; 89 eState = st_short; 90 fCurTokenAddFunction = &SapiDocu_PE::AddDocuToken2Short; 91 } 92 93 csv_assert(pDocu); 94 95 let_drToken.Trigger(*this); 96 delete &let_drToken; 97 } 98 99 void 100 SapiDocu_PE::Process_AtTag( const Tok_AtTag & i_rToken ) 101 { 102 if (NOT pCurAtTag) 103 { 104 eState = st_attags; 105 fCurTokenAddFunction = &SapiDocu_PE::AddDocuToken2CurAtTag; 106 } 107 else 108 { 109 csv_assert(eState == st_attags); 110 pDocu->AddAtTag(*pCurAtTag.Release()); 111 } 112 113 if (i_rToken.Id() == Tok_AtTag::param) 114 { 115 pCurAtTag = new DT_ParameterAtTag; 116 fCurTokenAddFunction = &SapiDocu_PE::SetCurParameterAtTagName; 117 } 118 else if (i_rToken.Id() == Tok_AtTag::see) 119 { 120 pCurAtTag = new DT_SeeAlsoAtTag; 121 fCurTokenAddFunction = &SapiDocu_PE::SetCurSeeAlsoAtTagLinkText; 122 } 123 else if (i_rToken.Id() == Tok_AtTag::deprecated) 124 { 125 pDocu->SetDeprecated(); 126 pCurAtTag = new DT_StdAtTag(""); // Dummy that will not be used. 127 fCurTokenAddFunction = &SapiDocu_PE::AddDocuToken2Deprecated; 128 } 129 else if (i_rToken.Id() == Tok_AtTag::since) 130 { 131 pCurAtTag = new DT_SinceAtTag; 132 fCurTokenAddFunction = &SapiDocu_PE::SetCurSinceAtTagVersion_OOo; 133 } 134 else 135 { 136 pCurAtTag = new DT_StdAtTag( AtTagTitle(i_rToken) ); 137 fCurTokenAddFunction = &SapiDocu_PE::AddDocuToken2CurAtTag; 138 } 139 } 140 141 void 142 SapiDocu_PE::Process_HtmlTag( const Tok_HtmlTag & i_rToken ) 143 { 144 if (eState == st_short AND i_rToken.IsParagraphStarter()) 145 { 146 eState = st_description; 147 fCurTokenAddFunction = &SapiDocu_PE::AddDocuToken2Description; 148 } 149 150 // Workaround special for some errors in API docu: 151 if ( strnicmp("<true",i_rToken.Text(),5 ) == 0 ) 152 { 153 if ( strcmp("<TRUE/>",i_rToken.Text()) != 0 ) 154 TheMessages().Out_InvalidConstSymbol( i_rToken.Text(), 155 pPositionInfo->CurFile(), 156 pPositionInfo->CurLine() ); 157 (this->*fCurTokenAddFunction)( *new DT_TextToken("<b>true</b>") ); 158 return; 159 } 160 else if ( strnicmp("<false",i_rToken.Text(),6 ) == 0 ) 161 { 162 if ( strcmp("<FALSE/>",i_rToken.Text()) != 0 ) 163 TheMessages().Out_InvalidConstSymbol( i_rToken.Text(), 164 pPositionInfo->CurFile(), 165 pPositionInfo->CurLine() ); 166 (this->*fCurTokenAddFunction)( *new DT_TextToken("<b>false</b>") ); 167 return; 168 } 169 else if ( strnicmp("<NULL",i_rToken.Text(),5 ) == 0 ) 170 { 171 if ( strcmp("<NULL/>",i_rToken.Text()) != 0 ) 172 TheMessages().Out_InvalidConstSymbol( i_rToken.Text(), 173 pPositionInfo->CurFile(), 174 pPositionInfo->CurLine() ); 175 (this->*fCurTokenAddFunction)( *new DT_TextToken("<b>null</b>") ); 176 return; 177 } 178 else if ( strnicmp("<void",i_rToken.Text(),5 ) == 0 ) 179 { 180 if ( strcmp("<void/>",i_rToken.Text()) != 0 ) 181 TheMessages().Out_InvalidConstSymbol( i_rToken.Text(), 182 pPositionInfo->CurFile(), 183 pPositionInfo->CurLine() ); 184 (this->*fCurTokenAddFunction)( *new DT_TextToken("<b>void</b>") ); 185 return; 186 } 187 188 (this->*fCurTokenAddFunction)( *new DT_Style(i_rToken.Text(),false) ); 189 } 190 191 void 192 SapiDocu_PE::Process_XmlConst( const Tok_XmlConst & i_rToken ) 193 { 194 (this->*fCurTokenAddFunction)(*new DT_MupConst(i_rToken.Text())); 195 } 196 197 void 198 SapiDocu_PE::Process_XmlLink_BeginTag( const Tok_XmlLink_BeginTag & i_rToken ) 199 { 200 switch (i_rToken.Id()) 201 { 202 case Tok_XmlLink_Tag::e_const: 203 (this->*fCurTokenAddFunction)(*new DT_Style("<b>",false)); 204 break; 205 case Tok_XmlLink_Tag::member: 206 (this->*fCurTokenAddFunction)(*new DT_MupMember(i_rToken.Scope())); 207 break; 208 case Tok_XmlLink_Tag::type: 209 (this->*fCurTokenAddFunction)(*new DT_MupType(i_rToken.Scope())); 210 break; 211 default: 212 // Do nothing. 213 ; 214 } 215 216 if ( i_rToken.Dim().length() > 0 ) 217 sCurDimAttribute = i_rToken.Dim(); 218 else 219 sCurDimAttribute.clear(); 220 } 221 222 void 223 SapiDocu_PE::Process_XmlLink_EndTag( const Tok_XmlLink_EndTag & i_rToken ) 224 { 225 switch (i_rToken.Id()) 226 { 227 case Tok_XmlLink_Tag::e_const: 228 (this->*fCurTokenAddFunction)(*new DT_Style("</b>",false)); 229 break; 230 case Tok_XmlLink_Tag::member: 231 (this->*fCurTokenAddFunction)(*new DT_MupMember(true)); 232 break; 233 case Tok_XmlLink_Tag::type: 234 (this->*fCurTokenAddFunction)(*new DT_MupType(true)); 235 break; 236 default: 237 // Do nothing. 238 ; 239 } 240 if ( sCurDimAttribute.length() > 0 ) 241 { 242 (this->*fCurTokenAddFunction)( *new DT_TextToken(sCurDimAttribute.c_str()) ); 243 sCurDimAttribute.clear(); 244 } 245 } 246 247 void 248 SapiDocu_PE::Process_XmlFormat_BeginTag( const Tok_XmlFormat_BeginTag & i_rToken ) 249 { 250 switch (i_rToken.Id()) 251 { 252 case Tok_XmlFormat_Tag::code: 253 (this->*fCurTokenAddFunction)(*new DT_Style("<code>",false)); 254 break; 255 case Tok_XmlFormat_Tag::listing: 256 (this->*fCurTokenAddFunction)(*new DT_Style("<pre>",true)); 257 break; 258 case Tok_XmlFormat_Tag::atom: 259 (this->*fCurTokenAddFunction)(*new DT_Style("<code>",true)); 260 break; 261 default: 262 // Do nothing. 263 ; 264 } 265 if ( i_rToken.Dim().length() > 0 ) 266 sCurDimAttribute = i_rToken.Dim(); 267 else 268 sCurDimAttribute.clear(); 269 } 270 271 void 272 SapiDocu_PE::Process_XmlFormat_EndTag( const Tok_XmlFormat_EndTag & i_rToken ) 273 { 274 switch (i_rToken.Id()) 275 { 276 case Tok_XmlFormat_Tag::code: 277 (this->*fCurTokenAddFunction)(*new DT_Style("</code>",false)); 278 break; 279 case Tok_XmlFormat_Tag::listing: 280 (this->*fCurTokenAddFunction)(*new DT_Style("</pre>",true)); 281 break; 282 case Tok_XmlFormat_Tag::atom: 283 (this->*fCurTokenAddFunction)(*new DT_Style("</code>",true)); 284 break; 285 default: 286 // Do nothing. 287 ; 288 } 289 if ( sCurDimAttribute.length() > 0 ) 290 { 291 (this->*fCurTokenAddFunction)( *new DT_TextToken(sCurDimAttribute.c_str()) ); 292 sCurDimAttribute.clear(); 293 } 294 } 295 296 void 297 SapiDocu_PE::Process_Word( const Tok_Word & i_rToken ) 298 { 299 (this->*fCurTokenAddFunction)(*new DT_TextToken(i_rToken.Text())); 300 } 301 302 void 303 SapiDocu_PE::Process_Comma() 304 { 305 csv_assert(1==7); 306 // (this->*fCurTokenAddFunction)(*new DT_Comma(i_rToken.Text())); 307 } 308 309 void 310 SapiDocu_PE::Process_DocuEnd() 311 { 312 eState = st_complete; 313 if (pCurAtTag) 314 pDocu->AddAtTag(*pCurAtTag.Release()); 315 fCurTokenAddFunction = &SapiDocu_PE::AddDocuToken2Void; 316 } 317 318 void 319 SapiDocu_PE::Process_EOL() 320 { 321 (this->*fCurTokenAddFunction)(*new DT_EOL); 322 } 323 324 void 325 SapiDocu_PE::Process_White() 326 { 327 (this->*fCurTokenAddFunction)(*new DT_White); 328 } 329 330 DYN ary::doc::OldIdlDocu * 331 SapiDocu_PE::ReleaseJustParsedDocu() 332 { 333 if (IsComplete()) 334 { 335 eState = e_none; 336 return pDocu.Release(); 337 } 338 return 0; 339 } 340 341 342 bool 343 SapiDocu_PE::IsComplete() const 344 { 345 return eState == st_complete; 346 } 347 348 void 349 SapiDocu_PE::AddDocuToken2Void( DYN ary::inf::DocuToken & let_drNewToken ) 350 { 351 delete &let_drNewToken; 352 } 353 354 void 355 SapiDocu_PE::AddDocuToken2Short( DYN ary::inf::DocuToken & let_drNewToken ) 356 { 357 csv_assert(pDocu); 358 pDocu->AddToken2Short(let_drNewToken); 359 } 360 361 void 362 SapiDocu_PE::AddDocuToken2Description( DYN ary::inf::DocuToken & let_drNewToken ) 363 { 364 csv_assert(pDocu); 365 pDocu->AddToken2Description(let_drNewToken); 366 } 367 368 void 369 SapiDocu_PE::AddDocuToken2Deprecated( DYN ary::inf::DocuToken & let_drNewToken ) 370 { 371 csv_assert(pDocu); 372 pDocu->AddToken2DeprecatedText(let_drNewToken); 373 } 374 375 void 376 SapiDocu_PE::AddDocuToken2CurAtTag( DYN ary::inf::DocuToken & let_drNewToken ) 377 { 378 csv_assert(pCurAtTag); 379 pCurAtTag->AddToken(let_drNewToken); 380 } 381 382 void 383 SapiDocu_PE::SetCurParameterAtTagName( DYN ary::inf::DocuToken & let_drNewToken ) 384 { 385 if (let_drNewToken.IsWhiteOnly()) 386 { 387 delete &let_drNewToken; 388 return; 389 } 390 391 csv_assert(pCurAtTag); 392 DT_TextToken * dpText = dynamic_cast< DT_TextToken* >(&let_drNewToken); 393 if (dpText != 0) 394 pCurAtTag->SetName(dpText->GetText()); 395 else 396 pCurAtTag->SetName("parameter ?"); 397 delete &let_drNewToken; 398 fCurTokenAddFunction = &SapiDocu_PE::AddDocuToken2CurAtTag; 399 } 400 401 void 402 SapiDocu_PE::SetCurSeeAlsoAtTagLinkText( DYN ary::inf::DocuToken & let_drNewToken ) 403 { 404 csv_assert(pCurAtTag); 405 406 if (let_drNewToken.IsWhiteOnly()) 407 { 408 delete &let_drNewToken; 409 return; 410 } 411 412 DT_TextToken * pText = dynamic_cast< DT_TextToken* >(&let_drNewToken); 413 if (pText != 0) 414 pCurAtTag->SetName(pText->GetText()); 415 else 416 { 417 DT_MupType * 418 pTypeBegin = dynamic_cast< DT_MupType* >(&let_drNewToken); 419 DT_MupMember * 420 pMemberBegin = dynamic_cast< DT_MupMember* >(&let_drNewToken); 421 if (pTypeBegin != 0 OR pMemberBegin != 0) 422 { 423 sCurAtSeeType_byXML.reset(); 424 425 sCurAtSeeType_byXML 426 << ( pTypeBegin != 0 427 ? pTypeBegin->Scope() 428 : pMemberBegin->Scope() ); 429 430 if (sCurAtSeeType_byXML.tellp() > 0) 431 { 432 sCurAtSeeType_byXML 433 << "::"; 434 } 435 delete &let_drNewToken; 436 fCurTokenAddFunction = &SapiDocu_PE::SetCurSeeAlsoAtTagLinkText_2; 437 return; 438 } 439 else 440 { 441 pCurAtTag->SetName("? (no identifier found)"); 442 } 443 } 444 delete &let_drNewToken; 445 fCurTokenAddFunction = &SapiDocu_PE::AddDocuToken2CurAtTag; 446 } 447 448 void 449 SapiDocu_PE::SetCurSeeAlsoAtTagLinkText_2( DYN ary::inf::DocuToken & let_drNewToken ) 450 { 451 csv_assert(pCurAtTag); 452 453 if (let_drNewToken.IsWhiteOnly()) 454 { 455 delete &let_drNewToken; 456 return; 457 } 458 459 DT_TextToken * 460 pText = dynamic_cast< DT_TextToken* >(&let_drNewToken); 461 if (pText != 0) 462 { 463 sCurAtSeeType_byXML 464 << pText->GetText(); 465 pCurAtTag->SetName(sCurAtSeeType_byXML.c_str()); 466 } 467 else 468 { 469 pCurAtTag->SetName("? (no identifier found)"); 470 } 471 sCurAtSeeType_byXML.reset(); 472 delete &let_drNewToken; 473 fCurTokenAddFunction = &SapiDocu_PE::SetCurSeeAlsoAtTagLinkText_3; 474 } 475 476 void 477 SapiDocu_PE::SetCurSeeAlsoAtTagLinkText_3( DYN ary::inf::DocuToken & let_drNewToken ) 478 { 479 csv_assert(pCurAtTag); 480 481 if (let_drNewToken.IsWhiteOnly()) 482 { 483 delete &let_drNewToken; 484 return; 485 } 486 487 /// Could emit warning, but don't because this parser is obsolete. 488 // Tok_XmlLink_BeginTag * 489 // pLinkEnd = dynamic_cast< Tok_XmlLink_EndTag* >(&let_drNewToken); 490 // if (pLinkEnd == 0) 491 // { 492 // warn_aboutMissingClosingTag(); 493 // } 494 495 delete &let_drNewToken; 496 fCurTokenAddFunction = &SapiDocu_PE::AddDocuToken2CurAtTag; 497 } 498 499 const String 500 C_sSinceFormat("Correct version format: \"OOo <major>.<minor>[.<micro> if micro is not 0]\"."); 501 502 void 503 SapiDocu_PE::SetCurSinceAtTagVersion_OOo( DYN ary::inf::DocuToken & let_drNewToken ) 504 { 505 csv_assert(pCurAtTag); 506 507 DT_TextToken * pToken = dynamic_cast< DT_TextToken* >(&let_drNewToken); 508 if (pToken == 0) 509 { 510 delete &let_drNewToken; 511 return; 512 } 513 514 const String 515 sVersion(pToken->GetText()); 516 if (NOT CheckVersionSyntax_OOo(sVersion)) 517 { 518 Cerr() << "Version information in @since tag has incorrect format.\n" 519 << "Found: \"" << sVersion << "\"\n" 520 << C_sSinceFormat 521 << Endl(); 522 exit(1); 523 } 524 525 const autodoc::CommandLine & 526 rCommandLine = autodoc::CommandLine::Get_(); 527 if (NOT rCommandLine.DoesTransform_SinceTag()) 528 pCurAtTag->AddToken(let_drNewToken); 529 530 fCurTokenAddFunction = &SapiDocu_PE::SetCurSinceAtTagVersion_Number; 531 } 532 533 void 534 SapiDocu_PE::SetCurSinceAtTagVersion_Number( DYN ary::inf::DocuToken & let_drNewToken ) 535 { 536 csv_assert(pCurAtTag); 537 538 DT_TextToken * pToken = dynamic_cast< DT_TextToken* >(&let_drNewToken); 539 if (pToken == 0) 540 { 541 if (dynamic_cast< DT_White* >(&let_drNewToken) != 0) 542 { 543 String & 544 sValue = pCurAtTag->Access_Text().Access_TextOfFirstToken(); 545 StreamLock 546 sHelp(1000); 547 sValue = sHelp() << sValue << " " << c_str; 548 } 549 550 delete &let_drNewToken; 551 return; 552 } 553 554 const String 555 sVersion(pToken->GetText()); 556 if (NOT CheckVersionSyntax_Number(sVersion)) 557 { 558 Cerr() << "Version information in @since tag has incorrect format.\n" 559 << "Found: \"" << sVersion << "\"\n" 560 << C_sSinceFormat 561 << Endl(); 562 exit(1); 563 } 564 565 const autodoc::CommandLine & 566 rCommandLine = autodoc::CommandLine::Get_(); 567 if ( rCommandLine.DoesTransform_SinceTag()) 568 { 569 pCurAtTag->AddToken(let_drNewToken); 570 571 if (rCommandLine.DisplayOf_SinceTagValue(sVersion).empty()) 572 { 573 // This is the numbered part, but we don't know it. 574 delete &let_drNewToken; 575 576 StreamLock 577 sl(200); 578 sl() 579 << "Since-value '" 580 << sVersion 581 << "' not found in translation table."; 582 throw X_Docu("since", sl().c_str()); 583 } 584 } 585 else 586 { 587 AddDocuToken2SinceAtTag(let_drNewToken); 588 } 589 fCurTokenAddFunction = &SapiDocu_PE::AddDocuToken2SinceAtTag; 590 } 591 592 void 593 SapiDocu_PE::AddDocuToken2SinceAtTag( DYN ary::inf::DocuToken & let_drNewToken ) 594 { 595 csv_assert(pCurAtTag); 596 String & 597 sValue = pCurAtTag->Access_Text().Access_TextOfFirstToken(); 598 StreamLock 599 sHelp(1000); 600 601 DT_TextToken * 602 pToken = dynamic_cast< DT_TextToken* >(&let_drNewToken); 603 if (pToken != 0) 604 { 605 sValue = sHelp() << sValue << pToken->GetText() << c_str; 606 } 607 else if (dynamic_cast< DT_White* >(&let_drNewToken) != 0) 608 { 609 sValue = sHelp() << sValue << " " << c_str; 610 } 611 delete &let_drNewToken; 612 } 613 614 bool 615 SapiDocu_PE::CheckVersionSyntax_OOo(const String & i_versionPart1) 616 { 617 return i_versionPart1 == "OOo" 618 OR i_versionPart1 == "OpenOffice.org"; 619 } 620 621 bool 622 SapiDocu_PE::CheckVersionSyntax_Number(const String & i_versionPart2) 623 { 624 if (i_versionPart2.length () == 0) 625 return false; 626 627 const char 628 pt = '.'; 629 unsigned int countDigit = 0; 630 unsigned int countPoint = 0; 631 const char * 632 pFirstPoint = 0; 633 const char * 634 pLastPoint = 0; 635 636 for ( const char * p = i_versionPart2.begin(); 637 *p != 0; 638 ++p ) 639 { 640 if ( std::isdigit(*p) ) 641 ++countDigit; 642 else if (*p == pt) 643 { 644 if (countPoint == 0) 645 pFirstPoint = p; 646 pLastPoint = p; 647 ++countPoint; 648 } 649 } 650 651 if ( countDigit + countPoint == i_versionPart2.length() // only digits and points 652 AND pFirstPoint != 0 AND countPoint < 3 // 1 or 2 points 653 AND pFirstPoint + 1 != pLastPoint // there are digits between two points 654 AND *i_versionPart2.begin() != pt AND *(pLastPoint + 1) != 0 // points are surrounded by digits 655 AND (*(pLastPoint + 1) != '0' OR pLastPoint == pFirstPoint) ) // the first micro-digit is not 0 656 { 657 return true; 658 } 659 return false; 660 } 661 662 const char * 663 AtTagTitle( const Tok_AtTag & i_rToken ) 664 { 665 switch (i_rToken.Id()) 666 { 667 case Tok_AtTag::author: return ""; 668 case Tok_AtTag::see: return "See also"; 669 case Tok_AtTag::param: return "Parameters"; 670 case Tok_AtTag::e_return: return "Returns"; 671 case Tok_AtTag::e_throw: return "Throws"; 672 case Tok_AtTag::example: return "Example"; 673 case Tok_AtTag::deprecated: return "Deprecated"; 674 case Tok_AtTag::suspicious: return ""; 675 case Tok_AtTag::missing: return ""; 676 case Tok_AtTag::incomplete: return ""; 677 case Tok_AtTag::version: return ""; 678 case Tok_AtTag::guarantees: return "Guarantees"; 679 case Tok_AtTag::exception: return "Exception"; 680 case Tok_AtTag::since: return "Since version"; 681 default: 682 // See below. 683 ; 684 } 685 return i_rToken.Text(); 686 } 687 688 689 690 } // namespace dsapi 691 } // namespace csi 692 693