1 /////////////////////////////////////////////////////////////////////////////
3 // WinMerge: An interactive diff/merge utility
4 // Copyright (C) 1997 Dean P. Grimm
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /////////////////////////////////////////////////////////////////////////////
23 * @file MergeCmdLineInfo.cpp
25 * @brief MergeCmdLineInfo class implementation.
29 // ID line follows -- this is updated by SVN
30 // $Id: MergeCmdLineInfo.cpp 6940 2009-08-01 17:29:01Z kimmov $
32 #include "MergeCmdLineInfo.h"
35 #include "Constants.h"
37 #include "OptionsDef.h"
42 * @brief Eat and digest a command line parameter.
43 * @param [in] p Points into the command line.
44 * @param [out] param Receives the digested command line parameter.
45 * @param [out] flag Tells whether param is the name of a flag.
46 * @return Points to the remaining portion of the command line.
48 const TCHAR *MergeCmdLineInfo::EatParam(const TCHAR *p, String ¶m, bool *flag)
50 if (p && *(p += _tcsspn(p, _T(" \t\r\n"))) == _T('\0'))
62 } while (c != _T('\0') && (quoted ||
63 c != _T(' ') && c != _T('\t') && c != _T('\r') && c != _T('\n')));
67 if (*p == _T('-') || *p == _T('/'))
71 for (const TCHAR *i = q; i >= p; --i)
84 param.assign(p ? p : _T(""), q - p);
87 param = string_makelower(param);
89 // Strip any leading or trailing whitespace or quotes
90 param.erase(0, param.find_first_not_of(_T(" \t\r\n\"")));
91 param.erase(param.find_last_not_of(_T(" \t\r\n\"")) + 1);
96 * @brief Set WinMerge option from command line.
97 * @param [in] p Points into the command line.
98 * @param [in] key Name of WinMerge option to set.
99 * @param [in] value Default value in case none is specified.
100 * @return Points to the remaining portion of the command line.
102 const TCHAR *MergeCmdLineInfo::SetOption(const TCHAR *q, const TCHAR *key, const TCHAR *value)
108 value = s.c_str() + 1;
110 // GetOptionsMgr()->SaveOption(key, value);
115 * @brief ClearCaseCmdLineParser's constructor.
116 * @param [in] q Points to the beginning of the command line.
118 MergeCmdLineInfo::MergeCmdLineInfo(const TCHAR *q):
119 m_nCmdShow(SHOWNORMAL),
120 m_bClearCaseTool(false),
121 m_bEscShutdown(false),
122 m_bExitIfNoDiff(Disabled),
124 m_bNonInteractive(false),
125 m_bSingleInstance(false),
128 m_dwLeftFlags(FFILEOPEN_NONE),
129 m_dwMiddleFlags(FFILEOPEN_NONE),
130 m_dwRightFlags(FFILEOPEN_NONE)
132 // Rational ClearCase has a weird way of executing external
133 // tools which replace the build-in ones. It also doesn't allow
134 // you to define which parameters to send to the executable.
135 // So, in order to run as an external tool, WinMerge should do:
136 // if argv[0] is "xcompare" then it "knows" that it was
137 // executed from ClearCase. In this case, it should read and
138 // parse ClearCase's command line parameters and not the
139 // "regular" parameters. More information can be found in
140 // C:\Program Files\Rational\ClearCase\lib\mgrs\mgr_info.h file.
142 q = EatParam(q, exeName);
143 if (exeName == _T("compare") || exeName == _T("xcompare"))
145 ParseClearCaseCmdLine(q, _T("<No Base>"));
147 else if (exeName == _T("merge") || exeName == _T("xmerge"))
149 ParseClearCaseCmdLine(q, _T(""));
153 ParseWinMergeCmdLine(q);
158 * @brief Parse a command line passed in from ClearCase.
159 * @param [in] p Points into the command line.
161 void MergeCmdLineInfo::ParseClearCaseCmdLine(const TCHAR *q, const TCHAR *basedesc)
163 String sBaseFile; /**< Base file path. */
164 String sBaseDesc = basedesc; /**< Base file description. */
165 String sOutFile; /**< Out file path. */
166 m_bClearCaseTool = true;
169 while ((q = EatParam(q, param, &flag)) != 0)
174 param = paths_GetLongPath(param);
175 m_Files.SetPath(m_Files.GetSize(), param);
176 if (param == m_sLeftDesc)
177 m_dwLeftFlags &= ~FFILEOPEN_READONLY;
178 if (param == m_sRightDesc)
179 m_dwRightFlags &= ~FFILEOPEN_READONLY;
181 else if (param == _T("base"))
183 // -base is followed by common ancestor file description.
184 q = EatParam(q, sBaseFile);
186 else if (param == _T("out"))
188 // -out is followed by merge's output file name.
189 q = EatParam(q, sOutFile);
191 else if (param == _T("fname"))
193 // -fname is followed by file description.
194 if (sBaseDesc.empty())
195 q = EatParam(q, sBaseDesc);
196 else if (m_sLeftDesc.empty())
198 q = EatParam(q, m_sLeftDesc);
199 m_dwLeftFlags |= FFILEOPEN_READONLY;
201 else if (m_sRightDesc.empty())
203 q = EatParam(q, m_sRightDesc);
204 m_dwRightFlags |= FFILEOPEN_READONLY;
207 q = EatParam(q, param); // ignore excess arguments
210 if (!sOutFile.empty())
212 String path = paths_GetLongPath(sOutFile);
213 m_sOutputpath = path;
218 * @brief Add path to list of paths.
219 * This method adds given string as a path to the list of paths. Path
220 * are converted if needed, shortcuts expanded etc.
221 * @param [in] path Path string to add.
223 void MergeCmdLineInfo::AddPath(const String &path)
227 // Convert paths given in Linux-style ('/' as separator) given from
228 // Cygwin to Windows style ('\' as separator)
229 string_replace(param, _T("/"), _T("\\"));
231 // If shortcut, expand it first
232 if (paths_IsShortcut(param))
233 param = ExpandShortcut(param);
234 param = paths_GetLongPath(param);
236 // Set flag indicating path is from command line
237 const size_t ord = m_Files.GetSize();
239 m_dwLeftFlags |= FFILEOPEN_CMDLINE;
241 m_dwRightFlags |= FFILEOPEN_CMDLINE;
243 m_Files.SetPath(m_Files.GetSize(), param);
247 * @brief Parse native WinMerge command line.
248 * @param [in] p Points into the command line.
250 void MergeCmdLineInfo::ParseWinMergeCmdLine(const TCHAR *q)
255 while ((q = EatParam(q, param, &flag)) != 0)
259 // Its not a flag so it is a path
262 else if (param == _T("?"))
264 // -? to show common command line arguments.
267 else if (param == _T("o"))
269 // -o "outputfilename"
270 q = EatParam(q, m_sOutputpath);
272 else if (param == _T("dl"))
274 // -dl "desc" - description for left file
275 q = EatParam(q, m_sLeftDesc);
277 else if (param == _T("dm"))
279 // -dr "desc" - description for middle file
280 q = EatParam(q, m_sMiddleDesc);
282 else if (param == _T("dr"))
284 // -dr "desc" - description for right file
285 q = EatParam(q, m_sRightDesc);
287 else if (param == _T("e"))
289 // -e to allow closing with single esc press
290 m_bEscShutdown = true;
292 else if (param == _T("f"))
294 // -f "mask" - file filter mask ("*.h *.cpp")
295 q = EatParam(q, m_sFileFilter);
297 else if (param == _T("r"))
299 // -r to compare recursively
302 else if (param == _T("s"))
304 // -s to allow only one instance
305 m_bSingleInstance = true;
307 else if (param == _T("noninteractive"))
309 // -noninteractive to suppress message boxes & close with result code
310 m_bNonInteractive = true;
312 else if (param == _T("noprefs"))
314 // -noprefs means do not load or remember options (preferences)
315 // Turn off serializing to registry.
316 // GetOptionsMgr()->SetSerializing(false);
317 // Load all default settings.
318 // theApp.ResetOptions();
320 else if (param == _T("minimize"))
322 // -minimize means minimize the main window.
323 m_nCmdShow = MINIMIZE;
325 else if (param == _T("maximize"))
327 // -maximize means maximize the main window.
328 m_nCmdShow = MAXIMIZE;
330 else if (param == _T("prediffer"))
332 // Get prediffer if specified (otherwise prediffer will be blank, which is default)
333 q = EatParam(q, m_sPreDiffer);
335 else if (param == _T("wl"))
337 // -wl to open left path as read-only
338 m_dwLeftFlags |= FFILEOPEN_READONLY;
340 else if (param == _T("wm"))
342 // -wm to open middle path as read-only
343 m_dwMiddleFlags |= FFILEOPEN_READONLY;
345 else if (param == _T("wr"))
347 // -wr to open right path as read-only
348 m_dwRightFlags |= FFILEOPEN_READONLY;
350 else if (param == _T("ul"))
352 // -ul to not add left path to MRU
353 m_dwLeftFlags |= FFILEOPEN_NOMRU;
355 else if (param == _T("um"))
357 // -um to not add middle path to MRU
358 m_dwMiddleFlags |= FFILEOPEN_NOMRU;
360 else if (param == _T("ur"))
362 // -ur to not add right path to MRU
363 m_dwRightFlags |= FFILEOPEN_NOMRU;
365 else if (param == _T("u") || param == _T("ub"))
367 // -u or -ub (deprecated) to add neither right nor left path to MRU
368 m_dwLeftFlags |= FFILEOPEN_NOMRU;
369 m_dwMiddleFlags |= FFILEOPEN_NOMRU;
370 m_dwRightFlags |= FFILEOPEN_NOMRU;
372 else if (param == _T("fl"))
374 // -fl to set focus to the left panbe
375 m_dwLeftFlags |= FFILEOPEN_SETFOCUS;
377 else if (param == _T("fm"))
379 // -fm to set focus to the middle pane
380 m_dwMiddleFlags |= FFILEOPEN_SETFOCUS;
382 else if (param == _T("fr"))
384 // -fr to set focus to the right pane
385 m_dwRightFlags |= FFILEOPEN_SETFOCUS;
387 else if (param == _T("al"))
389 // -al to auto-merge at the left pane
390 m_dwLeftFlags |= FFILEOPEN_AUTOMERGE;
392 else if (param == _T("am"))
394 // -am to auto-merge at the middle pane
395 m_dwMiddleFlags |= FFILEOPEN_AUTOMERGE;
397 else if (param == _T("ar"))
399 // -ar to auto-merge at the right pane
400 m_dwRightFlags |= FFILEOPEN_AUTOMERGE;
402 else if (param == _T("x"))
404 // -x to close application if files are identical.
405 m_bExitIfNoDiff = Exit;
407 else if (param == _T("xq"))
409 // -xn to close application if files are identical without showing
411 m_bExitIfNoDiff = ExitQuiet;
413 else if (param == _T("cp"))
416 q = EatParam(q, codepage);
417 try { m_nCodepage = string_stoi(codepage); } catch (...) { /* FIXME: */ }
419 else if (param == _T("ignorews"))
421 q = SetOption(q, OPT_CMP_IGNORE_WHITESPACE);
423 else if (param == _T("ignoreblanklines"))
425 q = SetOption(q, OPT_CMP_IGNORE_BLANKLINES);
427 else if (param == _T("ignorecase"))
429 q = SetOption(q, OPT_CMP_IGNORE_CASE);
431 else if (param == _T("ignoreeol"))
433 q = SetOption(q, OPT_CMP_IGNORE_EOL);
436 // If "compare file dir" make it "compare file dir\file".
437 if (m_Files.GetSize() >= 2)
439 PATH_EXISTENCE p1 = paths_DoesPathExist(m_Files[0]);
440 PATH_EXISTENCE p2 = paths_DoesPathExist(m_Files[1]);
442 if ((p1 == IS_EXISTING_FILE) && (p2 == IS_EXISTING_DIR))
444 m_Files[1] = paths_ConcatPath(m_Files[1], paths_FindFileName(m_Files[0]));
449 m_bNonInteractive = false;