strtool.cxx

Go to the documentation of this file.
00001 //
00002 // Copyright 2002, 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 <stdlib.h>
00028 #include <stdio.h>
00029 
00034 
00035 using namespace std;
00036 
00037 namespace cxxtls
00038 {
00039 
00040 
00041 string
00042 StrTool::
00043 expand_tabs(char const *s, bool *non_printable_chars, char replacement )
00044 {
00045   string rv;
00046 
00047   int count=0;
00048 
00049   char c;
00050 
00051   while(0 != (c = *s++) )
00052   {
00053     if(c == '\t')
00054     {
00055 
00056       // int next_tab_stop = ( (count >> 3) + 1 ) << 3;
00057 
00058       // from expand.c:   next_tab_column = column + tab_size - column % tab_size;
00059 
00060       int next_tab_stop = count + 8 - count % 8;
00061 
00062       while(count != next_tab_stop)
00063       {
00064         rv += ' ';
00065         ++count;
00066       }
00067 
00068     }
00069     else
00070     {
00071       if(c < ' ' || c >= 0x7f )
00072       {
00073         if(non_printable_chars)
00074           *non_printable_chars = true;
00075         
00076         if(replacement)
00077           c = replacement;
00078       }
00079 
00080       rv += c;
00081       ++count;
00082     }
00083   }
00084 
00085   return rv;
00086 
00087 }
00088 
00089 
00090 string
00091 StrTool::
00092 pack_tabs(char const *s, bool stop_after_first_non_blank)
00093   // convert spaces to tabs if possible
00094 {
00095 
00096   string rv;
00097 
00098   int output=0;  // output is always less than or equal to input
00099   int input=0;
00100 
00101   char space=0x20;
00102 
00103   char c;
00104 
00105   for(;;)  // process all characters in the string -- even the null
00106   {
00107     c = *s++;
00108 
00109     if(c == space)
00110     {
00111        ++input;  // allow output and input to differ by the number of
00112                  // blanks
00113     }
00114     else
00115     if(c == '\t')
00116     {
00117        input >>= 3;  // treat tabs as a bunch of input spaces
00118        ++input;
00119        input <<= 3;
00120     }
00121     else
00122     {
00123       // not a space: force sync between output and input character positions
00124 
00125       if( (input - output == 1) && 
00126           (output%8 == 7) 
00127         )
00128       {
00129         rv += space;
00130         ++output;
00131       }
00132       else
00133       {
00134 
00135         int tout = output >> 3;
00136         int tin  = input  >> 3;
00137         
00138         if(tout != tin)
00139         {
00140            while(tout != tin)
00141            {
00142              rv += '\t';   // the most recent output character is in a different
00143                            // tab stop region ( 8 char wide ) than the input
00144                            // character
00145              ++tout;
00146            }
00147           
00148            output = tout << 3;
00149           
00150         }
00151       }
00152 
00153 
00154       while(output != input)
00155       {
00156         rv += space;            // output and input are in same tab stop
00157         ++output;             // but some number of blanks apart
00158       }
00159 
00160 
00161       if(c == 0)
00162       {
00163         break;
00164       }
00165 
00166       rv += c;
00167 
00168       ++input;
00169 
00170       output = input;
00171 
00172       // now output = input and all blanks and tabs are accounted for.
00173 
00174       if(stop_after_first_non_blank)
00175       {
00176         rv += s;
00177         return rv;
00178       }
00179 
00180     }
00181 
00182   }
00183 
00184   return rv;
00185 }
00186 
00187 void
00188 StrTool::
00189 remove_leading(std::string &s, char space)
00190 {
00191   // remove all leading copies of space from the string
00192 
00193   std::string::iterator scan = s.begin(),
00194                         end  = s.end();
00195 
00196   while(scan != end && *scan == space)
00197     ++scan;
00198 
00199   if(scan != s.begin())
00200     s.erase(s.begin(), scan);
00201 
00202 }
00203 
00204 
00205 
00206 bool 
00207 StrTool::
00208 snatch_file_info(std::string const &s, std::string &outputFile, int &outputLine)
00209    {
00210           // return true on success
00211 
00212           size_t rLength = s.size();
00213 
00214           if(rLength == 0)
00215             return false;
00216 
00217           size_t firstNonBlank = s.find_first_not_of(" \t");
00218 
00219           if(firstNonBlank > rLength)
00220             return false;
00221         
00222           std::string tmp(s.begin() + firstNonBlank, s.end());  
00223         
00224           tmp += ' ';  // make sure there's a blank at the end
00225         
00226           char name[3000];
00227           char numbuff[3000];
00228           int  number;
00229         
00230           name[0] = 0;
00231         
00232           //
00233           //  use scanf to parse some standard program output
00234           //  formats:
00235           //
00236           //      filename:lineNo:  -- grep format
00237           //      file lineNo:      -- borland c output
00238           //      "file", line 2:   -- other compiler outputs
00239           //      file(line)        -- microsoft
00240           //      #line 12 "file"   -- C preprocessor
00241           //      <file>            -- #include file names
00242           //      #12 "file"
00243           //      Error 112: "reports_pkg.c", line 48
00244           //      Error (112): "reports_pkg.c", line 48
00245           //      error: "reports_pkg.c", line 48
00246           //      warning: "reports_pkg.c", line 48
00247           //      file:             -- grep without the -n
00248           //      (file:line)       -- valgrind logs with debug on
00249           //      (in file)         -- valgrind logs without debug on
00250         
00251           if( 2 == sscanf(tmp.c_str(), "(%[^:]:%d)", name, &number) )
00252           {
00253 
00254             // valgrind log
00255           }
00256           else
00257           if( 1 == sscanf(tmp.c_str(), "(in %[^):]", name) )
00258           {
00259             number=1;
00260           }
00261           else
00262           if( 2 ==
00263               sscanf(tmp.c_str(), "error: \"%[+-.$#@!`~=a-zA-Z0-9_/\\]\", line %[0-9]",
00264                      name,
00265                      numbuff
00266                     )
00267             )
00268             {  //      error: "reports_pkg.c", line 48
00269         
00270                number=atol(numbuff);
00271             }
00272           else
00273           if( 2 ==
00274               sscanf(tmp.c_str(), "warning: \"%[+-.$#@!`~=a-zA-Z0-9_/\\]\", line %[0-9]",
00275                      name,
00276                      numbuff
00277                     )
00278             )
00279             {  // warning: "reports_pkg.c", line 48
00280         
00281                number=atol(numbuff);
00282             }
00283           else
00284           if( 2 ==
00285               sscanf(tmp.c_str(), "Error %*[()0-9]: \"%[+-.$#@!`~=a-zA-Z0-9_/\\]\", line %[0-9]",
00286                      name,
00287                      numbuff
00288                     )
00289             )
00290             {  // Error (112): "reports_pkg.c", line 48
00291                number=atol(numbuff);
00292             }
00293           else
00294           if( 2 ==
00295               sscanf(tmp.c_str(), "# %[0-9] \"%[^\"]\"",
00296                      numbuff,
00297                      name
00298                     )
00299             )
00300             { // #123 "file.c"
00301         
00302               // compiler -E output format
00303         
00304               number=atol(numbuff);
00305             }
00306           else
00307           if( 2 ==
00308               sscanf(tmp.c_str(), "#line %[0-9] \"%[^\"]\"",
00309                      numbuff,
00310                      name
00311                     )
00312             )
00313             { // #line 132 "file.c"
00314         
00315               // manually overrride of the compilers line number info
00316         
00317               number=atol(numbuff);
00318             }
00319           else
00320           if( 2 ==
00321               sscanf(tmp.c_str(), "\"%[+-.$#@!`~=a-zA-Z0-9_/\\]\", line %[0-9]",
00322                      name,
00323                      numbuff
00324                     )
00325             )
00326               { // "filename", line 47:
00327         
00328                  // aix compiler
00329         
00330                   number = atol(numbuff);
00331               }
00332           else
00333           if( 2 ==
00334               sscanf(tmp.c_str(), "%[^ :]:%d:", name, &number)
00335             )
00336               { // file:line:
00337         
00338                   // gnu grep output
00339         
00340               }
00341           else
00342           if( 2 == sscanf(tmp.c_str(), "%s %d", name, &number) )
00343               { // filename linenumber
00344         
00345                   // borland c++ compiler
00346         
00347               }
00348           else
00349           if( 2 == sscanf(tmp.c_str(), "%[^(](%d)", name, &number) )
00350               { // filename(linenumber)
00351         
00352                   // microsoft c++ compiler
00353         
00354               }
00355           else
00356           if( 1 == sscanf(tmp.c_str(), "\"%[^\"]\"", name) )
00357               { // "filename"
00358         
00359                   number=1;   // plain old quoted string
00360         
00361               }
00362           else
00363           if( 1 == sscanf(tmp.c_str(), "<%[^>]>", name) )
00364           {
00365             number=1;
00366           }
00367           else
00368           if( 1 == sscanf(tmp.c_str(), "%[^: ]:", name) )  // WARNING:  must be last real test!
00369               { // filename:
00370         
00371                   number=1;   // plain old filename ending in :
00372         
00373                   // fix erroneous return of true in some cases...
00374         
00375                   int l = strlen(name);
00376         
00377                   while(l)
00378                   {
00379                     --l;
00380                     if(name[l] != ' ')
00381                       break;
00382                   }
00383         
00384                   name[l+1] = 0;
00385         
00386 #ifdef _MSC_VER
00387         
00388                   if(l == 0 && tmp[1] == ':' )
00389                 {
00390                   if( (name[0] >= 'a' && name[0] <= 'z')
00391                       || (name[0] >= 'A' && name[0] <= 'Z')
00392                     )
00393                   {
00394                     // yep, we have a dos style fully qualified pathname:
00395                     //
00396                     //   c:\dir\file:
00397                     //
00398                     // And possibly this:
00399                     //
00400                     //  c:\dir\file:line
00401         
00402                     std::string drive = tmp.substr(0,2);
00403                     std::string path  = tmp.substr(2,tmp.size()-2);
00404         
00405                     if(2 == sscanf(path.c_str(), "%[^ :]:%d:", name, &number ) )
00406                     {
00407                       drive += name;
00408         
00409                       strcpy(name, drive.c_str());
00410         
00411                     }
00412                     else
00413                     {
00414                       drive = tmp.substr(0,tmp.size()-1);
00415         
00416                       strcpy(name, drive.c_str());
00417                     }
00418         
00419         
00420                   }
00421                 }
00422         
00423 #endif
00424         
00425         
00426               }
00427           else  // WARNING:  do not put any new tests here, put them before
00428                 // the above test due to bugs in sscanf on some machines
00429               {
00430                 // plain old non-quoted string
00431         
00432                   number = 1;
00433                   sscanf(tmp.c_str(), "%s", name);
00434                 
00435               }
00436 
00437        outputFile = name;
00438        outputLine = number;
00439        
00440        return !outputFile.empty();
00441 
00442 
00443    }
00444 
00445 
00446 } // namespace cxxtls
Generated on Wed Feb 29 22:50:05 2012 for CXXUtilities by  doxygen 1.6.3