OSDN Git Service

Plugins: Fix a crash on Window XP
[winmerge-jp/winmerge-jp.git] / Src / MergeCmdLineInfo.cpp
index 2aada6b..46d0e83 100644 (file)
@@ -1,24 +1,8 @@
 /////////////////////////////////////////////////////////////////////////////
-//
 //    WinMerge: An interactive diff/merge utility
 //    Copyright (C) 1997 Dean P. Grimm
-//
-//    This program is free software; you can redistribute it and/or modify
-//    it under the terms of the GNU General Public License as published by
-//    the Free Software Foundation; either version 2 of the License, or
-//    (at your option) any later version.
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU General Public License for more details.
-//
-//    You should have received a copy of the GNU General Public License
-//    along with this program; if not, write to the Free Software
-//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-//
+//    SPDX-License-Identifier: GPL-2.0-or-later
 /////////////////////////////////////////////////////////////////////////////
-
 /** 
  * @file  MergeCmdLineInfo.cpp
  *
  *
  */
 
-// ID line follows -- this is updated by SVN
-// $Id: MergeCmdLineInfo.cpp 6940 2009-08-01 17:29:01Z kimmov $
 
+#include "pch.h"
 #include "MergeCmdLineInfo.h"
-#include <cstring>
-#include <algorithm>
 #include "Constants.h"
 #include "Paths.h"
 #include "OptionsDef.h"
+#include "unicoder.h"
 
 // MergeCmdLineInfo
 
  * @param [out] flag Tells whether param is the name of a flag.
  * @return Points to the remaining portion of the command line.
  */
