فهرست منبع

ENH: Added support for # characters inside quoted arguments and for escaping # in a non-quoted argument. Improved parsing speed by not compiling regular expressions on blank lines.

Brad King 22 سال پیش
والد
کامیت
40c156dead
2فایلهای تغییر یافته به همراه69 افزوده شده و 16 حذف شده
  1. 68 16
      Source/cmListFileCache.cxx
  2. 1 0
      Source/cmSystemTools.cxx

+ 68 - 16
Source/cmListFileCache.cxx

@@ -146,15 +146,59 @@ void cmListFileCache::FlushCache(const char* path)
     }
 }
 
-inline void RemoveComments(std::string& line)
+//----------------------------------------------------------------------------
+inline bool cmListFileCachePreprocessLine(std::string& line)
 {
-  std::string::size_type pos = line.find("#");
-  if (pos != std::string::npos )
+  // Keep track of whether characters are inside a quoted argument.
+  bool quoted = false;
+  
+  // Keep track of whether the line is blank.
+  bool blank = true;
+  
+  // Loop over every character in the line.
+  std::string::iterator c;
+  for(c = line.begin(); c != line.end(); ++c)
     {
-    line.erase(pos);
+    if((*c == '\\') && (c < line.end()-1))
+      {
+      // A backslash escapes any character, so skip the next
+      // character.
+      ++c;
+      
+      // We have encountered a non-whitespace character.
+      blank = false;
+      }
+    else if(*c == '"')
+      {
+      // A double-quote either starts or ends a quoted argument.
+      quoted = !quoted;
+      
+      // We have encountered a non-whitespace character.
+      blank = false;
+      }
+    else if(*c == '#' && !quoted)
+      {
+      // A pound character outside a double-quoted argument marks the
+      // rest of the line as a comment.  Skip it.
+      break;
+      }
+    else if((*c != ' ') && (*c != '\t') && (*c != '\r'))
+      {
+      // We have encountered a non-whitespace character.
+      blank = false;
+      }
     }
+  
+  // Erase from the comment character to the end of the line.  If no
+  // comment was present, both iterators are end() iterators and this
+  // does nothing.
+  line.erase(c, line.end());
+  
+  // Return true if there is anything useful on this line.
+  return !blank;
 }
 
+//----------------------------------------------------------------------------
 bool cmListFileCache::ParseFunction(std::ifstream& fin,
                                     cmListFileFunction& function,
                                     const char* filename,
@@ -173,20 +217,23 @@ bool cmListFileCache::ParseFunction(std::ifstream& fin,
     }
   if(cmSystemTools::GetLineFromStream(fin, inbuffer) )
     {
+    // Count this line in line numbering.
     ++line;
-    RemoveComments(inbuffer);
-    cmsys::RegularExpression blankLine("^[ \t\r]*$");
+    
+    // Preprocess the line to remove comments.  Only use it if there
+    // is non-whitespace.
+    if(!cmListFileCachePreprocessLine(inbuffer))
+      {
+      return false;
+      }
+    
+    // Regular expressions to match portions of a command invocation.
     cmsys::RegularExpression oneLiner("^[ \t]*([A-Za-z_0-9]*)[ \t]*\\((.*)\\)[ \t\r]*$");
     cmsys::RegularExpression multiLine("^[ \t]*([A-Za-z_0-9]*)[ \t]*\\((.*)$");
     cmsys::RegularExpression lastLine("^(.*)\\)[ \t\r]*$");
 
-    // check for blank line or comment
-    if(blankLine.find(inbuffer.c_str()) )
-      {
-      return false;
-      }
     // look for a oneline fun(arg arg2) 
-    else if(oneLiner.find(inbuffer.c_str()))
+    if(oneLiner.find(inbuffer.c_str()))
       {
       // the arguments are the second match
       std::string args = oneLiner.match(2);
@@ -210,11 +257,16 @@ bool cmListFileCache::ParseFunction(std::ifstream& fin,
         // read lines until the end paren is found
         if(cmSystemTools::GetLineFromStream(fin, inbuffer) )
           {
+          // Count this line in line numbering.
           ++line;
-          RemoveComments(inbuffer);
-          // Check for comment lines and ignore them.
-          if(blankLine.find(inbuffer.c_str()))
-            { continue; }
+          
+          // Preprocess the line to remove comments.  Only use it if there
+          // is non-whitespace.
+          if(!cmListFileCachePreprocessLine(inbuffer))
+            {
+            continue;
+            }
+    
           // Is this the last line?
           if(lastLine.find(inbuffer.c_str()))
             {

+ 1 - 0
Source/cmSystemTools.cxx

@@ -164,6 +164,7 @@ std::string cmSystemTools::RemoveEscapes(const char* s)
         case 't': result.insert(result.end(), '\t'); break;
         case 'n': result.insert(result.end(), '\n'); break;
         case 'r': result.insert(result.end(), '\r'); break;
+        case '#': result.insert(result.end(), '#'); break;
         case '0': result.insert(result.end(), '\0'); break;
         case '\0':
           {