cpptagdb.cxx

Go to the documentation of this file.
00001 //
00002 // Copyright 2012, Lowell Boggs Jr.
00003 //
00004 // This file or directory, containing source code for a computer program,
00005 // is Copyrighted by Lowell Boggs, Jr.  987 Regency Drive, Lewisville
00006 // TX (USA), 75067.  You may use, copy, modify, and distribute this
00007 // source file without charge or obligation so long as you agree to
00008 // the following:
00009 //
00010 //  1.  You must indemnify Lowell Boggs against any and all financial
00011 //      obligations caused by its use, misuse, function, or malfunction.
00012 //      Further, you acknowledge that there is no warranty of any kind,
00013 //      whatsoever.
00014 //
00015 //  2.  You agree not to attempt to patent any portion of this original
00016 //      work -- though you may attempt to patent your own extensions to
00017 //      it if you so choose.
00018 //
00019 //  3.  You keep this copyright notice with the file and all copies
00020 //      of the file and do not change it anyway except language translation.
00021 //
00022 // You are responsible for enforcing your own compliance with these
00023 // conditions and may not use this source file if you cannot agree to the
00024 // above terms and conditions.
00025 
00026 #include <cxxtls/strtool.h>
00027 #include <BIscan/BIscan.h>
00028 #include <cxxtls/cpptagdb.h>
00029 #include <errno.h>
00030 #include <cxxtls/file.h>
00031 #include <cxxtls/foreach.h>
00032 
00033 
00034 using namespace std;
00035 
00036 namespace cxxtls
00037 {
00038 namespace CppTagDB
00039 {
00040 
00041 
00042 void 
00043 SymbolInfo::
00044 output(std::ostream &s, std::string indent) const
00045        {
00046           // s << file_ << ':' << line_ << ' ' << type_ << ' ' << fullname_;
00047 
00048           s << indent << annotatedName(true) << "\t\t" << file_ << ':' << line_;
00049           
00050           const_iterator first= children_.begin(),
00051                          last = children_.end();
00052 
00053 
00054           if(first != last)
00055           {
00056               indent += "      ";
00057           }
00058 
00059           while(first != last)
00060           {
00061              s << '\n';
00062 
00063              first->second.output(s, indent);
00064    
00065              ++first;
00066    
00067           }
00068    
00069        }
00070 
00071 
00072 SymbolInfo::Type 
00073 SymbolInfo::
00074 computeTypeId(std::string const &typeName)
00075        {
00076             using namespace std;
00077 
00078             Type scopeType = unknownType;
00079 
00080             static string function_id("function");
00081             static string class_id("class");
00082             static string struct_id("struct");
00083             static string enum_id("enum");
00084             static string enumeration_id("enumeration");
00085             static string typedef_id("typename");
00086             static string namespace_id("namespace");
00087             static string used_id("used");
00088             static string variable_id("variable");
00089             static string union_id("union");
00090             static string define_id("define");
00091 
00092             if(typeName.empty())
00093               return scopeType;
00094 
00095             char firstLetter = typeName[0];
00096 
00097             if(firstLetter == 'd' &&  define_id == typeName)
00098                scopeType = Enumeration;
00099             else
00100             if(firstLetter == 'e' &&  enum_id == typeName)
00101                scopeType = Enum;
00102             else
00103             if(firstLetter == 'e' &&  enumeration_id == typeName)
00104                scopeType = Enumeration;
00105             else
00106             if(firstLetter == 'f' &&  function_id == typeName)
00107                scopeType = Function;
00108             else
00109             if(firstLetter == 's' &&  struct_id == typeName)
00110                scopeType = Class;
00111             else
00112             if(firstLetter == 'u' &&  union_id == typeName)
00113                scopeType = Class;
00114             else
00115             if(firstLetter == 'c' &&  class_id == typeName)
00116                scopeType = Class;
00117             else
00118             if(firstLetter == 't' &&  typedef_id == typeName)
00119                scopeType = Typedef;
00120             else
00121             if(firstLetter == 'n' &&  namespace_id == typeName)
00122                scopeType = Namespace;
00123             else
00124             if(firstLetter == 'u' &&  used_id == typeName)
00125                scopeType = Used;
00126             else
00127             if(firstLetter == 'v' &&  variable_id == typeName)
00128                scopeType = Variable;
00129 
00130             return scopeType;
00131 
00132        }
00133 
00134 
00135 char SymbolInfo::typeChar() const 
00136        {
00137           switch(typeId_)
00138           {
00139              case   Function:    return 'f';
00140              case   Variable:    return 'v';
00141              case   Class:       return 'c';
00142              case   Enum:        return 'e';
00143              case   Enumeration: return '#'; 
00144              case   Typedef:     return 't';
00145              case   Namespace:   return 'n';
00146              case   FileScope:   return 'F';
00147              case   Used:        return 'u';
00148              case   Define:      return 'd';
00149     
00150              default: break;
00151     
00152           }
00153     
00154           return '?';
00155        }
00156 
00157 
00158 std::string 
00159 SymbolInfo::
00160 annotatedName(bool member) const 
00161        {
00162 
00163           using namespace std;
00164 
00165           string const *name = &fullname_;
00166 
00167           if(member)
00168              name = &member_;
00169 
00170           switch(typeId_)
00171           {
00172              case   Function:    return *name + " ()";
00173              case   Variable:    return *name + "  @";
00174              case   Class:       return *name + " {}";
00175              case   Enum:        return *name + "  %";
00176              case   Enumeration: return *name + "  #"; 
00177              case   Typedef:     return *name + " {}";
00178              case   Namespace:   return *name + " {}";
00179              case   FileScope:   return *name + "  /";
00180           
00181              default: break;
00182           
00183           }
00184 
00185           if( name->empty() )
00186              return "::";
00187           
00188           return *name;
00189 
00190        }
00191 
00192 int 
00193 Info::
00194 populate(std::string const &filename, int &failedLine)
00195     {
00196         FILE *f = fopen(filename.c_str(), "r");
00197 
00198         if(!f)
00199            return -1;
00200 
00201         int rc = populate(f, failedLine);
00202 
00203         fclose(f);
00204 
00205         return rc;
00206     }
00207 
00208 
00209 
00210 int 
00211 Info::
00212 populate(FILE *f, int &failedLine)
00213     {
00214 
00215         if(!f)
00216            return -1;
00217 
00218         using namespace std;
00219 
00220         failedLine=0;
00221 
00222         char buffer[10000];
00223 
00224         errno = 0;
00225 
00226         string filename;
00227 
00228 
00229         while(fgets(buffer, sizeof(buffer)-1, f))
00230         {
00231            ++failedLine;
00232 
00233            buffer[ strlen(buffer)-1] = 0; // remove training \n
00234 
00235 
00236            if(buffer[0] == '+')
00237            {
00238               filename = buffer+1;
00239 
00240               directories_.insert( FileName(filename).dirname() );
00241 
00242               size_t sep = filename.find_last_of("/\\");
00243 
00244               if(sep >= filename.size())
00245                  files_.insert( pair<string,string>(filename,filename));
00246               else
00247               {
00248                  pair<string,string> entry;
00249 
00250                  entry.second = filename;
00251                  entry.first  = filename.substr(sep+1, filename.size() - sep - 1);
00252 
00253                  files_.insert(entry);
00254 
00255 
00256 
00257 
00258               }
00259            }
00260            else
00261            if(buffer[0] == '-')
00262            {
00263 
00264               if( populateSymbol(filename, buffer+1) )
00265                  return -2;
00266            }
00267             
00268         }
00269 
00270         if(errno)
00271            return -1;
00272 
00273         return 0;
00274     }
00275 
00276 
00277 void 
00278 Info::
00279 findMatchingFiles(string const &fileNodeName, vector<string> &output) const
00280 {
00281     pair<FilesMap::const_iterator, FilesMap::const_iterator> range;
00282 
00283     range = files_.equal_range(fileNodeName);
00284 
00285     while(range.first != range.second)
00286     {
00287        output.push_back(range.first->second);
00288        ++range.first;
00289     }
00290 
00291 
00292 }
00293 
00294 void 
00295 Info::
00296 findRelativeFiles(string const &fileNodeName, vector<string> &output) const
00297 {
00298 
00299    CXXTLS_FOREACH(FileName cur, directories_)
00300    {
00301       cur += fileNodeName;
00302 
00303 
00304       if(cur.exists())
00305       {
00306          output.push_back(cur);
00307       }
00308    }
00309    
00310 
00311 }
00312 
00313 
00314 void 
00315 Info::
00316 findMatchingMembers(string const &memberName, vector<SymbolInfo const*> &output, bool caseSensitive) const
00317 {
00318     if(caseSensitive)
00319     {
00320         pair<MembersMap::const_iterator, MembersMap::const_iterator> range;
00321         
00322         range = members_.equal_range(memberName);
00323         
00324         while(range.first != range.second)
00325         {
00326            SymbolInfo const* cur = range.first->second;
00327 
00328            if(cur->line_ != 0)
00329            {
00330                output.push_back(cur);
00331            }
00332            ++range.first;
00333         }
00334     }
00335     else
00336     {
00337         // case insensitive comparison
00338 
00339         pair<MembersMap::const_iterator, MembersMap::const_iterator> range;
00340         
00341         range.first   = members_.begin();
00342         range.second  = members_.end();
00343         
00344         while(range.first != range.second)
00345         {
00346            if(StrTool::compareInsensitive(memberName, range.first->first) == 0)
00347              {
00348                SymbolInfo const* cur = range.first->second;
00349 
00350                if(cur->line_ != 0)
00351                {
00352                    output.push_back(cur);
00353                }
00354              }
00355 
00356            ++range.first;
00357         }
00358 
00359     }
00360 }
00361 
00362 
00363 std::ostream &
00364 operator<< (std::ostream &s, Info const &me)
00365     {
00366        SymbolInfo::const_iterator first= me.symbols_.children_.begin(),
00367                                   last = me.symbols_.children_.end();
00368 
00369        while(first != last)
00370        {
00371           s << first->second << std::endl;
00372 
00373           ++first;
00374        }
00375 
00376 
00377        return s;
00378     }
00379 
00380 int 
00381 Info::
00382 populateSymbol(std::string const &filename, std::string const &info)
00383     {
00384         using namespace std;
00385 
00386         string type;
00387         string name;
00388         string operatorTypeOrLineNumber;
00389         string lineNumber;
00390         int    line=0;
00391 
00392         BIscan::stream(info) >> type >> name >> operatorTypeOrLineNumber >> lineNumber;
00393 
00394         if(lineNumber.empty())
00395         {
00396            BIscan::stream(operatorTypeOrLineNumber) >> line;
00397         }
00398         else
00399         {
00400            char c = operatorTypeOrLineNumber[0];
00401 
00402            if( isalnum(c) || c == '_')
00403            {
00404               name += ' ';
00405            }
00406            
00407            name += operatorTypeOrLineNumber;
00408 
00409            BIscan::stream(lineNumber) >> line;
00410         }
00411 
00412 
00413         vector<string> component;
00414 
00415         size_t components = StrTool::splitOnString(name, component, "::");
00416 
00417         if(components == 0)
00418         {
00419           return -1;
00420         }
00421 
00422         // make sure parent object exists
00423 
00424         SymbolInfo *parent = &symbols_;
00425 
00426         string fullParentName;
00427 
00428         for(size_t i = 0; i < components-1; ++i)
00429         {
00430            string const &compName = component[i];
00431 
00432            fullParentName += "::";
00433            fullParentName += compName;
00434 
00435            SymbolInfo parentInfo(fullParentName, compName, "namespace", "", 0);  // parent's should exist, so
00436                                                                                  // if they don't, we shouldn't
00437                                                                                  // force a name, type, and line
00438                                                                                  // number here.
00439 
00440            SymbolInfo::iterator where;
00441            
00442            where = parent->children_.find(compName);
00443 
00444            if(where != parent->children_.end())
00445            {
00446               // parent exists, like it should
00447 
00448               parent = &where->second;
00449 
00450            }
00451            else
00452            {
00453               where = parent->children_.insert( SymbolInfo::Children::value_type(compName, parentInfo));
00454 
00455               parent = &where->second;
00456 
00457               members_.insert( MembersMap::value_type( compName, &where->second ) );
00458                                 
00459 
00460            }
00461 
00462         }
00463 
00464         // insert this new child symbol under its parent
00465 
00466         if(!type.empty() && type[0] == 'n')
00467         {
00468             //
00469             //  don't add duplicate namespaces, but all other types should be 
00470             //  inserted as they encountered.
00471             //
00472 
00473             SymbolInfo::iterator where = parent->children_.find(component.back());
00474 
00475             while(where != parent->children_.end())
00476             {
00477                if(where->first != component.back())
00478                    break;
00479 
00480                if(where->second.typeId_ == SymbolInfo::Namespace
00481                  )
00482                {
00483                   // we have a symbol by the same name and it is also a
00484                   // namespace
00485 
00486                   return 0;
00487                }
00488 
00489                ++where;
00490 
00491             }
00492 
00493 
00494         }
00495 
00496         // if we get here, either the type is not namespace or there is no existing
00497         // namespace by that name in the parent
00498 
00499         SymbolInfo::Children::iterator where;
00500         
00501         where = 
00502         parent->children_.insert( SymbolInfo::Children::value_type(component.back(), 
00503                                                                    SymbolInfo(name,
00504                                                                               component.back(),
00505                                                                               type,
00506                                                                               filename,
00507                                                                               line
00508                                                                              ) 
00509                                                                   )
00510                                 );
00511 
00512         members_.insert( MembersMap::value_type( component.back(), &where->second ) );
00513         
00514 
00515         return 0;
00516     }
00517 
00518 
00519 
00520 } // namespace CppTagDB
00521 } // namespace cxxtls
Generated on Wed Feb 29 22:50:04 2012 for CXXUtilities by  doxygen 1.6.3