toolkit/components/commandlines/nsCommandLine.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial