ソースを参照

BUG: Reimplemented ExpandListArguments to properly handle escaped backslashes that occur right before semicolons. This is important for lists of paths ending in backslashes on windows.

Brad King 22 年 前
コミット
ec78910bac
1 ファイル変更49 行追加59 行削除
  1. 49 59
      Source/cmSystemTools.cxx

+ 49 - 59
Source/cmSystemTools.cxx

@@ -841,82 +841,72 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
   if(arg.find(';') == std::string::npos)
     {
     newargs.push_back(arg);
+    return;
     }
-  else
+  // Break the string at non-escaped semicolons not nested in [].
+  int squareNesting = 0;
+  for(const char* c = arg.c_str(); *c; ++c)
     {
-    std::string::size_type start = 0;
-    std::string::size_type endpos = 0;
-    const std::string::size_type size = arg.size();
-    // break up ; separated sections of the string into separate strings
-    while(endpos != size)
+    switch(*c)
       {
-      endpos = arg.find(';', start); 
-      if(endpos == std::string::npos)
-        {
-        endpos = arg.size();
-        }
-      else
-        {
-        // skip right over escaped ; ( \; )
-        while((endpos != std::string::npos)
-              && (endpos > 0) 
-              && ((arg)[endpos-1] == '\\') )
-          {
-          endpos = arg.find(';', endpos+1);
-          }
-        if(endpos == std::string::npos)
-          {
-          endpos = arg.size();
-          }
-        }
-      std::string::size_type len = endpos - start;
-      if (len > 0)
+      case '\\':
         {
-        // check for a closing ] after the start position
-        if(arg.find('[', start) == std::string::npos)
+        // We only want to allow escaping of semicolons.  Other
+        // escapes should not be processed here.
+        ++c;
+        if(*c == ';')
           {
-          // if there is no [ in the string then keep it
-          newarg = arg.substr(start, len);
+          newarg += ';';
           }
         else
           {
-          int opencount = 0;
-          int closecount = 0;
-          for(std::string::size_type j = start; j < endpos; ++j)
+          newarg += '\\';
+          if(*c)
             {
-            if(arg.at(j) == '[')
-              {
-              ++opencount;
-              }
-            else if (arg.at(j) == ']')
-              {
-              ++closecount;
-              }
+            newarg += *c;
             }
-          if(opencount != closecount)
+          }
+        } break;
+      case '[':
+        {
+        ++squareNesting;
+        newarg += '[';
+        } break;
+      case ']':
+        {
+        --squareNesting;
+        newarg += ']';
+        } break;
+      case ';':
+        {
+        // Break the string here if we are not nested inside square
+        // brackets.
+        if(squareNesting == 0)
+          {
+          if(newarg.length())
             {
-            // skip this one
-            endpos = arg.find(';', endpos+1);  
-            if(endpos == std::string::npos)
-              {
-              endpos = arg.size();
-              }
-            len = endpos - start;
+            // Add an argument if the string is not empty.
+            newargs.push_back(newarg);
+            newarg = "";
             }
-          newarg = arg.substr(start, len);
           }
-        // unescape semicolons 
-        std::string::size_type pos = newarg.find("\\;");
-        while (pos != std::string::npos)
+        else
           {
-          newarg.erase(pos, 1);
-          pos = newarg.find("\\;");
+          newarg += ';';
           }
-        newargs.push_back(newarg);
-        }
-      start = endpos+1;
+        } break;
+      default:
+        {
+        // Just append this character.
+        newarg += *c;
+        } break;
       }
     }
+  if(newarg.length())
+    {
+    // Add the last argument if the string is not empty.
+    newargs.push_back(newarg);
+    }
 }
 
 bool cmSystemTools::SimpleGlob(const std::string& glob,