etagsdb.cxx

Go to the documentation of this file.
00001 /*
00002 //  Copyright 1997, Lowell Boggs, all rights reserved.
00003 //  Refer to the file, copyright, for a list of your rights.
00004 */
00005 #include <portable_io.h>
00006 #include <string.h>
00007 #include <stdlib.h>
00008 
00012 
00013 #include <cxxtls/etagsdb.h>
00014 
00015 #ifdef _AIX
00016 #include <strings.h>
00017 #endif
00018 
00019 #if !defined(_MSC_VER)
00020 #define stricmp strcasecmp
00021 #endif
00022 
00023 extern "C"
00024 {
00025   typedef int (*compare_func_t)(char const *l, char const *r);
00026 };
00027 
00028 namespace cxxtls
00029 {
00030 
00031 
00032 EtagsDB::
00033 EtagsDB(std::string filename)
00034 {
00035   filename_ = filename;
00036 
00037   file_ = fopen(filename.c_str(), "rb");
00038 
00039 }
00040 
00041 EtagsDB::
00042 ~EtagsDB()
00043 {
00044   if(file_)
00045     fclose(file_);
00046 }
00047 
00048 
00049 bool
00050 EtagsDB::
00051 find_first(std::string const &symbol,
00052              std::string       *foundFile,
00053              int               *foundLine,
00054              std::string       *sourceText,
00055              bool               case_sensitive
00056             )
00057     /*
00058     **  etagsSearchFirst will return 1 only if the symbol is found in the
00059     **  the specified tagFile.  If a 1 is returned, the in foundFile will
00060     **  contain the name of a file_, and foundLine will contain the 1 based
00061     **  number of a line on which the symbol is defined.  In any other
00062     **  situation, a 0 will be returned.   sourceText is the text of the
00063     **  source line where etags recognized the function or macro defintion.
00064     **  It is returned to the caller so that in case the source file_ has been
00065     **  edited, and the line number has changed, the program can scan the
00066     **  source file_ for sourceText matching.  This text may have tabs in
00067     **  it and is not the complete line.
00068     */
00069 { /* search for a symbol in the specified tagFile */
00070 
00071     *foundLine = 0;
00072     *foundFile = "";
00073 
00074     if(file_ == 0)
00075       return false;
00076 
00077     fseek(file_, 0, SEEK_SET);
00078 
00079     case_sensitive_ = case_sensitive;
00080 
00081     symbol_ = symbol;
00082 
00083     return find_next(foundFile, foundLine, sourceText);
00084 
00085 } /* search for a symbol in the specified tagFile */
00086 
00087 #define issym(c) ( (c >= 'a' && c <= 'z') || \
00088                    (c >= 'A' && c <= 'Z') || \
00089                    (c >= '0' && c <= '9') || \
00090                     c == ':'              || \
00091                     c == '_'              || \
00092                     c == '~'                 \
00093                  )
00094 
00095 int
00096 EtagsDB::
00097 searchFor(std::string const &symbol,
00098           std::string       *foundFile,
00099           int               *foundLine,
00100           std::string       *sourceText
00101          )
00102     /*
00103     **  this function reads lines from the tags file_ and parses that file_
00104     **  into information suitable for determining if the specified
00105     **  symbol is defined in a file_ which was read to produce the TAGS
00106     **  information.
00107     **
00108     **  this function returns 2 if end of tags file_ is encountered
00109     **  it returns 1 if the symbol is found
00110     **  it returns 0 if the symbol is not found but not eof
00111     */
00112 { /* searchFor() */
00113 
00114     char line[5000];
00115     char leader[5000];
00116     char *ptr;
00117     char tagName[5000];
00118     char definitionalLine[5000];
00119     char *scan;
00120 
00121     int symLength;
00122     int tagLength;
00123 
00124     tagName[0] = 0;
00125     definitionalLine[0] = 0;
00126 
00127     if(file_ == 0) return 2;  /* end of file_ without finding it */
00128 
00129     if(0 == fgets(line, 5000, file_) )
00130         {
00131             most_recent_file_[0] = 0;
00132             return 2;   /* end of file_ is a 2 */
00133         }
00134 
00135     if(line[0] == 0x0c)
00136         { /* this line is a delimiter which sets apart files */
00137 
00138             most_recent_file_[0] = 0;
00139 
00140             if(0 == fgets(line, sizeof(line), file_) )
00141                 {
00142                     return 2;
00143                 }
00144 
00145             sscanf(line, "%[^,\n]", most_recent_file_);
00146 
00147             return 0;
00148 
00149         } /* this line is a delimiter which sets apart files */
00150 
00151     for(scan = line, ptr=leader;
00152         *scan != 0 && *scan < 0x7f;
00153         *ptr++ = *scan++
00154         );
00155 
00156     *ptr = 0;
00157 
00158     ++scan;
00159 
00160     if( *scan > '9' )
00161         { /* full symbol name comes next */
00162 
00163             for(ptr = tagName; *scan >= ' '; *ptr++ = *scan++);
00164 
00165             *ptr = 0;
00166 
00167             ++scan;
00168 
00169             /* now we have the line number */
00170 
00171             for(ptr = definitionalLine; *scan >= ' '; *ptr++ = *scan++);
00172 
00173             *ptr = 0;
00174 
00175         } /* full symbol name comes next */
00176     else
00177         { /* line number text comes next */
00178 
00179             for(ptr = definitionalLine; 
00180                 *scan >= ' ' && 
00181                   size_t(ptr-definitionalLine) < size_t(sizeof(definitionalLine)-1);
00182                 *ptr++ = *scan++);
00183 
00184             if( size_t(ptr - definitionalLine) >= size_t(sizeof(definitionalLine)-1) )
00185             {
00186               return 0;  /* bad data */
00187             }
00188              
00189             *ptr = 0;
00190 
00191             ++scan;
00192 
00193             for(ptr = tagName; 
00194                 *scan >= ' ' &&
00195                    size_t(ptr-tagName) < size_t(sizeof(tagName)-1);
00196                 *ptr++ = *scan++);
00197 
00198             *ptr = 0;
00199 
00200         } /* line number text comes next */
00201 
00202 
00203     /*
00204     **  at this point, definitionalLine is defined, leader is define,
00205     **  and symbol is defined
00206     **
00207     **  Note that any one of these could be an empty string -- in particular
00208     **  the symbol name could be an empty string.
00209     */
00210 
00211     if(tagName[0] == 0)
00212         { /* etags.exe didn't put in a tagName:  find it in leader */
00213 
00214             for(scan=leader + strlen(leader);
00215                 scan > leader && !issym(scan[-1]);
00216                 --scan
00217               );
00218 
00219            while(scan > leader && issym(scan[-1]))
00220             {
00221                 --scan;
00222             }
00223 
00224            for(ptr = tagName; issym(*scan); *ptr++ = *scan++);
00225 
00226 
00227            *ptr = 0;
00228 
00229         } /* etags.exe didn't put in a tagName:  find it in leader */
00230 
00231 
00232         compare_func_t compare_func;
00233         
00234         if(!case_sensitive_)
00235           compare_func = compare_func_t(stricmp);
00236         else
00237           compare_func = compare_func_t(strcmp);
00238 
00239         // check for an exact match
00240 
00241         if(symbol[0] == 0 || (*compare_func)(tagName, symbol.c_str()) == 0)
00242             {
00243                 *foundFile = most_recent_file_;
00244 
00245                 *sourceText = leader;
00246 
00247                 *foundLine = atoi(definitionalLine);
00248                 return 1;
00249             }
00250 
00251         {
00252           /*
00253           **  A simple direct comparison didn't work so try a more
00254           **  flexible algorithm
00255           */
00256         
00257           tagLength = strlen(tagName);
00258           symLength = strlen(symbol.c_str());
00259         
00260           bool e1 = tagLength > symLength;
00261 
00262           bool e2 = 0 == (*compare_func)(tagName + (tagLength - symLength),
00263                                          symbol.c_str());
00264         
00265           bool e3 = tagName[tagLength - symLength -1] == ':';
00266         
00267           if( e1 && e2 && e3 )
00268               {
00269                   *foundFile = most_recent_file_;
00270                   *sourceText= leader;
00271                   *foundLine = atoi(definitionalLine);
00272                   return 1;
00273               }
00274         }
00275 
00276     return 0;
00277 
00278 } /* searchFor() */
00279 
00280 bool
00281 EtagsDB::
00282 find_next(std::string       *foundFile,
00283           int               *foundLine,
00284           std::string       *sourceText
00285          )
00286 {
00287     int rc = 0;
00288 
00289     while(rc == 0)
00290         {
00291             rc = searchFor(symbol_, foundFile, foundLine, sourceText);
00292 
00293         }
00294 
00295     if(rc == 1)
00296         {
00297             return true;
00298         }
00299 
00300     return false;
00301 }
00302 
00303 EtagsDB::
00304 EtagsDB()
00305 {
00306   file_ = 0;
00307 }
00308 
00309 bool
00310 EtagsDB::
00311 set_tags_file(std::string tags_file_name)
00312 {
00313   if(file_)
00314   {
00315     fclose(file_);
00316   }
00317 
00318   filename_ = tags_file_name;
00319 
00320   file_ = fopen(tags_file_name.c_str(), "rb");
00321 
00322   return file_ == 0;
00323 }
00324 
00325 int
00326 EtagsDB::
00327 matching_files(std::string relpath, std::list<std::string> *matches) const
00328 {
00329   if(relpath.size() && 
00330      (relpath[0] == '/' || 
00331        ( (relpath.size() > 2) && (relpath[1] == ':' ) )
00332      )
00333     )
00334   {
00335     matches->push_back(relpath);
00336     return 1;
00337   }
00338 
00339   if(file_ == 0)
00340     return 0;
00341 
00342   fseek(file_, 0, SEEK_SET);
00343 
00344   char line[5000];
00345 
00346   int count=0;
00347 
00348 
00349   for(;;)
00350   {
00351 
00352     if(0 == fgets(line, 5000, file_) )
00353     {
00354       // end of file
00355 
00356       return count;
00357     }
00358 
00359     if(line[0] == 0x0c)
00360     { /* this line is a delimiter which sets apart files */
00361 
00362       if(0 == fgets(line, sizeof(line), file_) )
00363       {
00364         // eof, missing filename
00365 
00366         return count;
00367       }
00368 
00369       char filename[5000];
00370       
00371       sscanf(line, "%[^,\n]", filename);
00372 
00373       std::string whole(filename);
00374 
00375       size_t rel_len = relpath.size();
00376       size_t whole_len = whole.size();
00377 
00378       if(rel_len == 0)
00379       {
00380         ++count;
00381         matches->push_back(whole);
00382       }
00383       else
00384       if(whole_len >= rel_len)
00385       {
00386         size_t offset = whole_len - rel_len;
00387 
00388         std::string tail = whole.substr(offset, whole_len);
00389 
00390         if(tail == relpath)
00391         {
00392           if(offset == 0 || whole[offset-1] == '/' || whole[offset-1] == '\\')
00393           {
00394             ++count;
00395             matches->push_back(whole);
00396           }
00397           
00398         }
00399 
00400       }
00401 
00402 
00403     } /* this line is a delimiter which sets apart files */
00404   }
00405 
00406   // you can't get here from there
00407 }
00408 
00409 } // namespace cxxtls
Generated on Wed Feb 29 22:50:05 2012 for CXXUtilities by  doxygen 1.6.3