1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is the Mozilla toolkit.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Benjamin Smedberg <benjamin@smedbergs.us>
18 : *
19 : * Portions created by the Initial Developer are Copyright (C) 2004
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsICommandLineRunner.h"
39 :
40 : #include "nsICategoryManager.h"
41 : #include "nsICommandLineHandler.h"
42 : #include "nsICommandLineValidator.h"
43 : #include "nsIConsoleService.h"
44 : #include "nsIClassInfoImpl.h"
45 : #include "nsIDOMWindow.h"
46 : #include "nsIFile.h"
47 : #include "nsISimpleEnumerator.h"
48 : #include "nsIStringEnumerator.h"
49 :
50 : #include "nsCOMPtr.h"
51 : #include "mozilla/ModuleUtils.h"
52 : #include "nsISupportsImpl.h"
53 : #include "nsNativeCharsetUtils.h"
54 : #include "nsNetUtil.h"
55 : #include "nsUnicharUtils.h"
56 : #include "nsTArray.h"
57 : #include "nsTextFormatter.h"
58 : #include "nsXPCOMCID.h"
59 : #include "plstr.h"
60 :
61 : #ifdef MOZ_WIDGET_COCOA
62 : #include <CoreFoundation/CoreFoundation.h>
63 : #include "nsILocalFileMac.h"
64 : #elif defined(XP_WIN)
65 : #include <windows.h>
66 : #include <shlobj.h>
67 : #elif defined(XP_UNIX)
68 : #include <unistd.h>
69 : #elif defined(XP_OS2)
70 : #include <os2.h>
71 : #endif
72 :
73 : #ifdef DEBUG_bsmedberg
74 : #define DEBUG_COMMANDLINE
75 : #endif
76 :
77 : #define NS_COMMANDLINE_CID \
78 : { 0x23bcc750, 0xdc20, 0x460b, { 0xb2, 0xd4, 0x74, 0xd8, 0xf5, 0x8d, 0x36, 0x15 } }
79 :
80 : class nsCommandLine : public nsICommandLineRunner
81 : {
82 : public:
83 : NS_DECL_ISUPPORTS
84 : NS_DECL_NSICOMMANDLINE
85 : NS_DECL_NSICOMMANDLINERUNNER
86 :
87 : nsCommandLine();
88 :
89 : protected:
90 3 : ~nsCommandLine() { }
91 :
92 : typedef nsresult (*EnumerateHandlersCallback)(nsICommandLineHandler* aHandler,
93 : nsICommandLine* aThis,
94 : void *aClosure);
95 : typedef nsresult (*EnumerateValidatorsCallback)(nsICommandLineValidator* aValidator,
96 : nsICommandLine* aThis,
97 : void *aClosure);
98 :
99 : void appendArg(const char* arg);
100 : void resolveShortcutURL(nsILocalFile* aFile, nsACString& outURL);
101 : nsresult EnumerateHandlers(EnumerateHandlersCallback aCallback, void *aClosure);
102 : nsresult EnumerateValidators(EnumerateValidatorsCallback aCallback, void *aClosure);
103 :
104 : nsTArray<nsString> mArgs;
105 : PRUint32 mState;
106 : nsCOMPtr<nsIFile> mWorkingDir;
107 : nsCOMPtr<nsIDOMWindow> mWindowContext;
108 : bool mPreventDefault;
109 : };
110 :
111 3 : nsCommandLine::nsCommandLine() :
112 : mState(STATE_INITIAL_LAUNCH),
113 3 : mPreventDefault(false)
114 : {
115 :
116 3 : }
117 :
118 :
119 : NS_IMPL_CLASSINFO(nsCommandLine, NULL, 0, NS_COMMANDLINE_CID)
120 64 : NS_IMPL_ISUPPORTS2_CI(nsCommandLine,
121 : nsICommandLine,
122 6 : nsICommandLineRunner)
123 :
124 : NS_IMETHODIMP
125 1 : nsCommandLine::GetLength(PRInt32 *aResult)
126 : {
127 1 : *aResult = PRInt32(mArgs.Length());
128 1 : return NS_OK;
129 : }
130 :
131 : NS_IMETHODIMP
132 1 : nsCommandLine::GetArgument(PRInt32 aIndex, nsAString& aResult)
133 : {
134 1 : NS_ENSURE_ARG_MIN(aIndex, 0);
135 1 : NS_ENSURE_ARG_MAX(aIndex, PRInt32(mArgs.Length() - 1));
136 :
137 0 : aResult = mArgs[aIndex];
138 0 : return NS_OK;
139 : }
140 :
141 : NS_IMETHODIMP
142 0 : nsCommandLine::FindFlag(const nsAString& aFlag, bool aCaseSensitive, PRInt32 *aResult)
143 : {
144 0 : NS_ENSURE_ARG(!aFlag.IsEmpty());
145 :
146 0 : nsDefaultStringComparator caseCmp;
147 0 : nsCaseInsensitiveStringComparator caseICmp;
148 : nsStringComparator& c = aCaseSensitive ?
149 : static_cast<nsStringComparator&>(caseCmp) :
150 0 : static_cast<nsStringComparator&>(caseICmp);
151 :
152 0 : for (PRUint32 f = 0; f < mArgs.Length(); f++) {
153 0 : const nsString &arg = mArgs[f];
154 :
155 0 : if (arg.Length() >= 2 && arg.First() == PRUnichar('-')) {
156 0 : if (aFlag.Equals(Substring(arg, 1), c)) {
157 0 : *aResult = f;
158 0 : return NS_OK;
159 : }
160 : }
161 : }
162 :
163 0 : *aResult = -1;
164 0 : return NS_OK;
165 : }
166 :
167 : NS_IMETHODIMP
168 0 : nsCommandLine::RemoveArguments(PRInt32 aStart, PRInt32 aEnd)
169 : {
170 0 : NS_ENSURE_ARG_MIN(aStart, 0);
171 0 : NS_ENSURE_ARG_MAX(PRUint32(aEnd) + 1, mArgs.Length());
172 :
173 0 : for (PRInt32 i = aEnd; i >= aStart; --i) {
174 0 : mArgs.RemoveElementAt(i);
175 : }
176 :
177 0 : return NS_OK;
178 : }
179 :
180 : NS_IMETHODIMP
181 0 : nsCommandLine::HandleFlag(const nsAString& aFlag, bool aCaseSensitive,
182 : bool *aResult)
183 : {
184 : nsresult rv;
185 :
186 : PRInt32 found;
187 0 : rv = FindFlag(aFlag, aCaseSensitive, &found);
188 0 : NS_ENSURE_SUCCESS(rv, rv);
189 :
190 0 : if (found == -1) {
191 0 : *aResult = false;
192 0 : return NS_OK;
193 : }
194 :
195 0 : *aResult = true;
196 0 : RemoveArguments(found, found);
197 :
198 0 : return NS_OK;
199 : }
200 :
201 : NS_IMETHODIMP
202 0 : nsCommandLine::HandleFlagWithParam(const nsAString& aFlag, bool aCaseSensitive,
203 : nsAString& aResult)
204 : {
205 : nsresult rv;
206 :
207 : PRInt32 found;
208 0 : rv = FindFlag(aFlag, aCaseSensitive, &found);
209 0 : NS_ENSURE_SUCCESS(rv, rv);
210 :
211 0 : if (found == -1) {
212 0 : aResult.SetIsVoid(true);
213 0 : return NS_OK;
214 : }
215 :
216 0 : if (found == PRInt32(mArgs.Length()) - 1) {
217 0 : return NS_ERROR_INVALID_ARG;
218 : }
219 :
220 0 : ++found;
221 :
222 0 : if (mArgs[found].First() == '-') {
223 0 : return NS_ERROR_INVALID_ARG;
224 : }
225 :
226 0 : aResult = mArgs[found];
227 0 : RemoveArguments(found - 1, found);
228 :
229 0 : return NS_OK;
230 : }
231 :
232 : NS_IMETHODIMP
233 0 : nsCommandLine::GetState(PRUint32 *aResult)
234 : {
235 0 : *aResult = mState;
236 0 : return NS_OK;
237 : }
238 :
239 : NS_IMETHODIMP
240 0 : nsCommandLine::GetPreventDefault(bool *aResult)
241 : {
242 0 : *aResult = mPreventDefault;
243 0 : return NS_OK;
244 : }
245 :
246 : NS_IMETHODIMP
247 0 : nsCommandLine::SetPreventDefault(bool aValue)
248 : {
249 0 : mPreventDefault = aValue;
250 0 : return NS_OK;
251 : }
252 :
253 : NS_IMETHODIMP
254 0 : nsCommandLine::GetWorkingDirectory(nsIFile* *aResult)
255 : {
256 0 : NS_ENSURE_TRUE(mWorkingDir, NS_ERROR_NOT_INITIALIZED);
257 :
258 0 : NS_ADDREF(*aResult = mWorkingDir);
259 0 : return NS_OK;
260 : }
261 :
262 : NS_IMETHODIMP
263 0 : nsCommandLine::GetWindowContext(nsIDOMWindow* *aResult)
264 : {
265 0 : NS_IF_ADDREF(*aResult = mWindowContext);
266 0 : return NS_OK;
267 : }
268 :
269 : NS_IMETHODIMP
270 0 : nsCommandLine::SetWindowContext(nsIDOMWindow* aValue)
271 : {
272 0 : mWindowContext = aValue;
273 0 : return NS_OK;
274 : }
275 :
276 : NS_IMETHODIMP
277 0 : nsCommandLine::ResolveFile(const nsAString& aArgument, nsIFile* *aResult)
278 : {
279 0 : NS_ENSURE_TRUE(mWorkingDir, NS_ERROR_NOT_INITIALIZED);
280 :
281 : // This is some seriously screwed-up code. nsILocalFile.appendRelativeNativePath
282 : // explicitly does not accept .. or . path parts, but that is exactly what we
283 : // need here. So we hack around it.
284 :
285 : nsresult rv;
286 :
287 : #if defined(MOZ_WIDGET_COCOA)
288 : nsCOMPtr<nsILocalFileMac> lfm (do_QueryInterface(mWorkingDir));
289 : NS_ENSURE_TRUE(lfm, NS_ERROR_NO_INTERFACE);
290 :
291 : nsCOMPtr<nsILocalFileMac> newfile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
292 : NS_ENSURE_TRUE(newfile, NS_ERROR_OUT_OF_MEMORY);
293 :
294 : CFURLRef baseurl;
295 : rv = lfm->GetCFURL(&baseurl);
296 : NS_ENSURE_SUCCESS(rv, rv);
297 :
298 : nsCAutoString path;
299 : NS_CopyUnicodeToNative(aArgument, path);
300 :
301 : CFURLRef newurl =
302 : CFURLCreateFromFileSystemRepresentationRelativeToBase(NULL, (const UInt8*) path.get(),
303 : path.Length(),
304 : true, baseurl);
305 :
306 : CFRelease(baseurl);
307 :
308 : rv = newfile->InitWithCFURL(newurl);
309 : CFRelease(newurl);
310 : if (NS_FAILED(rv)) return rv;
311 :
312 : NS_ADDREF(*aResult = newfile);
313 : return NS_OK;
314 :
315 : #elif defined(XP_UNIX)
316 0 : nsCOMPtr<nsILocalFile> lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
317 0 : NS_ENSURE_TRUE(lf, NS_ERROR_OUT_OF_MEMORY);
318 :
319 0 : if (aArgument.First() == '/') {
320 : // absolute path
321 0 : rv = lf->InitWithPath(aArgument);
322 0 : if (NS_FAILED(rv)) return rv;
323 :
324 0 : NS_ADDREF(*aResult = lf);
325 0 : return NS_OK;
326 : }
327 :
328 0 : nsCAutoString nativeArg;
329 0 : NS_CopyUnicodeToNative(aArgument, nativeArg);
330 :
331 0 : nsCAutoString newpath;
332 0 : mWorkingDir->GetNativePath(newpath);
333 :
334 0 : newpath.Append('/');
335 0 : newpath.Append(nativeArg);
336 :
337 0 : rv = lf->InitWithNativePath(newpath);
338 0 : if (NS_FAILED(rv)) return rv;
339 :
340 0 : rv = lf->Normalize();
341 0 : if (NS_FAILED(rv)) return rv;
342 :
343 0 : NS_ADDREF(*aResult = lf);
344 0 : return NS_OK;
345 :
346 : #elif defined(XP_WIN32)
347 : nsCOMPtr<nsILocalFile> lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
348 : NS_ENSURE_TRUE(lf, NS_ERROR_OUT_OF_MEMORY);
349 :
350 : rv = lf->InitWithPath(aArgument);
351 : if (NS_FAILED(rv)) {
352 : // If it's a relative path, the Init is *going* to fail. We use string magic and
353 : // win32 _fullpath. Note that paths of the form "\Relative\To\CurDrive" are
354 : // going to fail, and I haven't figured out a way to work around this without
355 : // the PathCombine() function, which is not available in plain win95/nt4
356 :
357 : nsAutoString fullPath;
358 : mWorkingDir->GetPath(fullPath);
359 :
360 : fullPath.Append('\\');
361 : fullPath.Append(aArgument);
362 :
363 : WCHAR pathBuf[MAX_PATH];
364 : if (!_wfullpath(pathBuf, fullPath.get(), MAX_PATH))
365 : return NS_ERROR_FAILURE;
366 :
367 : rv = lf->InitWithPath(nsDependentString(pathBuf));
368 : if (NS_FAILED(rv)) return rv;
369 : }
370 : NS_ADDREF(*aResult = lf);
371 : return NS_OK;
372 :
373 : #elif defined(XP_OS2)
374 : nsCOMPtr<nsILocalFile> lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
375 : NS_ENSURE_TRUE(lf, NS_ERROR_OUT_OF_MEMORY);
376 :
377 : rv = lf->InitWithPath(aArgument);
378 : if (NS_FAILED(rv)) {
379 :
380 : nsCAutoString fullPath;
381 : mWorkingDir->GetNativePath(fullPath);
382 :
383 : nsCAutoString carg;
384 : NS_CopyUnicodeToNative(aArgument, carg);
385 :
386 : fullPath.Append('\\');
387 : fullPath.Append(carg);
388 :
389 : char pathBuf[CCHMAXPATH];
390 : if (DosQueryPathInfo(fullPath.get(), FIL_QUERYFULLNAME, pathBuf, sizeof(pathBuf)))
391 : return NS_ERROR_FAILURE;
392 :
393 : rv = lf->InitWithNativePath(nsDependentCString(pathBuf));
394 : if (NS_FAILED(rv)) return rv;
395 : }
396 : NS_ADDREF(*aResult = lf);
397 : return NS_OK;
398 :
399 : #else
400 : #error Need platform-specific logic here.
401 : #endif
402 : }
403 :
404 : NS_IMETHODIMP
405 1 : nsCommandLine::ResolveURI(const nsAString& aArgument, nsIURI* *aResult)
406 : {
407 : nsresult rv;
408 :
409 : // First, we try to init the argument as an absolute file path. If this doesn't
410 : // work, it is an absolute or relative URI.
411 :
412 2 : nsCOMPtr<nsIIOService> io = do_GetIOService();
413 1 : NS_ENSURE_TRUE(io, NS_ERROR_OUT_OF_MEMORY);
414 :
415 2 : nsCOMPtr<nsIURI> workingDirURI;
416 1 : if (mWorkingDir) {
417 0 : io->NewFileURI(mWorkingDir, getter_AddRefs(workingDirURI));
418 : }
419 :
420 2 : nsCOMPtr<nsILocalFile> lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
421 1 : rv = lf->InitWithPath(aArgument);
422 1 : if (NS_SUCCEEDED(rv)) {
423 1 : lf->Normalize();
424 2 : nsCAutoString url;
425 : // Try to resolve the url for .url files.
426 1 : resolveShortcutURL(lf, url);
427 1 : if (!url.IsEmpty()) {
428 1 : return io->NewURI(url,
429 : nsnull,
430 : workingDirURI,
431 1 : aResult);
432 : }
433 :
434 0 : return io->NewFileURI(lf, aResult);
435 : }
436 :
437 0 : return io->NewURI(NS_ConvertUTF16toUTF8(aArgument),
438 : nsnull,
439 : workingDirURI,
440 0 : aResult);
441 : }
442 :
443 : void
444 0 : nsCommandLine::appendArg(const char* arg)
445 : {
446 : #ifdef DEBUG_COMMANDLINE
447 : printf("Adding XP arg: %s\n", arg);
448 : #endif
449 :
450 0 : nsAutoString warg;
451 : #ifdef XP_WIN
452 : CopyUTF8toUTF16(nsDependentCString(arg), warg);
453 : #else
454 0 : NS_CopyNativeToUnicode(nsDependentCString(arg), warg);
455 : #endif
456 :
457 0 : mArgs.AppendElement(warg);
458 0 : }
459 :
460 : void
461 1 : nsCommandLine::resolveShortcutURL(nsILocalFile* aFile, nsACString& outURL)
462 : {
463 2 : nsCOMPtr<nsIFileProtocolHandler> fph;
464 1 : nsresult rv = NS_GetFileProtocolHandler(getter_AddRefs(fph));
465 1 : if (NS_FAILED(rv))
466 : return;
467 :
468 2 : nsCOMPtr<nsIURI> uri;
469 1 : rv = fph->ReadURLFile(aFile, getter_AddRefs(uri));
470 1 : if (NS_FAILED(rv))
471 : return;
472 :
473 2 : uri->GetSpec(outURL);
474 : }
475 :
476 : NS_IMETHODIMP
477 0 : nsCommandLine::Init(PRInt32 argc, char** argv, nsIFile* aWorkingDir,
478 : PRUint32 aState)
479 : {
480 : NS_ENSURE_ARG_MIN(aState, 0);
481 0 : NS_ENSURE_ARG_MAX(aState, 2);
482 :
483 : PRInt32 i;
484 :
485 0 : mWorkingDir = aWorkingDir;
486 :
487 : // skip argv[0], we don't want it
488 0 : for (i = 1; i < argc; ++i) {
489 0 : const char* curarg = argv[i];
490 :
491 : #ifdef DEBUG_COMMANDLINE
492 : printf("Testing native arg %i: '%s'\n", i, curarg);
493 : #endif
494 : #if defined(XP_WIN) || defined(XP_OS2)
495 : if (*curarg == '/') {
496 : char* dup = PL_strdup(curarg);
497 : if (!dup) return NS_ERROR_OUT_OF_MEMORY;
498 :
499 : *dup = '-';
500 : char* colon = PL_strchr(dup, ':');
501 : if (colon) {
502 : *colon = '\0';
503 : appendArg(dup);
504 : appendArg(colon+1);
505 : } else {
506 : appendArg(dup);
507 : }
508 : PL_strfree(dup);
509 : continue;
510 : }
511 : #endif
512 : #ifdef XP_UNIX
513 0 : if (*curarg == '-' &&
514 0 : *(curarg+1) == '-') {
515 0 : ++curarg;
516 :
517 0 : char* dup = PL_strdup(curarg);
518 0 : if (!dup) return NS_ERROR_OUT_OF_MEMORY;
519 :
520 0 : char* eq = PL_strchr(dup, '=');
521 0 : if (eq) {
522 0 : *eq = '\0';
523 0 : appendArg(dup);
524 0 : appendArg(eq + 1);
525 : } else {
526 0 : appendArg(dup);
527 : }
528 0 : PL_strfree(dup);
529 0 : continue;
530 : }
531 : #endif
532 :
533 0 : appendArg(curarg);
534 : }
535 :
536 0 : mState = aState;
537 :
538 0 : return NS_OK;
539 : }
540 :
541 : static void
542 0 : LogConsoleMessage(const PRUnichar* fmt, ...)
543 : {
544 : va_list args;
545 0 : va_start(args, fmt);
546 0 : PRUnichar* msg = nsTextFormatter::vsmprintf(fmt, args);
547 0 : va_end(args);
548 :
549 0 : nsCOMPtr<nsIConsoleService> cs = do_GetService("@mozilla.org/consoleservice;1");
550 0 : if (cs)
551 0 : cs->LogStringMessage(msg);
552 :
553 0 : NS_Free(msg);
554 0 : }
555 :
556 : nsresult
557 0 : nsCommandLine::EnumerateHandlers(EnumerateHandlersCallback aCallback, void *aClosure)
558 : {
559 : nsresult rv;
560 :
561 : nsCOMPtr<nsICategoryManager> catman
562 0 : (do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
563 0 : NS_ENSURE_TRUE(catman, NS_ERROR_UNEXPECTED);
564 :
565 0 : nsCOMPtr<nsISimpleEnumerator> entenum;
566 0 : rv = catman->EnumerateCategory("command-line-handler",
567 0 : getter_AddRefs(entenum));
568 0 : NS_ENSURE_SUCCESS(rv, rv);
569 :
570 0 : nsCOMPtr<nsIUTF8StringEnumerator> strenum (do_QueryInterface(entenum));
571 0 : NS_ENSURE_TRUE(strenum, NS_ERROR_UNEXPECTED);
572 :
573 0 : nsCAutoString entry;
574 : bool hasMore;
575 0 : while (NS_SUCCEEDED(strenum->HasMore(&hasMore)) && hasMore) {
576 0 : strenum->GetNext(entry);
577 :
578 0 : nsCString contractID;
579 0 : rv = catman->GetCategoryEntry("command-line-handler",
580 : entry.get(),
581 0 : getter_Copies(contractID));
582 0 : if (NS_FAILED(rv))
583 0 : continue;
584 :
585 0 : nsCOMPtr<nsICommandLineHandler> clh(do_GetService(contractID.get()));
586 0 : if (!clh) {
587 0 : LogConsoleMessage(NS_LITERAL_STRING("Contract ID '%s' was registered as a command line handler for entry '%s', but could not be created.").get(),
588 0 : contractID.get(), entry.get());
589 0 : continue;
590 : }
591 :
592 0 : rv = (aCallback)(clh, this, aClosure);
593 0 : if (rv == NS_ERROR_ABORT)
594 : break;
595 :
596 0 : rv = NS_OK;
597 : }
598 :
599 0 : return rv;
600 : }
601 :
602 : nsresult
603 0 : nsCommandLine::EnumerateValidators(EnumerateValidatorsCallback aCallback, void *aClosure)
604 : {
605 : nsresult rv;
606 :
607 : nsCOMPtr<nsICategoryManager> catman
608 0 : (do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
609 0 : NS_ENSURE_TRUE(catman, NS_ERROR_UNEXPECTED);
610 :
611 0 : nsCOMPtr<nsISimpleEnumerator> entenum;
612 0 : rv = catman->EnumerateCategory("command-line-validator",
613 0 : getter_AddRefs(entenum));
614 0 : NS_ENSURE_SUCCESS(rv, rv);
615 :
616 0 : nsCOMPtr<nsIUTF8StringEnumerator> strenum (do_QueryInterface(entenum));
617 0 : NS_ENSURE_TRUE(strenum, NS_ERROR_UNEXPECTED);
618 :
619 0 : nsCAutoString entry;
620 : bool hasMore;
621 0 : while (NS_SUCCEEDED(strenum->HasMore(&hasMore)) && hasMore) {
622 0 : strenum->GetNext(entry);
623 :
624 0 : nsXPIDLCString contractID;
625 0 : rv = catman->GetCategoryEntry("command-line-validator",
626 : entry.get(),
627 0 : getter_Copies(contractID));
628 0 : if (!contractID)
629 0 : continue;
630 :
631 0 : nsCOMPtr<nsICommandLineValidator> clv(do_GetService(contractID.get()));
632 0 : if (!clv)
633 0 : continue;
634 :
635 0 : rv = (aCallback)(clv, this, aClosure);
636 0 : if (rv == NS_ERROR_ABORT)
637 : break;
638 :
639 0 : rv = NS_OK;
640 : }
641 :
642 0 : return rv;
643 : }
644 :
645 : static nsresult
646 0 : EnumValidate(nsICommandLineValidator* aValidator, nsICommandLine* aThis, void*)
647 : {
648 0 : return aValidator->Validate(aThis);
649 : }
650 :
651 : static nsresult
652 0 : EnumRun(nsICommandLineHandler* aHandler, nsICommandLine* aThis, void*)
653 : {
654 0 : return aHandler->Handle(aThis);
655 : }
656 :
657 : NS_IMETHODIMP
658 0 : nsCommandLine::Run()
659 : {
660 : nsresult rv;
661 :
662 0 : rv = EnumerateValidators(EnumValidate, nsnull);
663 0 : if (rv == NS_ERROR_ABORT)
664 0 : return rv;
665 :
666 0 : rv = EnumerateHandlers(EnumRun, nsnull);
667 0 : if (rv == NS_ERROR_ABORT)
668 0 : return rv;
669 :
670 0 : return NS_OK;
671 : }
672 :
673 : static nsresult
674 0 : EnumHelp(nsICommandLineHandler* aHandler, nsICommandLine* aThis, void* aClosure)
675 : {
676 : nsresult rv;
677 :
678 0 : nsCString text;
679 0 : rv = aHandler->GetHelpInfo(text);
680 0 : if (NS_SUCCEEDED(rv)) {
681 0 : NS_ASSERTION(text.Length() == 0 || text.Last() == '\n',
682 : "Help text from command line handlers should end in a newline.");
683 :
684 0 : nsACString* totalText = reinterpret_cast<nsACString*>(aClosure);
685 0 : totalText->Append(text);
686 : }
687 :
688 0 : return NS_OK;
689 : }
690 :
691 : NS_IMETHODIMP
692 0 : nsCommandLine::GetHelpText(nsACString& aResult)
693 : {
694 0 : EnumerateHandlers(EnumHelp, &aResult);
695 :
696 0 : return NS_OK;
697 : }
698 :
699 6 : NS_GENERIC_FACTORY_CONSTRUCTOR(nsCommandLine)
700 :
701 : NS_DEFINE_NAMED_CID(NS_COMMANDLINE_CID);
702 :
703 : static const mozilla::Module::CIDEntry kCommandLineCIDs[] = {
704 : { &kNS_COMMANDLINE_CID, false, NULL, nsCommandLineConstructor },
705 : { NULL }
706 : };
707 :
708 : static const mozilla::Module::ContractIDEntry kCommandLineContracts[] = {
709 : { "@mozilla.org/toolkit/command-line;1", &kNS_COMMANDLINE_CID },
710 : { NULL }
711 : };
712 :
713 : static const mozilla::Module kCommandLineModule = {
714 : mozilla::Module::kVersion,
715 : kCommandLineCIDs,
716 : kCommandLineContracts
717 : };
718 :
719 : NSMODULE_DEFN(CommandLineModule) = &kCommandLineModule;
|