1 //@copyright_begin
2 // ================================================================
3 // Copyright Notice
4 // Copyright (C) 1998-2004 by Joe Linoff
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the
8 // "Software"), to deal in the Software without restriction, including
9 // without limitation the rights to use, copy, modify, merge, publish,
10 // distribute, sublicense, and/or sell copies of the Software, and to
11 // permit persons to whom the Software is furnished to do so, subject to
12 // the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 // IN NO EVENT SHALL JOE LINOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 // OTHER DEALINGS IN THE SOFTWARE.
24 //
25 // Comments and suggestions are always welcome.
26 // Please report bugs to http://ccdoc.sourceforge.net/ccdoc
27 // ================================================================
28 //@copyright_end
29 #include "statement.h"
30 #include "log.h"
31 #include <algorithm>
32 #include <cstdio>
33 #include <cstring>
34 
35 // ================================================================
36 // This variable allows the header version
37 // to be queried at runtime.
38 // ================================================================
39 namespace {
40   char ccdoc_rcsid[] = "$Id: statement.cc,v 1.15 2004/09/30 04:52:36 jlinoff Exp $";
41 }
42 
43 // ================================================================
44 // String manager.
45 // ================================================================
46 namespace {
47   ccdoc::strmgr s_strmgr;
48 }
get_strmgr()49 ccdoc::strmgr& ccdoc::statement::base::get_strmgr()
50 {
51   // Make sure that all of the terse strings in are
52   // the string table. This guarantees that the db
53   // write will work correctly in terse mode.
54   s_strmgr.get("pub");
55   s_strmgr.get("pro");
56   s_strmgr.get("pri");
57 
58   s_strmgr.get("unk");
59   s_strmgr.get("ign");
60   s_strmgr.get("att");
61   s_strmgr.get("atf");
62   s_strmgr.get("enu");
63   s_strmgr.get("ext");
64   s_strmgr.get("frc");
65   s_strmgr.get("frf");
66   s_strmgr.get("fct");
67   s_strmgr.get("con");
68   s_strmgr.get("des");
69   s_strmgr.get("opr");
70   s_strmgr.get("cls");
71   s_strmgr.get("clx");
72   s_strmgr.get("cod");
73   s_strmgr.get("cop");
74   s_strmgr.get("cos");
75   s_strmgr.get("m00");
76   s_strmgr.get("m01");
77   s_strmgr.get("m0n");
78   s_strmgr.get("mnn");
79   s_strmgr.get("mif");
80   s_strmgr.get("miv");
81   s_strmgr.get("met");
82   s_strmgr.get("nsp");
83   s_strmgr.get("nsx");
84   s_strmgr.get("pkg");
85   s_strmgr.get("str");
86   s_strmgr.get("stx");
87   s_strmgr.get("tyf");
88   s_strmgr.get("tyv");
89   s_strmgr.get("uni");
90   s_strmgr.get("unx");
91   s_strmgr.get("var");
92   s_strmgr.get("vaf");
93 
94   return s_strmgr;
95 }
96 // ================================================================
97 // Constructor
98 // ================================================================
base()99 ccdoc::statement::base::base()
100   : m_comment(0),
101     m_file(0),
102     m_id(0),
103     m_extern(0),
104     m_lineno(0),
105     m_parent(0),
106     m_type(STMT_IGNORE),
107     m_access(STMT_PUBLIC),
108     m_tag(0),
109     m_sorted(true),
110     m_static(false),
111     m_template(false),
112     m_next(0)
113 {
114   set_id(0);
115   set_file(0);
116   set_extern(0);
117 }
118 // ================================================================
119 // Copy Constructor
120 // ================================================================
base(const base & x)121 ccdoc::statement::base::base(const base& x)
122   : m_children(x.m_children),
123     m_comment(x.m_comment),
124     m_file(x.m_file),
125     m_id(x.m_id),
126     m_extern(x.m_extern),
127     m_lineno(x.m_lineno),
128     m_parent(x.m_parent),
129     m_tokens(x.m_tokens),
130     m_type(x.m_type),
131     m_access(x.m_access),
132     m_tag(x.m_tag),
133     m_sorted(x.m_sorted),
134     m_static(x.m_static),
135     m_template(x.m_template),
136     m_next(x.m_next)
137 {
138 }
139 // ================================================================
140 // Copy operator
141 // ================================================================
142 ccdoc::statement::base&
operator =(const base & x)143 ccdoc::statement::base::operator=(const base& x)
144 {
145   m_access   = x.m_access;
146   m_children = x.m_children;
147   m_comment  = x.m_comment;
148   m_file     = x.m_file;
149   m_id       = x.m_id;
150   m_extern   = x.m_extern;
151   m_lineno   = x.m_lineno;
152   m_tag      = x.m_tag;
153   m_parent   = x.m_parent;
154   m_sorted   = x.m_sorted;
155   m_static   = x.m_static;
156   m_template = x.m_template;
157   m_tokens   = x.m_tokens;
158   m_type     = x.m_type;
159 
160   return *this;
161 }
162 // ================================================================
163 // Destructor
164 // ================================================================
~base()165 ccdoc::statement::base::~base()
166 {
167   if( m_parent ) {
168     m_parent->remove_child(this);
169     m_parent = 0;
170   }
171   if( m_comment ) {
172     m_comment->set_comment(0);
173     m_comment = 0;
174   }
175   if( m_children.size() ) {
176     // Make a copy of the children vector
177     // to avoid messing up the iterator.
178     stmts_t vec = m_children;
179     m_children.clear();
180     stmts_itr_t itr = vec.begin();
181     for(;itr!=vec.end();++itr) {
182       base* child = *itr;
183       delete child;
184     }
185   }
186 }
187 // ================================================================
188 // Clear
189 // ================================================================
clear()190 void ccdoc::statement::base::clear()
191 {
192   m_access = STMT_PUBLIC;
193   m_comment = 0;
194   m_children.clear();
195   set_file(0);
196   set_id(0);
197   set_extern(0);
198   m_lineno = 0;
199   m_tag = 0;
200   m_parent = 0;
201   m_tokens.clear();
202   m_type = STMT_IGNORE;
203   m_sorted = false;
204   m_static = false;
205   m_template = false;
206   set_id(0);
207 }
208 // ================================================================
209 // Set string.
210 // ================================================================
set_string(const char * value)211 const char* ccdoc::statement::base::set_string(const char* value)
212 {
213   if(value) {
214     string key = value;
215     const string& p = s_strmgr.get(key);
216     return p.c_str();
217   }
218   return set_string("");
219 }
220 // ================================================================
221 // Set file.
222 // ================================================================
set_file(const char * file)223 void ccdoc::statement::base::set_file(const char* file)
224 {
225   m_file = set_string(file);
226 }
227 // ================================================================
228 // Set the external linkage type.
229 // ================================================================
set_extern(const char * x)230 void ccdoc::statement::base::set_extern(const char* x)
231 {
232   m_extern = set_string(x);
233 }
234 // ================================================================
235 // Set id.
236 // ================================================================
set_id(const char * id)237 void ccdoc::statement::base::set_id(const char* id)
238 {
239   m_id = set_string(id);
240   if( m_parent )
241     m_parent->m_sorted = false;
242 }
243 // ================================================================
244 // Set id.
245 // ================================================================
set_id(const string & id)246 void ccdoc::statement::base::set_id(const string& id)
247 {
248   set_id(id.c_str());
249 }
250 // ================================================================
251 // add token
252 // ================================================================
add_token(const char * str)253 void ccdoc::statement::base::add_token(const char* str)
254 {
255   if(str) {
256     const string& p = s_strmgr.get(str);
257     m_tokens.push_back( p.c_str() );
258   }
259 }
260 // ================================================================
261 // Set tokens.
262 // ================================================================
set_tokens(strs_t & vec)263 void ccdoc::statement::base::set_tokens(strs_t& vec)
264 {
265   m_tokens.clear();
266   strs_itr_t itr = vec.begin();
267   for(;itr!=vec.end();++itr) {
268     string& str = *itr;
269     const string& p = s_strmgr.get(str);
270     m_tokens.push_back( p.c_str() );
271   }
272 }
273 // ================================================================
274 // Get parents.
275 // ================================================================
get_parents(base::stmts_t & parents) const276 void ccdoc::statement::base::get_parents(base::stmts_t& parents) const
277 {
278   if(parents.size())
279     parents.clear();
280   base* stmt = get_parent();
281   while(stmt) {
282     parents.push_back(stmt);
283     stmt = stmt->get_parent();
284   }
285   reverse(parents.begin(),parents.end());
286 }
287 // ================================================================
288 // Get parents, don't include packages.
289 // ================================================================
get_parents_no_pkgs(stmts_t & parents) const290 void ccdoc::statement::base::get_parents_no_pkgs(stmts_t& parents) const
291 {
292   if(parents.size())
293     parents.clear();
294   if( get_type() != STMT_PACKAGE ) {
295     base* stmt = get_parent();
296     while(stmt) {
297       if( stmt->get_type() == STMT_PACKAGE )
298 	break;
299       parents.push_back(stmt);
300       stmt = stmt->get_parent();
301     }
302     reverse(parents.begin(),parents.end());
303   }
304 }
305 // ================================================================
306 // Set parent.
307 // ================================================================
set_parent(base * parent)308 void ccdoc::statement::base::set_parent(base* parent)
309 {
310   if(m_parent) {
311     m_parent->remove_child(this);
312   }
313   m_parent = parent;
314   if(m_parent) {
315     m_parent->add_child(this);
316   }
317 }
318 // ================================================================
319 // Insert before.
320 // ================================================================
insert_before(base * stmt)321 void ccdoc::statement::base::insert_before(base* stmt)
322 {
323   // Insert this after stmt in it's child list.
324   if( stmt ) {
325     if( m_parent ) {
326       m_parent->remove_child(this);
327     }
328     if( stmt->m_parent ) {
329       stmts_t& vec = stmt->m_parent->m_children;
330       stmts_itr_t itr = vec.begin();
331       for(;itr!=m_children.end();++itr) {
332 	if( stmt == *itr ) {
333 	  m_sorted = false;
334 	  vec.insert(itr,this);
335 	  m_parent = stmt->m_parent;
336 	  return;
337 	}
338       }
339     }
340   }
341 }
342 // ================================================================
343 // Insert after.
344 // ================================================================
insert_after(base * stmt)345 void ccdoc::statement::base::insert_after(base* stmt)
346 {
347   // Insert this after stmt in it's child list.
348   if( stmt ) {
349     if( m_parent ) {
350       m_parent->remove_child(this);
351     }
352     if( stmt->m_parent ) {
353       stmts_t& vec = stmt->m_parent->m_children;
354       stmts_itr_t itr = vec.begin();
355       for(;itr!=m_children.end();++itr) {
356 	if( stmt == *itr ) {
357 	  ++itr;
358 	  m_sorted = false;
359 	  if( itr != m_children.end() ) {
360 	    vec.insert(itr,this);
361 	  }
362 	  else {
363 	    vec.push_back(this);
364 	  }
365 	  m_parent = stmt->m_parent;
366 	  return;
367 	}
368       }
369     }
370   }
371 }
372 // ================================================================
373 // Add a child.
374 // ================================================================
add_child(base * child)375 void ccdoc::statement::base::add_child(base* child)
376 {
377   if(child && find_child(child) == false) {
378     if( m_sorted &&
379 	m_children.size() &&
380 	strcmp(m_children.back()->get_id(),child->get_id())>0 )
381       m_sorted = false;
382     m_children.push_back(child);
383     child->m_parent = this;
384   }
385 }
386 // ================================================================
387 // Remove a child.
388 // ================================================================
remove_child(base * child)389 void ccdoc::statement::base::remove_child(base* child)
390 {
391   if(child) {
392     stmts_itr_t itr = m_children.begin();
393     for(;itr!=m_children.end();++itr) {
394       if( *itr == child ) {
395 	child->m_parent = 0;
396 	m_children.erase(itr);
397 	return;
398       }
399     }
400   }
401 }
402 // ================================================================
403 // Get all children, load them into a vector.
404 // ================================================================
get_all_children(stmts_t & children) const405 void ccdoc::statement::base::get_all_children(stmts_t& children) const
406 {
407   stmts_citr_t itr = m_children.begin();
408   for(;itr!=m_children.end();++itr) {
409     statement::base* stmt = *itr;
410     children.push_back(stmt);
411     stmt->get_all_children(children);
412   }
413 }
414 // ================================================================
415 // Get a child by a type and an id name.
416 // ================================================================
417 ccdoc::statement::base*
get_child_by_id_type(const char * id,TYPE t) const418 ccdoc::statement::base::get_child_by_id_type(const char* id,TYPE t) const
419 {
420   if(id) {
421     stmts_citr_t itr = m_children.begin();
422     for(;itr!=m_children.end();++itr) {
423       statement::base* stmt = *itr;
424       if( stmt->get_type() == t && !::strcmp(stmt->get_id(),id) )
425 	return stmt;
426     }
427   }
428   return 0;
429 }
430 // ================================================================
431 // Get a child by a type and an id name.
432 // ================================================================
433 ccdoc::statement::base*
get_child_by_id_type(const string & id,TYPE t) const434 ccdoc::statement::base::get_child_by_id_type(const string& id,TYPE t) const
435 {
436   return get_child_by_id_type(id.c_str(),t);
437 }
438 // ================================================================
439 // Get a child by an id name.
440 // ================================================================
441 ccdoc::statement::base*
get_child_by_id(const char * id) const442 ccdoc::statement::base::get_child_by_id(const char* id) const
443 {
444   if(id) {
445     stmts_citr_t itr = m_children.begin();
446     for(;itr!=m_children.end();++itr) {
447       statement::base* stmt = *itr;
448       if( !::strcmp(stmt->get_id(),id) )
449 	return stmt;
450     }
451   }
452   return 0;
453 }
454 // ================================================================
455 // Get a child by an id name.
456 // ================================================================
457 ccdoc::statement::base*
get_child_by_id(const string & id) const458 ccdoc::statement::base::get_child_by_id(const string& id) const
459 {
460   return get_child_by_id(id.c_str());
461 }
462 // ================================================================
463 // Find a child.
464 // ================================================================
find_child(base * child) const465 bool ccdoc::statement::base::find_child(base* child) const
466 {
467   if(child) {
468     stmts_citr_t itr = m_children.begin();
469     for(;itr!=m_children.end();++itr) {
470       if( *itr == child )
471 	return true;
472     }
473   }
474   return false;
475 }
476 // ================================================================
477 // Get children by an id name.
478 // ================================================================
get_children_by_id(stmts_t & vec,const char * id)479 bool ccdoc::statement::base::get_children_by_id(stmts_t& vec,
480 						const char* id)
481 {
482   bool st = false;
483   if(id) {
484     stmts_itr_t itr = search(id);
485     for(;itr!=m_children.end();++itr) {
486       statement::base* stmt = *itr;
487       if( !::strcmp(stmt->get_id(),id) ) {
488 	st = true;
489 	vec.push_back(stmt);
490       }
491       else {
492 	break;
493       }
494     }
495   }
496   return st;
497 }
498 // ================================================================
499 // Get children by an id name.
500 // ================================================================
get_children_by_id(stmts_t & vec,const string & id)501 bool ccdoc::statement::base::get_children_by_id(stmts_t& vec,
502 						const string& id)
503 {
504   return get_children_by_id(vec,id.c_str());
505 }
506 // ================================================================
507 // Get hier id.
508 // ================================================================
get_hier_id(string & id) const509 void ccdoc::statement::base::get_hier_id(string& id) const
510 {
511   id = "";
512   if(get_parent()) {
513     strs_t vec;
514     const base* x = this;
515     while( x ) {
516       vec.push_back(x->get_id());
517       x = x->get_parent();
518     }
519 
520     strs_ritr_t itr = vec.rbegin();
521     for(;itr!=vec.rend();++itr) {
522       id += "::";
523       id += *itr;
524     }
525   }
526 }
527 // ================================================================
528 // Get hier id, don't include packages.
529 // ================================================================
get_hier_id_no_pkgs(string & id) const530 void ccdoc::statement::base::get_hier_id_no_pkgs(string& id) const
531 {
532   id = "";
533   if(get_parent()) {
534     strs_t vec;
535     const base* x = this;
536     while( x ) {
537       if( x->get_type() == STMT_PACKAGE )
538 	break;
539       vec.push_back(x->get_id());
540       x = x->get_parent();
541     }
542 
543     if( vec.size() ) {
544       strs_ritr_t itr = vec.rbegin();
545       if( itr != vec.rend() )
546 	id += *itr;
547       for(++itr;itr!=vec.rend();++itr) {
548 	id += "::";
549 	id += *itr;
550       }
551     }
552   }
553 }
554 // ================================================================
555 // Get the access name.
556 // ================================================================
get_access_name(ACCESS a)557 const char* ccdoc::statement::base::get_access_name(ACCESS a)
558 {
559   switch(a) {
560   case STMT_PUBLIC:    return "public";
561   case STMT_PROTECTED: return "protected";
562   case STMT_PRIVATE:   return "private";
563   default: break;
564   }
565   return "unknown";
566 }
567 // ================================================================
568 // Get the terse access name.
569 // ================================================================
get_terse_access_name(ACCESS a)570 const char* ccdoc::statement::base::get_terse_access_name(ACCESS a)
571 {
572   switch(a) {
573   case STMT_PUBLIC:    return "pub";
574   case STMT_PROTECTED: return "pro";
575   case STMT_PRIVATE:   return "pri";
576   default: break;
577   }
578   return "unknown";
579 }
580 // ================================================================
581 // Get the terse access name.
582 // ================================================================
583 ccdoc::statement::base::ACCESS
get_terse_access(const string & token)584 ccdoc::statement::base::get_terse_access(const string& token)
585 {
586   if( token == "pro" ) return STMT_PROTECTED;
587   if( token == "pri" ) return STMT_PRIVATE;
588   return STMT_PUBLIC;
589 }
590 // ================================================================
591 // Get the full type name in lower case with static prepended.
592 // ================================================================
get_type_name2() const593 string ccdoc::statement::base::get_type_name2() const
594 {
595   string name;
596 
597   // Issue 0144:
598   if( m_static )
599     name += "static ";
600 
601   // Issue 0122:
602   if( m_template )
603     name += "template ";
604 
605   name += get_type_name1();
606   return name;
607 }
608 // ================================================================
609 // Get the full type name in lower case.
610 // ================================================================
get_type_name1(TYPE t)611 const char* ccdoc::statement::base::get_type_name1(TYPE t)
612 {
613   switch(t) {
614   case STMT_ATTRIBUTE:            return "attribute";
615   case STMT_ATTRIBUTE_FUNCTION:   return "attribute";
616   case STMT_ENUM:                 return "enum";
617   case STMT_FRIEND_FUNCTION:      return "friend";
618   case STMT_FUNCTION:             return "function";
619   case STMT_FUNCTION_OPERATOR:    return "operator";
620   case STMT_CLASS_BEGIN:          return "class";
621   case STMT_MACRODEF_0_0:         return "macro";
622   case STMT_MACRODEF_0_1:         return "macro";
623   case STMT_MACRODEF_0_N:         return "macro";
624   case STMT_MACRODEF_N_N:         return "macro";
625   case STMT_MACROINST_FUNCTION:   return "macroinst";
626   case STMT_MACROINST_VARIABLE:   return "macroinst";
627   case STMT_METHOD:               return "method";
628   case STMT_METHOD_CONSTRUCTOR:   return "constructor";
629   case STMT_METHOD_DESTRUCTOR:    return "destructor";
630   case STMT_METHOD_OPERATOR:      return "operator";
631   case STMT_NAMESPACE_BEGIN:      return "namespace";
632   case STMT_PACKAGE:              return "package";
633   case STMT_STRUCT_BEGIN:         return "struct";
634   case STMT_TYPEDEF_FUNCTION:     return "typedef";
635   case STMT_TYPEDEF_VARIABLE:     return "typedef";
636   case STMT_UNION_BEGIN:          return "union";
637   case STMT_VARIABLE:             return "variable";
638   case STMT_VARIABLE_FUNCTION:    return "variable";
639   default: break;
640   }
641   return get_type_name(t);
642 }
643 // ================================================================
644 // Get the type name.
645 // ================================================================
get_type_name(TYPE t)646 const char* ccdoc::statement::base::get_type_name(TYPE t)
647 {
648   switch(t) {
649   case STMT_IGNORE:               return "IGNORE";
650   case STMT_ATTRIBUTE:            return "ATTRIBUTE";
651   case STMT_ATTRIBUTE_FUNCTION:   return "ATTRIBUTE_FUNCTION";
652   case STMT_ENUM:                 return "ENUM";
653   case STMT_EXTERN:               return "EXTERN";
654   case STMT_FRIEND_CLASS:         return "FRIEND_CLASS";
655   case STMT_FRIEND_FUNCTION:      return "FRIEND_FUNCTION";
656   case STMT_FUNCTION:             return "FUNCTION";
657   case STMT_FUNCTION_OPERATOR:    return "FUNCTION_OPERATOR";
658   case STMT_CLASS_BEGIN:          return "CLASS_BEGIN";
659   case STMT_CLASS_END:            return "CLASS_END";
660   case STMT_COMMENT_PKGDOC:       return "COMMENT_PKGDOC";
661   case STMT_COMMENT_PKGDOC_URL:   return "COMMENT_PKGDOC_URL";
662   case STMT_COMMENT_PREFIX:       return "COMMENT_PREFIX";
663   case STMT_COMMENT_SUFFIX:       return "COMMENT_SUFFIX";
664   case STMT_MACRODEF_0_0:         return "MACRODEF_0_0";
665   case STMT_MACRODEF_0_1:         return "MACRODEF_0_1";
666   case STMT_MACRODEF_0_N:         return "MACRODEF_0_N";
667   case STMT_MACRODEF_N_N:         return "MACRODEF_N_N";
668   case STMT_MACROINST_FUNCTION:   return "MACROINST_FUNCTION";
669   case STMT_MACROINST_VARIABLE:   return "MACROINST_VARIABLE";
670   case STMT_METHOD:               return "METHOD";
671   case STMT_METHOD_CONSTRUCTOR:   return "METHOD_CONSTRUCTOR";
672   case STMT_METHOD_DESTRUCTOR:    return "METHOD_DESTRUCTOR";
673   case STMT_METHOD_OPERATOR:      return "METHOD_OPERATOR";
674   case STMT_NAMESPACE_BEGIN:      return "NAMESPACE_BEGIN";
675   case STMT_NAMESPACE_END:        return "NAMESPACE_END";
676   case STMT_PACKAGE:              return "PACKAGE";
677   case STMT_STRUCT_BEGIN:         return "STRUCT_BEGIN";
678   case STMT_STRUCT_END:           return "STRUCT_END";
679   case STMT_TYPEDEF_FUNCTION:     return "TYPEDEF_FUNCTION";
680   case STMT_TYPEDEF_VARIABLE:     return "TYPEDEF_VARIABLE";
681   case STMT_UNION_BEGIN:          return "UNION_BEGIN";
682   case STMT_UNION_END:            return "UNION_END";
683   case STMT_VARIABLE:             return "VARIABLE";
684   case STMT_VARIABLE_FUNCTION:    return "VARIABLE_FUNCTION";
685   default: break;
686   }
687   return "UNKNOWN";
688 }
689 // ================================================================
690 // Get the terse type name.
691 // ================================================================
get_terse_type_name(TYPE t)692 const char* ccdoc::statement::base::get_terse_type_name(TYPE t)
693 {
694   switch(t) {
695   case STMT_IGNORE:               return "ign";
696   case STMT_ATTRIBUTE:            return "att";
697   case STMT_ATTRIBUTE_FUNCTION:   return "atf";
698   case STMT_ENUM:                 return "enu";
699   case STMT_EXTERN:               return "ext";
700   case STMT_FRIEND_CLASS:         return "frc";
701   case STMT_FRIEND_FUNCTION:      return "frf";
702   case STMT_FUNCTION:             return "fct";
703   case STMT_FUNCTION_OPERATOR:    return "opr";
704   case STMT_CLASS_BEGIN:          return "cls";
705   case STMT_CLASS_END:            return "clx";
706   case STMT_COMMENT_PKGDOC:       return "cod";
707   case STMT_COMMENT_PKGDOC_URL:   return "cou";
708   case STMT_COMMENT_PREFIX:       return "cop";
709   case STMT_COMMENT_SUFFIX:       return "cos";
710   case STMT_MACRODEF_0_0:         return "m00";
711   case STMT_MACRODEF_0_1:         return "m01";
712   case STMT_MACRODEF_0_N:         return "m0n";
713   case STMT_MACRODEF_N_N:         return "mnn";
714   case STMT_MACROINST_FUNCTION:   return "mif";
715   case STMT_MACROINST_VARIABLE:   return "miv";
716   case STMT_METHOD:               return "met";
717   case STMT_METHOD_CONSTRUCTOR:   return "con";
718   case STMT_METHOD_DESTRUCTOR:    return "des";
719   case STMT_METHOD_OPERATOR:      return "mop";
720   case STMT_NAMESPACE_BEGIN:      return "nsp";
721   case STMT_NAMESPACE_END:        return "nsx";
722   case STMT_PACKAGE:              return "pkg";
723   case STMT_STRUCT_BEGIN:         return "str";
724   case STMT_STRUCT_END:           return "stx";
725   case STMT_TYPEDEF_FUNCTION:     return "tyf";
726   case STMT_TYPEDEF_VARIABLE:     return "tyv";
727   case STMT_UNION_BEGIN:          return "uni";
728   case STMT_UNION_END:            return "unx";
729   case STMT_VARIABLE:             return "var";
730   case STMT_VARIABLE_FUNCTION:    return "vaf";
731   default: break;
732   }
733   return "unk";
734 }
735 // ================================================================
736 // Get the terse type name.
737 // ================================================================
738 ccdoc::statement::base::TYPE
get_terse_type(const string & token)739 ccdoc::statement::base::get_terse_type(const string& token)
740 {
741   if(token == "ign" ) return STMT_IGNORE              ;
742   if(token == "att" ) return STMT_ATTRIBUTE           ;
743   if(token == "atf" ) return STMT_ATTRIBUTE_FUNCTION  ;
744   if(token == "enu" ) return STMT_ENUM                ;
745   if(token == "ext" ) return STMT_EXTERN              ;
746   if(token == "frc" ) return STMT_FRIEND_CLASS        ;
747   if(token == "frf" ) return STMT_FRIEND_FUNCTION     ;
748   if(token == "fct" ) return STMT_FUNCTION            ;
749   if(token == "opr" ) return STMT_FUNCTION_OPERATOR   ;
750   if(token == "cls" ) return STMT_CLASS_BEGIN         ;
751   if(token == "clx" ) return STMT_CLASS_END           ;
752   if(token == "cod" ) return STMT_COMMENT_PKGDOC      ;
753   if(token == "cou" ) return STMT_COMMENT_PKGDOC_URL  ;
754   if(token == "cop" ) return STMT_COMMENT_PREFIX      ;
755   if(token == "cos" ) return STMT_COMMENT_SUFFIX      ;
756   if(token == "m00" ) return STMT_MACRODEF_0_0        ;
757   if(token == "m01" ) return STMT_MACRODEF_0_1        ;
758   if(token == "m0n" ) return STMT_MACRODEF_0_N        ;
759   if(token == "mnn" ) return STMT_MACRODEF_N_N        ;
760   if(token == "mif" ) return STMT_MACROINST_FUNCTION  ;
761   if(token == "miv" ) return STMT_MACROINST_VARIABLE  ;
762   if(token == "met" ) return STMT_METHOD              ;
763   if(token == "con" ) return STMT_METHOD_CONSTRUCTOR  ;
764   if(token == "des" ) return STMT_METHOD_DESTRUCTOR   ;
765   if(token == "mop" ) return STMT_METHOD_OPERATOR     ;
766   if(token == "nsp" ) return STMT_NAMESPACE_BEGIN     ;
767   if(token == "nsx" ) return STMT_NAMESPACE_END       ;
768   if(token == "pkg" ) return STMT_PACKAGE             ;
769   if(token == "str" ) return STMT_STRUCT_BEGIN        ;
770   if(token == "stx" ) return STMT_STRUCT_END          ;
771   if(token == "tyf" ) return STMT_TYPEDEF_FUNCTION    ;
772   if(token == "tyv" ) return STMT_TYPEDEF_VARIABLE    ;
773   if(token == "uni" ) return STMT_UNION_BEGIN         ;
774   if(token == "unx" ) return STMT_UNION_END           ;
775   if(token == "var" ) return STMT_VARIABLE            ;
776   if(token == "vaf" ) return STMT_VARIABLE_FUNCTION   ;
777   return STMT_IGNORE;
778 }
779 // ================================================================
780 // Get depth.
781 // ================================================================
get_depth() const782 unsigned ccdoc::statement::base::get_depth() const
783 {
784   // The top always returns zero.
785   unsigned depth = 0;
786   base* stmt = get_parent();
787   while(stmt) {
788     depth++;
789     stmt = stmt->get_parent();
790   }
791   return depth;
792 }
793 // ================================================================
794 // Get depth.
795 // ================================================================
get_depth_no_pkgs() const796 unsigned ccdoc::statement::base::get_depth_no_pkgs() const
797 {
798   // The top always returns zero.
799   unsigned depth = 0;
800   base* stmt = get_parent();
801   while(stmt && stmt->get_type() != STMT_PACKAGE ) {
802     depth++;
803     stmt = stmt->get_parent();
804   }
805   return depth;
806 }
807 // ================================================================
808 // Get the matching begin statement.
809 // ================================================================
810 ccdoc::statement::base*
get_matching_begin() const811 ccdoc::statement::base::get_matching_begin() const
812 {
813   switch( get_type() ) {
814   case STMT_CLASS_END:
815     return get_matching_begin(STMT_CLASS_BEGIN);
816     break;
817   case STMT_STRUCT_END:
818     return get_matching_begin(STMT_STRUCT_BEGIN);
819     break;
820   case STMT_UNION_END:
821     return get_matching_begin(STMT_UNION_BEGIN);
822     break;
823   default:
824     break;
825   }
826   return 0;
827 }
828 // ================================================================
829 // Get the matching begin statement.
830 // ================================================================
831 ccdoc::statement::base*
get_matching_begin(TYPE t) const832 ccdoc::statement::base::get_matching_begin(TYPE t) const
833 {
834   unsigned depth = get_depth();
835   base* parent = get_parent();
836   if( parent ) {
837     stmts_t& vec = parent->get_children();
838     stmts_itr_t itr = vec.begin();
839     for(;itr!=vec.end();++itr) {
840       if( *itr == this ) {
841 	// Found the end statement.
842 	// Now back up to the enclosing begin.
843 	for(;itr!=vec.begin();--itr) {
844 	  base* begin = *itr;
845 	  if( begin->get_type() == t && begin->get_depth() == depth )
846 	    return begin;
847 	}
848 	break;
849       }
850     }
851   }
852   return 0;
853 }
854 // ================================================================
855 // Local sort compare.
856 // ================================================================
857 namespace
858 {
compare_stmts(const ccdoc::statement::base * a,const ccdoc::statement::base * b)859   bool compare_stmts(const ccdoc::statement::base* a,
860                      const ccdoc::statement::base* b)
861   {
862     return strcmp(a->get_id(),b->get_id()) < 0;
863   }
864 }
865 // ================================================================
866 // Sort
867 // ================================================================
sort_children()868 void ccdoc::statement::base::sort_children()
869 {
870   if( !m_sorted ) {
871     stable_sort(m_children.begin(),m_children.end(),compare_stmts);
872     m_sorted = true;
873   }
874 }
875 // ================================================================
876 // Binary search
877 // ================================================================
878 ccdoc::statement::base::stmts_itr_t
search(const char * name)879 ccdoc::statement::base::search(const char* name)
880 {
881   if( name ) {
882     if( m_children.size() ) {
883       if( !m_sorted )
884 	sort_children();
885 
886       // Check the first record.
887       base* stmt = m_children[0];
888       if( !strcmp(stmt->get_id(),name) ) {
889 	return m_children.begin();
890       }
891 
892       // Check all of the other records.
893       unsigned top = m_children.size()-1;
894       unsigned bot = 0;
895       unsigned cnt = 0;
896       while( top>bot ) {
897 	unsigned delta = top-bot;
898 	unsigned mid = bot + ((delta+1)/2);
899 	stmt = m_children[mid];
900 	int cmp = strcmp(stmt->get_id(),name);
901 	if( cmp == 0 ) {
902 	  stmts_itr_t itr = m_children.begin();
903 	  if( mid ) {
904 	    itr += mid;
905 	    // Backup to the 1st one (duplicates are allowed).
906 	    stmts_itr_t itr1 = itr;
907 	    for(;;) {
908 	      --itr1;
909 	      stmt = *itr1;
910 	      if( strcmp(stmt->get_id(),name) ) {
911 		++itr1;
912 		itr = itr1;
913 		break;
914 	      }
915 	      if( itr1 == m_children.begin() ) {
916 		// The names match but we are at the beginning.
917 		itr = itr1;
918 		break;
919 	      }
920 	    }
921 	  }
922 	  return itr;
923 	}
924 	if( cmp > 0 ) {
925 	  top = mid;
926 	}
927 	else {
928 	  bot = mid;
929 	}
930 	if(++cnt>32)
931 	  break;
932       }
933     }
934   }
935   return m_children.end();
936 }
937 // ================================================================
938 // Binary search
939 // ================================================================
940 ccdoc::statement::base::stmts_itr_t
search(const string & name)941 ccdoc::statement::base::search(const string& name)
942 {
943   return search(name.c_str());
944 }
945 // ================================================================
946 // is_rptmac1_id
947 // ================================================================
is_rptmac1_id() const948 bool ccdoc::statement::base::is_rptmac1_id() const
949 {
950   return is_rptmac1_id(get_id());
951 }
952 // ================================================================
953 // is_rptmac1_id
954 // ================================================================
is_rptmac1_id(const char * id)955 bool ccdoc::statement::base::is_rptmac1_id(const char* id)
956 {
957   if( !id )
958     return false;
959 
960   // ================================================
961   // In heuristic mode ignore all macro definitions
962   // that have the following characteristics:
963   //   - Prefixes:
964   //      dll_,DLL_
965   //      include_,INCLUDE_,
966   //      included_,INCLUDED_,
967   //   - Suffixes:
968   //      _dll,_DLL
969   //      _h,_H,
970   //      _hh,_HH,
971   //      _include,_INCLUDE,
972   //      _included,_INCLUDED,
973   //      _included_,_INCLUDED_,
974   // More heuristics will be added over time as
975   // requested.
976   // ================================================
977 
978   // ================================================
979   // Define the search strings.
980   // ================================================
981   const char* prefixes[] = {
982     "dll_"     , "DLL_"     ,
983     "include_" , "INCLUDE_" ,
984     "included_", "INCLUDED_",
985     0 };
986   const char* suffixes[] = {
987     "_dll"      , "_DLL"      ,
988     "_h"        , "_H"        ,
989     "_hh"       , "_HH"       ,
990     "_include"  , "_INCLUDE"  ,
991     "_included" , "_INCLUDED" ,
992     "_included_", "_INCLUDED_",
993     0 };
994   // ================================================
995   // Check the prefixes.
996   // ================================================
997   {for(int i=0;prefixes[i];++i) {
998     const char* p1 = id;
999     const char* p2 = prefixes[i];
1000     for(;*p1 && *p2 && *p1 == *p2;++p1,++p2)
1001       ;
1002     if( *p2 == 0 )
1003       return true;
1004   }}
1005   // ================================================
1006   // Check the suffixes.
1007   // ================================================
1008   {for(int i=0;suffixes[i];++i) {
1009     const char* p1 = id;
1010     const char* p1e = p1;
1011     const char* p2 = suffixes[i];
1012     const char* p2e = p2;
1013 
1014     // Point to the end of the strings.
1015     for(;*p1e;++p1e)
1016       ;
1017     for(;*p2e;++p2e)
1018       ;
1019 
1020     // Compare backwards.
1021     for(;p1e!=p1 && p2e!=p2 && *p1e == *p2e;--p1e,--p2e)
1022       ;
1023     if( p2e == p2 && *p1e == *p2e )
1024       return true;
1025   }}
1026   return false;
1027 }
1028 // ================================================================
1029 // Debug dump
1030 // ================================================================
debug_dump(const char * prefix)1031 void ccdoc::statement::base::debug_dump(const char* prefix)
1032 {
1033   string p;
1034   if(prefix)
1035     p = prefix;
1036 
1037   string hid;
1038   get_hier_id(hid);
1039 
1040   s_log << p << "stmt: begin: ================================================\n";
1041   s_log << p << "stmt: id:     '" << get_id() << "'\n";
1042   s_log << p << "stmt: hid:    '" << hid << "'\n";
1043   s_log << p << "stmt: type:   " << get_type_name() << "\n";
1044   s_log << p << "stmt: access: " << get_access_name() << "\n";
1045   s_log << p << "stmt: depth:  " << get_depth() << "\n";
1046 
1047   s_log << p << "stmt: file:   '" << get_file() << "'\n";
1048   s_log << p << "stmt: lineno: " << get_lineno() << "\n";
1049   s_log << p << "stmt: extern: '" << get_extern() << "'\n";
1050 
1051   if( m_comment ) {
1052     m_comment->get_hier_id(hid);
1053     s_log << p << "stmt: ctype:  " << m_comment->get_type_name() << "'\n";
1054     s_log << p << "stmt: cid:    '" << hid << "'\n";
1055   }
1056   else {
1057     s_log << p << "stmt: ctype:\n";
1058     s_log << p << "stmt: cid:    ''\n";
1059   }
1060 
1061   // Children
1062   s_log << p << "stmt: nch:    " << m_children.size() << "\n";
1063   if( m_children.size() ) {
1064     stmts_itr_t itr = m_children.begin();
1065     for(int i=0;itr!=m_children.end();++itr,++i) {
1066       s_log << p << "stmt:   child[" << i << "]: "
1067 	    << (*itr)->get_type_name()
1068 	    << ": '"
1069 	;
1070       (*itr)->get_hier_id(hid);
1071       s_log << hid << "'\n";
1072     }
1073   }
1074 
1075   switch( m_type ) {
1076   case STMT_COMMENT_PKGDOC:
1077   case STMT_COMMENT_PKGDOC_URL:
1078   case STMT_COMMENT_PREFIX:
1079   case STMT_COMMENT_SUFFIX:
1080     {
1081       s_log << p << "stmt: ccdoc_begin\n";
1082       cstrs_itr_t itr = m_tokens.begin();
1083       for(;itr!=m_tokens.end();++itr) {
1084 	s_log << p << "stmt:   token: '" << (*itr);
1085 	s_log << "'\n";
1086       }
1087       s_log << p << "stmt: ccdoc_end\n";
1088       break;
1089     }
1090   case STMT_CLASS_END:
1091   case STMT_NAMESPACE_END:
1092   case STMT_STRUCT_END:
1093   case STMT_UNION_END:
1094     // Ignore hier-id and tokens for end statements.
1095     break;
1096   default:
1097     {
1098       s_log << p << "stmt: tokens:";
1099       cstrs_itr_t itr = m_tokens.begin();
1100       for(;itr!=m_tokens.end();++itr) {
1101 	s_log << " " << (*itr);
1102       }
1103       s_log << "\n";
1104       break;
1105     }
1106   }
1107   s_log << p << "stmt: end\n";
1108 }
1109 // ================================================================
1110 //
1111 // Comment class.
1112 //
1113 // ================================================================
1114 // ================================================================
1115 // Constructor
1116 // ================================================================
comment()1117 ccdoc::statement::comment::comment()
1118   : m_stmt(0),
1119     m_suffix(false)
1120 {
1121 }
1122 // ================================================================
1123 // Constructor
1124 // ================================================================
comment(base * stmt)1125 ccdoc::statement::comment::comment(base* stmt)
1126   :  m_stmt(stmt),
1127      m_suffix(false)
1128 {
1129   if(stmt) {
1130     set(stmt->get_tokens());
1131   }
1132 }
1133 // ================================================================
1134 // Destructor
1135 // ================================================================
~comment()1136 ccdoc::statement::comment::~comment()
1137 {
1138 }
1139 // ================================================================
1140 // Set
1141 // ================================================================
set(const base::cstrs_t & tokens)1142 void ccdoc::statement::comment::set(const base::cstrs_t& tokens)
1143 {
1144   base::cstrs_citr_t i = tokens.begin();
1145   base::cstrs_citr_t e = tokens.end();
1146 
1147   string token;
1148   if(!set(token,i,e,"@{"   )) return;
1149 
1150   if(!set(token,i,e,"@file")) return;
1151   if(!set(token,i,e,"2")) return;
1152   if(!set(token,i,e)) return;
1153   add_file(token);
1154   if(!set(token,i,e)) return;
1155   add_lineno(token);
1156 
1157   if(!set_scalar(token,i,e,"@type")) return;
1158   m_suffix = token == "@suffix";
1159 
1160   if(!set       (m_short_desc,i,e,"@short_desc")) return;
1161   if(!set       (m_long_desc ,i,e,"@long_desc")) return;
1162   if(!set       (m_params    ,i,e,"@params","@param")) return;
1163   if(!set       (m_returns   ,i,e,"@returns")) return;
1164   if(!set       (m_exceptions,i,e,"@exceptions","@exception")) return;
1165   if(!set       (m_deprecated,i,e,"@deprecated")) return;
1166   if(!set       (m_authors   ,i,e,"@authors")) return;
1167   if(!set_scalar(m_version   ,i,e,"@version")) return;
1168   if(!set       (m_sees      ,i,e,"@sees","@see")) return;
1169   if(!set_scalar(m_since     ,i,e,"@since")) return;
1170   if(!set_scalar(m_source    ,i,e,"@source")) return;
1171   if(!set       (m_pkg       ,i,e,"@pkg")) return;
1172   if(!set       (m_pkgdoc    ,i,e,"@pkgdoc")) return;
1173   if(!set       (m_todo      ,i,e,"@todo")) return; // Issue 0120
1174   if(!set       (token       ,i,e,"@}")) return;
1175 }
1176 // ================================================================
1177 // Set scalar token
1178 // ================================================================
set_scalar(string & var,base::cstrs_citr_t & i,base::cstrs_citr_t & e,const char * match)1179 bool ccdoc::statement::comment::set_scalar(string& var,
1180 					   base::cstrs_citr_t& i,
1181 					   base::cstrs_citr_t& e,
1182 					   const char* match)
1183 {
1184   string token;
1185   if(!set(token,i,e,match)) return false;
1186   if(!set(token,i,e)) return false;
1187   if( token == "1" ) {
1188     if(!set(var,i,e)) return false;
1189   }
1190   else if( token != "0" ) {
1191     // Issue 0053
1192     s_log.warning() << "Internal comment parsing error";
1193     if(m_stmt) {
1194       s_log << " at line " << m_stmt->get_lineno()
1195 	    << " in " << m_stmt->get_file();
1196     }
1197     s_log << ".\n"
1198 	  << "\tExpected 0 or 1 for the number of " << match << " arguments.\n"
1199 	  << "\tThis comment will be ignored.\n"
1200 	  << s_log.enable();
1201     clear();
1202     return false;
1203   }
1204   return true;
1205 }
1206 // ================================================================
1207 // Set token
1208 // ================================================================
set(string & token,base::cstrs_citr_t & i,base::cstrs_citr_t & e,const char * match)1209 bool ccdoc::statement::comment::set(string& token,
1210 				    base::cstrs_citr_t& i,
1211 				    base::cstrs_citr_t& e,
1212 				    const char* match)
1213 {
1214   if(i == e) {
1215     s_log.warning() << "Internal comment parsing error, empty list";
1216     if(m_stmt) {
1217       // Issue 0053
1218       s_log << " at line " << m_stmt->get_lineno()
1219 	    << " in " << m_stmt->get_file();
1220     }
1221     s_log << ".\n"
1222 	  << "\tUnexpected EOF for '" << token <<"'.\n"
1223 	  << "\tThis comment will be ignored.\n"
1224 	  << s_log.enable();
1225     clear();
1226     return false;
1227   }
1228   if( match && *match && ::strcmp(*i,match) ) {
1229     // Match failed, report a warning.
1230     s_log.warning() << "Internal comment parsing error, match failed";
1231     if(m_stmt) {
1232       // Issue 0053
1233       s_log << " at line " << m_stmt->get_lineno()
1234 	    << " in " << m_stmt->get_file();
1235     }
1236     s_log << ".\n"
1237 	  << "\tExpected token '" << match << "' but found '" << *i << "'.\n"
1238 	  << "\tThis comment will be ignored.\n"
1239 	  << s_log.enable();
1240     clear();
1241     return false;
1242   }
1243   token = *i;
1244   ++i;
1245   return true;
1246 }
1247 // ================================================================
1248 // Set token
1249 // ================================================================
set(base::strs_t & vec,base::cstrs_citr_t & i,base::cstrs_citr_t & e,const char * match)1250 bool ccdoc::statement::comment::set(base::strs_t& vec,
1251 				    base::cstrs_citr_t& i,
1252 				    base::cstrs_citr_t& e,
1253 				    const char* match)
1254 {
1255   string token;
1256   if(!set(token,i,e,match)) return false;
1257   if(!set(token,i,e)) return false;
1258   unsigned k = atoi(token.c_str());
1259   for(unsigned j=0;j<k;++j) {
1260     if(!set(token,i,e)) return false;
1261     vec.push_back(token);
1262   }
1263   return true;
1264 }
1265 // ================================================================
1266 // Set token
1267 // ================================================================
set(base::strss_t & vecvec,base::cstrs_citr_t & i,base::cstrs_citr_t & e,const char * match,const char * match1)1268 bool ccdoc::statement::comment::set(base::strss_t& vecvec,
1269 				    base::cstrs_citr_t& i,
1270 				    base::cstrs_citr_t& e,
1271 				    const char* match,
1272 				    const char* match1)
1273 {
1274   string token;
1275   if(!set(token,i,e,match)) return false;
1276   if(!set(token,i,e)) return false;
1277   unsigned k = atoi(token.c_str());
1278   for(unsigned j=0;j<k;++j) {
1279     base::strs_t vec;
1280     if(!set(vec,i,e,match1)) return false;
1281     vecvec.push_back(vec);
1282   }
1283   return true;
1284 }
1285 // ================================================================
1286 // Get.
1287 // ================================================================
get(base::strs_t & tokens)1288 void ccdoc::statement::comment::get(base::strs_t& tokens)
1289 {
1290 
1291   tokens.push_back("@{");
1292   tokens.push_back("@file");
1293   tokens.push_back("2");
1294   tokens.push_back(m_file);
1295   tokens.push_back(m_lineno);
1296   tokens.push_back("@type");
1297   tokens.push_back("1");
1298   if( m_suffix ) {
1299     tokens.push_back("@suffix");
1300   }
1301   else {
1302     tokens.push_back("@prefix");
1303   }
1304   get( tokens, m_short_desc, "@short_desc" );
1305   get( tokens, m_long_desc, "@long_desc" );
1306   get( tokens, m_params, "@param" );
1307   get( tokens, m_returns, "@returns" );
1308   get( tokens, m_exceptions, "@exception" );
1309   get( tokens, m_deprecated, "@deprecated" );
1310   get( tokens, m_authors, "@authors" );
1311   if( m_version.size() ) {
1312     tokens.push_back("@version");
1313     tokens.push_back( "1" );
1314     tokens.push_back( m_version );
1315   }
1316   else {
1317     tokens.push_back("@version");
1318     tokens.push_back("0");
1319   }
1320   get( tokens, m_sees, "@see" );
1321 
1322   tokens.push_back("@since");
1323   if( m_since.size() ) {
1324     tokens.push_back("1");
1325     tokens.push_back(m_since);
1326   }
1327   else {
1328     tokens.push_back("0");
1329   }
1330 
1331   tokens.push_back("@source");
1332   if( m_source.size() ) {
1333     tokens.push_back("1");
1334     tokens.push_back(m_source);
1335   }
1336   else {
1337     tokens.push_back("0");
1338   }
1339   get( tokens, m_pkg, "@pkg" );
1340   get( tokens, m_pkgdoc, "@pkgdoc" );
1341   get( tokens, m_todo, "@todo" ); // Issue 0120
1342   tokens.push_back("@}");
1343 }
1344 // ================================================================
1345 // Get.
1346 // ================================================================
get(base::strs_t & tokens,const base::strs_t & vec,const char * type)1347 void ccdoc::statement::comment::get(base::strs_t& tokens,
1348 				    const base::strs_t& vec,
1349 				    const char* type)
1350 {
1351   if(vec.size()) {
1352     char nbuf[16];
1353     sprintf(nbuf,"%d",vec.size());
1354 
1355     tokens.push_back(type);
1356     tokens.push_back(nbuf);
1357 
1358     base::strs_citr_t itr = vec.begin();
1359     for(;itr!=vec.end();++itr) {
1360       tokens.push_back(*itr);
1361     }
1362   }
1363   else {
1364     tokens.push_back(type);
1365     tokens.push_back("0");
1366   }
1367 }
1368 // ================================================================
1369 // Insert tokens
1370 // ================================================================
get(base::strs_t & tokens,base::strss_t & vecvec,const char * type)1371 void ccdoc::statement::comment::get(base::strs_t& tokens,
1372 				    base::strss_t& vecvec,
1373 				    const char* type)
1374 {
1375   string x = type;
1376   x += "s";
1377   if( vecvec.size() ) {
1378     tokens.push_back(x);
1379     char nbuf[16];
1380     sprintf(nbuf,"%d",vecvec.size());
1381     tokens.push_back(nbuf);
1382     base::strss_itr_t itr = vecvec.begin();
1383     for(;itr!=vecvec.end();++itr) {
1384       base::strs_t& vec = *itr;
1385 
1386       sprintf(nbuf,"%d",vec.size());
1387 
1388       tokens.push_back(type);
1389       tokens.push_back(nbuf);
1390 
1391       base::strs_citr_t itr1 = vec.begin();
1392       for(;itr1!=vec.end();++itr1) {
1393 	tokens.push_back(*itr1);
1394       }
1395     }
1396   }
1397   else {
1398     tokens.push_back(x);
1399     tokens.push_back("0");
1400   }
1401 }
1402 // ================================================================
1403 // Empty?
1404 // ================================================================
empty() const1405 bool ccdoc::statement::comment::empty() const
1406 {
1407   if(m_authors.size()) return false;
1408   if(m_exceptions.size()) return false;
1409   if(m_long_desc.size()) return false;
1410   if(m_params.size()) return false;
1411   if(m_pkg.size()) return false;
1412   if(m_pkgdoc.size()) return false;
1413   if(m_returns.size()) return false;
1414   if(m_sees.size()) return false;
1415   if(m_short_desc.size()) return false;
1416   if(m_since.size()) return false;
1417   if(m_source.size()) return false;
1418   if(m_version.size()) return false;
1419   return true;
1420 }
1421 // ================================================================
1422 // Clear
1423 // ================================================================
clear()1424 void ccdoc::statement::comment::clear()
1425 {
1426   m_authors.clear();
1427   m_exceptions.clear();
1428   m_long_desc.clear();
1429   m_params.clear();
1430   m_pkg.clear();
1431   m_pkgdoc.clear();
1432   m_returns.clear();
1433   m_sees.clear();
1434   m_short_desc.clear();
1435   m_since  = "";
1436   m_source  = "";
1437   m_version = "";
1438 }
1439 // ================================================================
1440 // Add since
1441 // ================================================================
add_since(const string & name)1442 void ccdoc::statement::comment::add_since(const string& name)
1443 {
1444   m_since=name;
1445 }
1446 // ================================================================
1447 // Add source
1448 // ================================================================
add_source(const string & name)1449 void ccdoc::statement::comment::add_source(const string& name)
1450 {
1451   m_source=name;
1452 }
1453 // ================================================================
1454 // Add version
1455 // ================================================================
add_version(const string & name)1456 void ccdoc::statement::comment::add_version(const string& name)
1457 {
1458   m_version=name;
1459 }
1460 // ================================================================
1461 // Add author
1462 // ================================================================
add_author(const string & name)1463 void ccdoc::statement::comment::add_author(const string& name)
1464 {
1465   m_authors.push_back(name);
1466 }
1467 // ================================================================
1468 // Add deprecated
1469 // ================================================================
add_deprecated(const string & desc)1470 void ccdoc::statement::comment::add_deprecated(const string& desc)
1471 {
1472   m_deprecated.push_back(desc);
1473 }
1474 // ================================================================
1475 // Add exception
1476 // ================================================================
add_new_exception(const string & name,const string & desc)1477 void ccdoc::statement::comment::add_new_exception(const string& name,
1478 						  const string& desc)
1479 {
1480   base::strs_t vec;
1481   vec.push_back(name);
1482   vec.push_back(desc);
1483   m_exceptions.push_back(vec);
1484 }
1485 // ================================================================
1486 // Add exception
1487 // ================================================================
add_new_exception(const string & name)1488 void ccdoc::statement::comment::add_new_exception(const string& name)
1489 {
1490   base::strs_t vec;
1491   vec.push_back(name);
1492   m_exceptions.push_back(vec);
1493 }
1494 // ================================================================
1495 // Add exception
1496 // ================================================================
add_exception_desc(const string & desc)1497 void ccdoc::statement::comment::add_exception_desc(const string& desc)
1498 {
1499   if( m_exceptions.size() ) {
1500     base::strs_t& vec = m_exceptions.back();
1501     vec.push_back(desc);
1502   }
1503 }
1504 // ================================================================
1505 // Add file
1506 // ================================================================
add_file(const string & name)1507 void ccdoc::statement::comment::add_file(const string& name)
1508 {
1509   m_file = name;
1510 }
1511 // ================================================================
1512 // Add lineno
1513 // ================================================================
add_lineno(const string & name)1514 void ccdoc::statement::comment::add_lineno(const string& name)
1515 {
1516   m_lineno = name;
1517 }
1518 // ================================================================
1519 // Add long desc
1520 // ================================================================
add_long_desc(const string & desc)1521 void ccdoc::statement::comment::add_long_desc(const string& desc)
1522 {
1523   m_long_desc.push_back(desc);
1524 }
1525 // ================================================================
1526 // Add params desc
1527 // ================================================================
add_new_param(const string & name)1528 void ccdoc::statement::comment::add_new_param(const string& name)
1529 {
1530   base::strs_t vec;
1531   vec.push_back(name);
1532   m_params.push_back(vec);
1533 }
1534 // ================================================================
1535 // Add params desc
1536 // ================================================================
add_new_param(const string & name,const string & desc)1537 void ccdoc::statement::comment::add_new_param(const string& name,
1538 					      const string& desc)
1539 {
1540   base::strs_t vec;
1541   vec.push_back(name);
1542   vec.push_back(desc);
1543   m_params.push_back(vec);
1544 }
1545 // ================================================================
1546 // Add params desc
1547 // ================================================================
add_param_desc(const string & desc)1548 void ccdoc::statement::comment::add_param_desc(const string& desc)
1549 {
1550   if( m_params.size() ) {
1551     base::strs_t& vec = m_params.back();
1552     vec.push_back(desc);
1553   }
1554 }
1555 // ================================================================
1556 // Add pkg
1557 // ================================================================
add_pkg(const string & desc)1558 void ccdoc::statement::comment::add_pkg(const string& desc)
1559 {
1560   m_pkg.push_back(desc);
1561 }
1562 // ================================================================
1563 // Add pkgdoc
1564 // ================================================================
add_pkgdoc(const string & desc)1565 void ccdoc::statement::comment::add_pkgdoc(const string& desc)
1566 {
1567   m_pkgdoc.push_back(desc);
1568 }
1569 // ================================================================
1570 // Add pkgdoc_tid
1571 // ================================================================
add_pkgdoc_tid(const string & desc)1572 void ccdoc::statement::comment::add_pkgdoc_tid(const string& desc)
1573 {
1574   // The package doc tag is always inserted at the
1575   // beginning of the pkgdoc vector as @tid <name>.
1576   base::strs_t vec;
1577   vec.push_back("@tid");
1578   vec.push_back(desc);
1579   base::strs_itr_t itr = m_pkgdoc.begin();
1580   for(;itr!=m_pkgdoc.end();++itr) {
1581     vec.push_back(*itr);
1582   }
1583   m_pkgdoc.clear();
1584   m_pkgdoc = vec;
1585 }
1586 // ================================================================
1587 // Add returns
1588 // ================================================================
add_returns(const string & desc)1589 void ccdoc::statement::comment::add_returns(const string& desc)
1590 {
1591   m_returns.push_back(desc);
1592 }
1593 // ================================================================
1594 // Add sees desc
1595 // ================================================================
add_new_see(const string & name)1596 void ccdoc::statement::comment::add_new_see(const string& name)
1597 {
1598   base::strs_t vec;
1599   vec.push_back(name);
1600   m_sees.push_back(vec);
1601 }
1602 // ================================================================
1603 // Add sees desc
1604 // ================================================================
add_new_see(const string & name,const string & desc)1605 void ccdoc::statement::comment::add_new_see(const string& name,
1606 					      const string& desc)
1607 {
1608   base::strs_t vec;
1609   vec.push_back(name);
1610   vec.push_back(desc);
1611   m_sees.push_back(vec);
1612 }
1613 // ================================================================
1614 // Add sees desc
1615 // ================================================================
add_see_desc(const string & desc)1616 void ccdoc::statement::comment::add_see_desc(const string& desc)
1617 {
1618   if( m_sees.size() ) {
1619     base::strs_t& vec = m_sees.back();
1620     vec.push_back(desc);
1621   }
1622 }
1623 // ================================================================
1624 // Add short desc
1625 // ================================================================
add_short_desc(const string & desc)1626 void ccdoc::statement::comment::add_short_desc(const string& desc)
1627 {
1628   m_short_desc.push_back(desc);
1629 }
1630 // ================================================================
1631 // Add todo
1632 // ================================================================
add_todo(const string & desc)1633 void ccdoc::statement::comment::add_todo(const string& desc)
1634 {
1635   m_todo.push_back(desc);
1636 }
1637 // ================================================================
1638 // Get the pkgdoc url.
1639 // ================================================================
get_pkgdoc_url() const1640 const string& ccdoc::statement::comment::get_pkgdoc_url() const
1641 {
1642   base::strs_citr_t itr = m_pkgdoc.begin();
1643   for(;itr!=m_pkgdoc.end();++itr) {
1644     if( *itr == "@url" ) {
1645       ++itr;
1646       if( itr!=m_pkgdoc.end())
1647 	return *itr;
1648       break;
1649     }
1650   }
1651   static string null;
1652   return null;
1653 }
1654 // ================================================================
1655 // Get the pkgdoc tid.
1656 // ================================================================
get_pkgdoc_tid() const1657 const string& ccdoc::statement::comment::get_pkgdoc_tid() const
1658 {
1659   base::strs_citr_t itr = m_pkgdoc.begin();
1660   for(;itr!=m_pkgdoc.end();++itr) {
1661     if( *itr == "@tid" ) {
1662       ++itr;
1663       if( itr!=m_pkgdoc.end())
1664 	return *itr;
1665       break;
1666     }
1667   }
1668   static string null;
1669   return null;
1670 }
1671