-const TCHAR *MergeCmdLineInfo::EatParam(const TCHAR *p, String &param, bool *flag)
+const TCHAR *MergeCmdLineInfo::EatParam(const TCHAR *p, String &param, bool *flag /*= nullptr*/)
 {
-       if (p && *(p += _tcsspn(p, _T(" \t\r\n"))) == _T('\0'))
-               p = 0;
+       if (p != nullptr && *(p += _tcsspn(p, _T(" \t\r\n"))) == _T('\0'))
+               p = nullptr;
        const TCHAR *q = p;
-       if (q)
+       if (q != nullptr)
        {
                TCHAR c = *q;
                bool quoted = false;
@@ -78,13 +60,13 @@ const TCHAR *MergeCmdLineInfo::EatParam(const TCHAR *p, String &param, bool *fla
                else
                {
                        *flag = false;
-                       flag = 0;
+                       flag = nullptr;
                }
        }
        param.assign(p ? p : _T(""), q - p);
-       if (q > p && flag)
+       if (q > p && flag != nullptr)
        {
-               param = string_makelower(param);
+               param = strutils::makelower(param);
        }
        // Strip any leading or trailing whitespace or quotes
        param.erase(0, param.find_first_not_of(_T(" \t\r\n\"")));
@@ -99,7 +81,7 @@ const TCHAR *MergeCmdLineInfo::EatParam(const TCHAR *p, String &param, bool *fla
  * @param [in] value Default value in case none is specified.
  * @return Points to the remaining portion of the command line.
  */
-const TCHAR *MergeCmdLineInfo::SetOption(const TCHAR *q, const TCHAR *key, const TCHAR *value)
+const TCHAR *MergeCmdLineInfo::SetOption(const TCHAR *q, const String& key, const TCHAR *value)
 {
        String s;
        if (*q == _T(':'))
@@ -107,111 +89,48 @@ const TCHAR *MergeCmdLineInfo::SetOption(const TCHAR *q, const TCHAR *key, const
                q = EatParam(q, s);
                value = s.c_str() + 1;
        }
-//     GetOptionsMgr()->SaveOption(key, value);
+       m_Options.insert_or_assign(key, value);
+       return q;
+}
+
+const TCHAR *MergeCmdLineInfo::SetConfig(const TCHAR *q)
+{
+       String s;
+       if (*q == ':')
+               ++q;
+       q = EatParam(q, s);
+       size_t pos = s.find_first_of('=');
+       if (pos != String::npos)
+       {
+               String key = s.substr(0, pos);
+               String value = s.c_str() + pos + 1;
+               m_Options.insert_or_assign(key, value);
+       }
        return q;
 }
 
 /**
- * @brief ClearCaseCmdLineParser's constructor.
+ * @brief MergeCmdLineParser's constructor.
  * @param [in] q Points to the beginning of the command line.
  */
 MergeCmdLineInfo::MergeCmdLineInfo(const TCHAR *q):
        m_nCmdShow(SHOWNORMAL),
-       m_bClearCaseTool(false),
        m_bEscShutdown(false),
        m_bExitIfNoDiff(Disabled),
        m_bRecurse(false),
        m_bNonInteractive(false),
-       m_bSingleInstance(false),
+       m_nSingleInstance(),
        m_bShowUsage(false),
+       m_bNoPrefs(false),
        m_nCodepage(0),
+       m_bSelfCompare(false),
        m_dwLeftFlags(FFILEOPEN_NONE),
        m_dwMiddleFlags(FFILEOPEN_NONE),
        m_dwRightFlags(FFILEOPEN_NONE)
 {
-       // Rational ClearCase has a weird way of executing external
-       // tools which replace the build-in ones. It also doesn't allow
-       // you to define which parameters to send to the executable.
-       // So, in order to run as an external tool, WinMerge should do:
-       // if argv[0] is "xcompare" then it "knows" that it was
-       // executed from ClearCase. In this case, it should read and
-       // parse ClearCase's command line parameters and not the
-       // "regular" parameters. More information can be found in
-       // C:\Program Files\Rational\ClearCase\lib\mgrs\mgr_info.h file.
        String exeName;
        q = EatParam(q, exeName);
-       if (exeName == _T("compare") || exeName == _T("xcompare"))
-       {
-               ParseClearCaseCmdLine(q, _T("<No Base>"));
-       }
-       else if (exeName == _T("merge") || exeName == _T("xmerge"))
-       {
-               ParseClearCaseCmdLine(q, _T(""));
-       }
-       else
-       {
-               ParseWinMergeCmdLine(q);
-       }
-}
-
-/**
- * @brief Parse a command line passed in from ClearCase.
- * @param [in] p Points into the command line.
- */
-void MergeCmdLineInfo::ParseClearCaseCmdLine(const TCHAR *q, const TCHAR *basedesc)
-{
-       String sBaseFile;  /**< Base file path. */
-       String sBaseDesc = basedesc;  /**< Base file description. */
-       String sOutFile;   /**< Out file path. */
-       m_bClearCaseTool = true;
-       String param;
-       bool flag;
-       while ((q = EatParam(q, param, &flag)) != 0)
-       {
-               if (!flag)
-               {
-                       // Not a flag
-                       param = paths_GetLongPath(param);
-                       m_Files.SetPath(m_Files.GetSize(), param);
-                       if (param == m_sLeftDesc)
-                               m_dwLeftFlags &= ~FFILEOPEN_READONLY;
-                       if (param == m_sRightDesc)
-                               m_dwRightFlags &= ~FFILEOPEN_READONLY;
-               }
-               else if (param == _T("base"))
-               {
-                       // -base is followed by common ancestor file description.
-                       q = EatParam(q, sBaseFile);
-               }
-               else if (param == _T("out"))
-               {
-                       // -out is followed by merge's output file name.
-                       q = EatParam(q, sOutFile);
-               }
-               else if (param == _T("fname"))
-               {
-                       // -fname is followed by file description.
-                       if (sBaseDesc.empty())
-                               q = EatParam(q, sBaseDesc);
-                       else if (m_sLeftDesc.empty())
-                       {
-                               q = EatParam(q, m_sLeftDesc);
-                               m_dwLeftFlags |= FFILEOPEN_READONLY;
-                       }
-                       else if (m_sRightDesc.empty())
-                       {
-                               q = EatParam(q, m_sRightDesc);
-                               m_dwRightFlags |= FFILEOPEN_READONLY;
-                       }
-                       else
-                               q = EatParam(q, param); // ignore excess arguments
-               }
-       }
-       if (!sOutFile.empty())
-       {
-               String path = paths_GetLongPath(sOutFile);
-               m_sOutputpath = path;
-       }
+       ParseWinMergeCmdLine(q);
 }
 
 /**
@@ -230,17 +149,19 @@ void MergeCmdLineInfo::AddPath(const String &path)
                m_dwLeftFlags |= FFILEOPEN_CMDLINE;
        else if (ord == 1)
                m_dwRightFlags |= FFILEOPEN_CMDLINE;
+       else if (ord == 2)
+               m_dwMiddleFlags |= FFILEOPEN_CMDLINE;
 
-       if (!paths_IsURLorCLSID(path))
+       if (!paths::IsURLorCLSID(path))
        {
                // Convert paths given in Linux-style ('/' as separator) given from
                // Cygwin to Windows style ('\' as separator)
-               string_replace(param, _T("/"), _T("\\"));
+               strutils::replace(param, _T("/"), _T("\\"));
 
                // If shortcut, expand it first
-               if (paths_IsShortcut(param))
-                       param = ExpandShortcut(param);
-               param = paths_GetLongPath(param);
+               if (paths::IsShortcut(param))
+                       param = paths::ExpandShortcut(param);
+               param = paths::GetLongPath(param);
                m_Files.SetPath(m_Files.GetSize(), param);
        }
        else
@@ -275,6 +196,11 @@ void MergeCmdLineInfo::ParseWinMergeCmdLine(const TCHAR *q)
                        // -o "outputfilename"
                        q = EatParam(q, m_sOutputpath);
                }
+               else if (param == _T("or"))
+               {
+                       // -or "reportfilename"
+                       q = EatParam(q, m_sReportFile);
+               }
                else if (param == _T("dl"))
                {
                        // -dl "desc" - description for left file
@@ -300,15 +226,56 @@ void MergeCmdLineInfo::ParseWinMergeCmdLine(const TCHAR *q)
                        // -f "mask" - file filter mask ("*.h *.cpp")
                        q = EatParam(q, m_sFileFilter);
                }
+               else if (param == _T("m"))
+               {
+                       // -m "method" - compare method
+                       q = EatParam(q, param);
+                       param = strutils::makelower(param);
+                       strutils::replace(param, _T("and"), _T(""));
+                       strutils::replace(param, _T("contents"), _T(""));
+                       strutils::replace(param, _T("modified"), _T(""));
+                       strutils::replace(param, _T(" "), _T(""));
+                       if (param == _T("full"))
+                               m_nCompMethod = CompareMethodType::CONTENT;
+                       else if (param == _T("quick"))
+                               m_nCompMethod = CompareMethodType::QUICK_CONTENT;
+                       else if (param == _T("binary"))
+                               m_nCompMethod = CompareMethodType::BINARY_CONTENT;
+                       else if (param == _T("date"))
+                               m_nCompMethod = CompareMethodType::DATE;
+                       else if (param == _T("sizedate") || param == _T("datesize"))
+                               m_nCompMethod = CompareMethodType::DATE_SIZE;
+                       else if (param == _T("size"))
+                               m_nCompMethod = CompareMethodType::SIZE;
+                       else
+                               m_sErrorMessages.push_back(_T("Unknown compare method '") + param + _T("' specified"));
+               }
                else if (param == _T("r"))
                {
                        // -r to compare recursively
                        m_bRecurse = true;
                }
+               else if (param == _T("s-"))
+               {
+                       // -s- to not allow only one instance
+                       m_nSingleInstance = 0;
+               }
+               else if (param == _T("sw"))
+               {
+                       // -sw to allow only one instance and wait for the instance to terminate
+                       m_nSingleInstance = 2;
+               }
                else if (param == _T("s"))
                {
                        // -s to allow only one instance
-                       m_bSingleInstance = true;
+                       if (*q == ':')
+                       {
+                               q = EatParam(q + 1, param);
+                               m_nSingleInstance = _ttoi(param.c_str());
+                       }
+                               
+                       else
+                               m_nSingleInstance = 1;
                }
                else if (param == _T("noninteractive"))
                {
@@ -318,10 +285,12 @@ void MergeCmdLineInfo::ParseWinMergeCmdLine(const TCHAR *q)
                else if (param == _T("noprefs"))
                {
                        // -noprefs means do not load or remember options (preferences)
-                       // Turn off serializing to registry.
-//                     GetOptionsMgr()->SetSerializing(false);
-                       // Load all default settings.
-//                     theApp.ResetOptions();
+                       m_bNoPrefs = true;
+               }
+               else if (param == _T("self-compare"))
+               {
+                       // -self-compare means compare a specified file with a copy of the file
+                       m_bSelfCompare = true;
                }
                else if (param == _T("minimize"))
                {
@@ -338,6 +307,11 @@ void MergeCmdLineInfo::ParseWinMergeCmdLine(const TCHAR *q)
                        // Get prediffer if specified (otherwise prediffer will be blank, which is default)
                        q = EatParam(q, m_sPreDiffer);
                }
+               else if (param == _T("unpacker"))
+               {
+                       // Get unpacker if specified (otherwise unpacker will be blank, which is default)
+                       q = EatParam(q, m_sUnpacker);
+               }
                else if (param == _T("wl"))
                {
                        // -wl to open left path as read-only
@@ -420,7 +394,7 @@ void MergeCmdLineInfo::ParseWinMergeCmdLine(const TCHAR *q)
                {
                        String codepage;
                        q = EatParam(q, codepage);
-                       try { m_nCodepage = string_stoi(codepage); } catch (...) { /* FIXME: */ }
+                       m_nCodepage = atoi(ucr::toUTF8(codepage).c_str());
                }
                else if (param == _T("ignorews"))
                {
@@ -438,16 +412,32 @@ void MergeCmdLineInfo::ParseWinMergeCmdLine(const TCHAR *q)
                {
                        q = SetOption(q, OPT_CMP_IGNORE_EOL);
                }
+               else if (param == _T("ignorecodepage"))
+               {
+                       q = SetOption(q, OPT_CMP_IGNORE_CODEPAGE);
+               }
+               else if (param == _T("ignorecomments"))
+               {
+                       q = SetOption(q, OPT_CMP_FILTER_COMMENTLINES);
+               }
+               else if (param == _T("cfg") || param == _T("config"))
+               {
+                       q = SetConfig(q);
+               }
+               else
+               {
+                       m_sErrorMessages.push_back(_T("Unknown option '/") + param + _T("'"));
+               }
        }
        // If "compare file dir" make it "compare file dir\file".
        if (m_Files.GetSize() >= 2)
        {
-               PATH_EXISTENCE p1 = paths_DoesPathExist(m_Files[0]);
-               PATH_EXISTENCE p2 = paths_DoesPathExist(m_Files[1]);
+               paths::PATH_EXISTENCE p1 = paths::DoesPathExist(m_Files[0]);
+               paths::PATH_EXISTENCE p2 = paths::DoesPathExist(m_Files[1]);
 
-               if ((p1 == IS_EXISTING_FILE) && (p2 == IS_EXISTING_DIR))
+               if ((p1 == paths::IS_EXISTING_FILE) && (p2 == paths::IS_EXISTING_DIR))
                {
-                       m_Files[1] = paths_ConcatPath(m_Files[1], paths_FindFileName(m_Files[0]));
+                       m_Files[1] = paths::ConcatPath(m_Files[1], paths::FindFileName(m_Files[0]));
                }
        }
        if (m_bShowUsage)