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