Back to index

lightning-sunbird  0.9+nobinonly
nsCommandLine.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Mozilla toolkit.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Benjamin Smedberg <benjamin@smedbergs.us>
00018  *
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsICommandLineRunner.h"
00039 
00040 #include "nsICategoryManager.h"
00041 #include "nsICommandLineHandler.h"
00042 #include "nsICommandLineValidator.h"
00043 #include "nsIDOMWindow.h"
00044 #include "nsIFile.h"
00045 #include "nsISimpleEnumerator.h"
00046 #include "nsIStringEnumerator.h"
00047 
00048 #include "nsCOMPtr.h"
00049 #include "nsIGenericFactory.h"
00050 #include "nsISupportsImpl.h"
00051 #include "nsNativeCharsetUtils.h"
00052 #include "nsNetUtil.h"
00053 #include "nsUnicharUtils.h"
00054 #include "nsVoidArray.h"
00055 #include "nsXPCOMCID.h"
00056 #include "plstr.h"
00057 
00058 #ifdef XP_MACOSX
00059 #include <CFURL.h>
00060 #include "nsILocalFileMac.h"
00061 #elif defined(XP_WIN)
00062 #include <windows.h>
00063 #include <shlobj.h>
00064 #elif defined(XP_BEOS)
00065 #include <Path.h>
00066 #include <Directory.h>
00067 #elif defined(XP_UNIX)
00068 #include <unistd.h>
00069 #elif defined(XP_OS2)
00070 #include <os2.h>
00071 #endif
00072 
00073 #ifdef DEBUG_bsmedberg
00074 #define DEBUG_COMMANDLINE
00075 #endif
00076 
00077 class nsCommandLine : public nsICommandLineRunner
00078 {
00079 public:
00080   NS_DECL_ISUPPORTS
00081   NS_DECL_NSICOMMANDLINE
00082   NS_DECL_NSICOMMANDLINERUNNER
00083 
00084   nsCommandLine();
00085 
00086 protected:
00087   ~nsCommandLine() { }
00088 
00089   typedef nsresult (*EnumerateHandlersCallback)(nsICommandLineHandler* aHandler,
00090                                    nsICommandLine* aThis,
00091                                    void *aClosure);
00092   typedef nsresult (*EnumerateValidatorsCallback)(nsICommandLineValidator* aValidator,
00093                                    nsICommandLine* aThis,
00094                                    void *aClosure);
00095 
00096   void appendArg(const char* arg);
00097   void resolveShortcutURL(nsILocalFile* aFile, nsACString& outURL);
00098   nsresult EnumerateHandlers(EnumerateHandlersCallback aCallback, void *aClosure);
00099   nsresult EnumerateValidators(EnumerateValidatorsCallback aCallback, void *aClosure);
00100 
00101   nsStringArray     mArgs;
00102   PRUint32          mState;
00103   nsCOMPtr<nsIFile> mWorkingDir;
00104   nsCOMPtr<nsIDOMWindow> mWindowContext;
00105   PRBool            mPreventDefault;
00106 };
00107 
00108 nsCommandLine::nsCommandLine() :
00109   mState(STATE_INITIAL_LAUNCH),
00110   mPreventDefault(PR_FALSE)
00111 {
00112 
00113 }
00114 
00115 
00116 NS_IMPL_ISUPPORTS2(nsCommandLine,
00117                    nsICommandLine,
00118                    nsICommandLineRunner)
00119 
00120 NS_IMETHODIMP
00121 nsCommandLine::GetLength(PRInt32 *aResult)
00122 {
00123   *aResult = mArgs.Count();
00124   return NS_OK;
00125 }
00126 
00127 NS_IMETHODIMP
00128 nsCommandLine::GetArgument(PRInt32 aIndex, nsAString& aResult)
00129 {
00130   NS_ENSURE_ARG_MIN(aIndex, 0);
00131   NS_ENSURE_ARG_MAX(aIndex, mArgs.Count());
00132 
00133   mArgs.StringAt(aIndex, aResult);
00134   return NS_OK;
00135 }
00136 
00137 NS_IMETHODIMP
00138 nsCommandLine::FindFlag(const nsAString& aFlag, PRBool aCaseSensitive, PRInt32 *aResult)
00139 {
00140   NS_ENSURE_ARG(!aFlag.IsEmpty());
00141 
00142   PRInt32 f;
00143 
00144   nsDefaultStringComparator caseCmp;
00145   nsCaseInsensitiveStringComparator caseICmp;
00146   nsStringComparator& c = aCaseSensitive ?
00147     NS_STATIC_CAST(nsStringComparator&, caseCmp) :
00148     NS_STATIC_CAST(nsStringComparator&, caseICmp);
00149 
00150   for (f = 0; f < mArgs.Count(); ++f) {
00151     const nsString &arg = *mArgs[f];
00152 
00153     if (arg.Length() >= 2 && arg.First() == PRUnichar('-')) {
00154       if (aFlag.Equals(Substring(arg, 1), c)) {
00155         *aResult = f;
00156         return NS_OK;
00157       }
00158     }
00159   }
00160 
00161   *aResult = -1;
00162   return NS_OK;
00163 }
00164 
00165 NS_IMETHODIMP
00166 nsCommandLine::RemoveArguments(PRInt32 aStart, PRInt32 aEnd)
00167 {
00168   NS_ENSURE_ARG_MIN(aStart, 0);
00169   NS_ENSURE_ARG_MAX(aEnd, mArgs.Count() - 1);
00170 
00171   for (PRInt32 i = aEnd; i >= aStart; --i) {
00172     mArgs.RemoveStringAt(i);
00173   }
00174 
00175   return NS_OK;
00176 }
00177 
00178 NS_IMETHODIMP
00179 nsCommandLine::HandleFlag(const nsAString& aFlag, PRBool aCaseSensitive,
00180                           PRBool *aResult)
00181 {
00182   nsresult rv;
00183 
00184   PRInt32 found;
00185   rv = FindFlag(aFlag, aCaseSensitive, &found);
00186   NS_ENSURE_SUCCESS(rv, rv);
00187 
00188   if (found == -1) {
00189     *aResult = PR_FALSE;
00190     return NS_OK;
00191   }
00192 
00193   *aResult = PR_TRUE;
00194   RemoveArguments(found, found);
00195 
00196   return NS_OK;
00197 }
00198 
00199 NS_IMETHODIMP
00200 nsCommandLine::HandleFlagWithParam(const nsAString& aFlag, PRBool aCaseSensitive,
00201                                    nsAString& aResult)
00202 {
00203   nsresult rv;
00204 
00205   PRInt32 found;
00206   rv = FindFlag(aFlag, aCaseSensitive, &found);
00207   NS_ENSURE_SUCCESS(rv, rv);
00208 
00209   if (found == -1) {
00210     aResult.SetIsVoid(PR_TRUE);
00211     return NS_OK;
00212   }
00213 
00214   if (found == mArgs.Count() - 1) {
00215     return NS_ERROR_INVALID_ARG;
00216   }
00217 
00218   ++found;
00219 
00220   if (mArgs[found]->First() == '-') {
00221     return NS_ERROR_INVALID_ARG;
00222   }
00223 
00224   mArgs.StringAt(found, aResult);
00225   RemoveArguments(found - 1, found);
00226 
00227   return NS_OK;
00228 }
00229 
00230 NS_IMETHODIMP
00231 nsCommandLine::GetState(PRUint32 *aResult)
00232 {
00233   *aResult = mState;
00234   return NS_OK;
00235 }
00236 
00237 NS_IMETHODIMP
00238 nsCommandLine::GetPreventDefault(PRBool *aResult)
00239 {
00240   *aResult = mPreventDefault;
00241   return NS_OK;
00242 }
00243 
00244 NS_IMETHODIMP
00245 nsCommandLine::SetPreventDefault(PRBool aValue)
00246 {
00247   mPreventDefault = aValue;
00248   return NS_OK;
00249 }
00250 
00251 NS_IMETHODIMP
00252 nsCommandLine::GetWorkingDirectory(nsIFile* *aResult)
00253 {
00254   NS_ENSURE_TRUE(mWorkingDir, NS_ERROR_NOT_INITIALIZED);
00255 
00256   NS_ADDREF(*aResult = mWorkingDir);
00257   return NS_OK;
00258 }
00259 
00260 NS_IMETHODIMP
00261 nsCommandLine::GetWindowContext(nsIDOMWindow* *aResult)
00262 {
00263   NS_IF_ADDREF(*aResult = mWindowContext);
00264   return NS_OK;
00265 }
00266 
00267 NS_IMETHODIMP
00268 nsCommandLine::SetWindowContext(nsIDOMWindow* aValue)
00269 {
00270   mWindowContext = aValue;
00271   return NS_OK;
00272 }
00273 
00274 NS_IMETHODIMP
00275 nsCommandLine::ResolveFile(const nsAString& aArgument, nsIFile* *aResult)
00276 {
00277   NS_ENSURE_TRUE(mWorkingDir, NS_ERROR_NOT_INITIALIZED);
00278 
00279   // This is some seriously screwed-up code. nsILocalFile.appendRelativeNativePath
00280   // explicitly does not accept .. or . path parts, but that is exactly what we
00281   // need here. So we hack around it.
00282 
00283   nsresult rv;
00284 
00285 #if defined(XP_MACOSX)
00286   nsCOMPtr<nsILocalFileMac> lfm (do_QueryInterface(mWorkingDir));
00287   NS_ENSURE_TRUE(lfm, NS_ERROR_NO_INTERFACE);
00288 
00289   nsCOMPtr<nsILocalFileMac> newfile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
00290   NS_ENSURE_TRUE(newfile, NS_ERROR_OUT_OF_MEMORY);
00291 
00292   CFURLRef baseurl;
00293   rv = lfm->GetCFURL(&baseurl);
00294   NS_ENSURE_SUCCESS(rv, rv);
00295 
00296   nsCAutoString path;
00297   NS_CopyUnicodeToNative(aArgument, path);
00298 
00299   CFURLRef newurl =
00300     CFURLCreateFromFileSystemRepresentationRelativeToBase(NULL, (const UInt8*) path.get(),
00301                                                           path.Length(),
00302                                                           true, baseurl);
00303 
00304   CFRelease(baseurl);
00305 
00306   rv = newfile->InitWithCFURL(newurl);
00307   CFRelease(newurl);
00308   if (NS_FAILED(rv)) return rv;
00309 
00310   NS_ADDREF(*aResult = newfile);
00311   return NS_OK;
00312 
00313 #elif defined(XP_BEOS)
00314   nsCOMPtr<nsILocalFile> lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
00315   NS_ENSURE_TRUE(lf, NS_ERROR_OUT_OF_MEMORY);
00316 
00317   if (aArgument.First() == '/') {
00318     // absolute path
00319     rv = lf->InitWithPath(aArgument);
00320     if (NS_FAILED(rv)) return rv;
00321 
00322     NS_ADDREF(*aResult = lf);
00323     return NS_OK;
00324   }
00325 
00326   nsCAutoString carg;
00327   NS_CopyUnicodeToNative(aArgument, carg);
00328 
00329   nsCAutoString wd;
00330   rv = mWorkingDir->GetNativePath(wd);
00331   NS_ENSURE_SUCCESS(rv, rv);
00332 
00333   BDirectory bwd(wd.get());
00334 
00335   BPath resolved(&bwd, carg.get(), true);
00336   if (resolved.InitCheck() != B_OK)
00337     return NS_ERROR_FAILURE;
00338 
00339   rv = lf->InitWithNativePath(nsDependentCString(resolved.Path()));
00340   if (NS_FAILED(rv)) return rv;
00341 
00342   NS_ADDREF(*aResult = lf);
00343   return NS_OK;
00344 
00345 #elif defined(XP_UNIX)
00346   nsCOMPtr<nsILocalFile> lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
00347   NS_ENSURE_TRUE(lf, NS_ERROR_OUT_OF_MEMORY);
00348 
00349   if (aArgument.First() == '/') {
00350     // absolute path
00351     rv = lf->InitWithPath(aArgument);
00352     if (NS_FAILED(rv)) return rv;
00353 
00354     NS_ADDREF(*aResult = lf);
00355     return NS_OK;
00356   }
00357 
00358   nsCAutoString nativeArg;
00359   NS_CopyUnicodeToNative(aArgument, nativeArg);
00360 
00361   nsCAutoString newpath;
00362   mWorkingDir->GetNativePath(newpath);
00363 
00364   newpath.Append('/');
00365   newpath.Append(nativeArg);
00366 
00367   rv = lf->InitWithNativePath(newpath);
00368   if (NS_FAILED(rv)) return rv;
00369 
00370   rv = lf->Normalize();
00371   if (NS_FAILED(rv)) return rv;
00372 
00373   NS_ADDREF(*aResult = lf);
00374   return NS_OK;
00375 
00376 #elif defined(XP_WIN32)
00377   nsCOMPtr<nsILocalFile> lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
00378   NS_ENSURE_TRUE(lf, NS_ERROR_OUT_OF_MEMORY);
00379 
00380   rv = lf->InitWithPath(aArgument);
00381   if (NS_FAILED(rv)) {
00382     // If it's a relative path, the Init is *going* to fail. We use string magic and
00383     // win32 _fullpath. Note that paths of the form "\Relative\To\CurDrive" are
00384     // going to fail, and I haven't figured out a way to work around this without
00385     // the PathCombine() function, which is not available in plain win95/nt4
00386 
00387     nsCAutoString fullPath;
00388     mWorkingDir->GetNativePath(fullPath);
00389 
00390     nsCAutoString carg;
00391     NS_CopyUnicodeToNative(aArgument, carg);
00392 
00393     fullPath.Append('\\');
00394     fullPath.Append(carg);
00395 
00396     char pathBuf[MAX_PATH];
00397     if (!_fullpath(pathBuf, fullPath.get(), MAX_PATH))
00398       return NS_ERROR_FAILURE;
00399 
00400     rv = lf->InitWithNativePath(nsDependentCString(pathBuf));
00401     if (NS_FAILED(rv)) return rv;
00402   }
00403   NS_ADDREF(*aResult = lf);
00404   return NS_OK;
00405 
00406 #elif defined(XP_OS2)
00407   nsCOMPtr<nsILocalFile> lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
00408   NS_ENSURE_TRUE(lf, NS_ERROR_OUT_OF_MEMORY);
00409 
00410   rv = lf->InitWithPath(aArgument);
00411   if (NS_FAILED(rv)) {
00412 
00413     nsCAutoString fullPath;
00414     mWorkingDir->GetNativePath(fullPath);
00415 
00416     nsCAutoString carg;
00417     NS_CopyUnicodeToNative(aArgument, carg);
00418 
00419     fullPath.Append('\\');
00420     fullPath.Append(carg);
00421 
00422     char pathBuf[CCHMAXPATH];
00423     if (DosQueryPathInfo(fullPath.get(), FIL_QUERYFULLNAME, pathBuf, sizeof(pathBuf)))
00424       return NS_ERROR_FAILURE;
00425 
00426     rv = lf->InitWithNativePath(nsDependentCString(pathBuf));
00427     if (NS_FAILED(rv)) return rv;
00428   }
00429   NS_ADDREF(*aResult = lf);
00430   return NS_OK;
00431 
00432 #else
00433 #error Need platform-specific logic here.
00434 #endif
00435 }
00436 
00437 NS_IMETHODIMP
00438 nsCommandLine::ResolveURI(const nsAString& aArgument, nsIURI* *aResult)
00439 {
00440   nsresult rv;
00441 
00442   // First, we try to init the argument as an absolute file path. If this doesn't
00443   // work, it is an absolute or relative URI.
00444 
00445   nsCOMPtr<nsIIOService> io = do_GetIOService();
00446   NS_ENSURE_TRUE(io, NS_ERROR_OUT_OF_MEMORY);
00447 
00448   nsCOMPtr<nsIURI> workingDirURI;
00449   if (mWorkingDir) {
00450     io->NewFileURI(mWorkingDir, getter_AddRefs(workingDirURI));
00451   }
00452 
00453   nsCOMPtr<nsILocalFile> lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
00454   rv = lf->InitWithPath(aArgument);
00455   if (NS_SUCCEEDED(rv)) {
00456     lf->Normalize();
00457     nsCAutoString url;
00458     // Try to resolve the url for .url files.
00459     resolveShortcutURL(lf, url);
00460     if (!url.IsEmpty()) {
00461       return io->NewURI(url,
00462                         nsnull,
00463                         workingDirURI,
00464                         aResult);
00465     }
00466     return io->NewFileURI(lf, aResult);
00467   }
00468 
00469   return io->NewURI(NS_ConvertUTF16toUTF8(aArgument),
00470                     nsnull,
00471                     workingDirURI,
00472                     aResult);
00473 }
00474 
00475 void
00476 nsCommandLine::appendArg(const char* arg)
00477 {
00478 #ifdef DEBUG_COMMANDLINE
00479   printf("Adding XP arg: %s\n", arg);
00480 #endif
00481 
00482   nsAutoString warg;
00483   NS_CopyNativeToUnicode(nsDependentCString(arg), warg);
00484 
00485   mArgs.AppendString(warg);
00486 }
00487 
00488 void
00489 nsCommandLine::resolveShortcutURL(nsILocalFile* aFile, nsACString& outURL)
00490 {
00491   nsCOMPtr<nsIFileProtocolHandler> fph;
00492   nsresult rv = NS_GetFileProtocolHandler(getter_AddRefs(fph));
00493   if (NS_FAILED(rv))
00494     return;
00495 
00496   nsCOMPtr<nsIURI> uri;
00497   rv = fph->ReadURLFile(aFile, getter_AddRefs(uri));
00498   if (NS_FAILED(rv))
00499     return;
00500 
00501   uri->GetSpec(outURL);
00502 }
00503 
00504 NS_IMETHODIMP
00505 nsCommandLine::Init(PRInt32 argc, char** argv, nsIFile* aWorkingDir,
00506                     PRUint32 aState)
00507 {
00508   NS_ENSURE_ARG_MIN(aState, 0);
00509   NS_ENSURE_ARG_MAX(aState, 2);
00510 
00511   PRInt32 i;
00512 
00513   mWorkingDir = aWorkingDir;
00514 
00515   // skip argv[0], we don't want it
00516   for (i = 1; i < argc; ++i) {
00517     const char* curarg = argv[i];
00518 
00519 #ifdef DEBUG_COMMANDLINE
00520     printf("Testing native arg %i: '%s'\n", i, curarg);
00521 #endif
00522 #if defined(XP_WIN) || defined(XP_OS2)
00523     if (*curarg == '/') {
00524       char* dup = PL_strdup(curarg);
00525       if (!dup) return NS_ERROR_OUT_OF_MEMORY;
00526 
00527       *dup = '-';
00528       char* colon = PL_strchr(dup, ':');
00529       if (colon) {
00530         *colon = '\0';
00531         appendArg(dup);
00532         appendArg(colon+1);
00533       } else {
00534         appendArg(dup);
00535       }
00536       PL_strfree(dup);
00537       continue;
00538     }
00539 #endif
00540 #ifdef XP_UNIX
00541     if (*curarg == '-' &&
00542         *(curarg+1) == '-') {
00543       ++curarg;
00544 
00545       char* dup = PL_strdup(curarg);
00546       if (!dup) return NS_ERROR_OUT_OF_MEMORY;
00547 
00548       char* eq = PL_strchr(dup, '=');
00549       if (eq) {
00550         *eq = '\0';
00551         appendArg(dup);
00552         appendArg(eq + 1);
00553       } else {
00554         appendArg(dup);
00555       }
00556       PL_strfree(dup);
00557       continue;
00558     }
00559 #endif
00560 
00561     appendArg(curarg);
00562   }
00563 
00564   mState = aState;
00565 
00566   return NS_OK;
00567 }
00568 
00569 nsresult
00570 nsCommandLine::EnumerateHandlers(EnumerateHandlersCallback aCallback, void *aClosure)
00571 {
00572   nsresult rv;
00573 
00574   nsCOMPtr<nsICategoryManager> catman
00575     (do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
00576   NS_ENSURE_TRUE(catman, NS_ERROR_UNEXPECTED);
00577 
00578   nsCOMPtr<nsISimpleEnumerator> entenum;
00579   rv = catman->EnumerateCategory("command-line-handler",
00580                                  getter_AddRefs(entenum));
00581   NS_ENSURE_SUCCESS(rv, rv);
00582 
00583   nsCOMPtr<nsIUTF8StringEnumerator> strenum (do_QueryInterface(entenum));
00584   NS_ENSURE_TRUE(strenum, NS_ERROR_UNEXPECTED);
00585 
00586   nsCAutoString entry;
00587   PRBool hasMore;
00588   while (NS_SUCCEEDED(strenum->HasMore(&hasMore)) && hasMore) {
00589     strenum->GetNext(entry);
00590 
00591     nsXPIDLCString contractID;
00592     rv = catman->GetCategoryEntry("command-line-handler",
00593                               entry.get(),
00594                               getter_Copies(contractID));
00595     if (!contractID)
00596       continue;
00597 
00598     nsCOMPtr<nsICommandLineHandler> clh(do_GetService(contractID.get()));
00599     if (!clh)
00600       continue;
00601 
00602     rv = (aCallback)(clh, this, aClosure);
00603     if (rv == NS_ERROR_ABORT)
00604       break;
00605 
00606     rv = NS_OK;
00607   }
00608 
00609   return rv;
00610 }
00611 
00612 nsresult
00613 nsCommandLine::EnumerateValidators(EnumerateValidatorsCallback aCallback, void *aClosure)
00614 {
00615   nsresult rv;
00616 
00617   nsCOMPtr<nsICategoryManager> catman
00618     (do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
00619   NS_ENSURE_TRUE(catman, NS_ERROR_UNEXPECTED);
00620 
00621   nsCOMPtr<nsISimpleEnumerator> entenum;
00622   rv = catman->EnumerateCategory("command-line-validator",
00623                                  getter_AddRefs(entenum));
00624   NS_ENSURE_SUCCESS(rv, rv);
00625 
00626   nsCOMPtr<nsIUTF8StringEnumerator> strenum (do_QueryInterface(entenum));
00627   NS_ENSURE_TRUE(strenum, NS_ERROR_UNEXPECTED);
00628 
00629   nsCAutoString entry;
00630   PRBool hasMore;
00631   while (NS_SUCCEEDED(strenum->HasMore(&hasMore)) && hasMore) {
00632     strenum->GetNext(entry);
00633 
00634     nsXPIDLCString contractID;
00635     rv = catman->GetCategoryEntry("command-line-validator",
00636                               entry.get(),
00637                               getter_Copies(contractID));
00638     if (!contractID)
00639       continue;
00640 
00641     nsCOMPtr<nsICommandLineValidator> clv(do_GetService(contractID.get()));
00642     if (!clv)
00643       continue;
00644 
00645     rv = (aCallback)(clv, this, aClosure);
00646     if (rv == NS_ERROR_ABORT)
00647       break;
00648 
00649     rv = NS_OK;
00650   }
00651 
00652   return rv;
00653 }
00654 
00655 static nsresult
00656 EnumValidate(nsICommandLineValidator* aValidator, nsICommandLine* aThis, void*)
00657 {
00658   return aValidator->Validate(aThis);
00659 }  
00660 
00661 static nsresult
00662 EnumRun(nsICommandLineHandler* aHandler, nsICommandLine* aThis, void*)
00663 {
00664   return aHandler->Handle(aThis);
00665 }  
00666 
00667 NS_IMETHODIMP
00668 nsCommandLine::Run()
00669 {
00670   nsresult rv;
00671 
00672   rv = EnumerateValidators(EnumValidate, nsnull);
00673   if (rv == NS_ERROR_ABORT)
00674     return rv;
00675 
00676   rv = EnumerateHandlers(EnumRun, nsnull);
00677   if (rv == NS_ERROR_ABORT)
00678     return rv;
00679 
00680   return NS_OK;
00681 }
00682 
00683 static nsresult
00684 EnumHelp(nsICommandLineHandler* aHandler, nsICommandLine* aThis, void* aClosure)
00685 {
00686   nsresult rv;
00687 
00688   nsCString text;
00689   rv = aHandler->GetHelpInfo(text);
00690   if (NS_SUCCEEDED(rv)) {
00691     NS_ASSERTION(text.Length() == 0 || text.Last() == '\n',
00692                  "Help text from command line handlers should end in a newline.");
00693 
00694     nsACString* totalText = NS_REINTERPRET_CAST(nsACString*, aClosure);
00695     totalText->Append(text);
00696   }
00697 
00698   return NS_OK;
00699 }  
00700 
00701 NS_IMETHODIMP
00702 nsCommandLine::GetHelpText(nsACString& aResult)
00703 {
00704   EnumerateHandlers(EnumHelp, &aResult);
00705 
00706   return NS_OK;
00707 }
00708 
00709 NS_GENERIC_FACTORY_CONSTRUCTOR(nsCommandLine)
00710 
00711 static const nsModuleComponentInfo components[] =
00712 {
00713   { "nsCommandLine",
00714     { 0x23bcc750, 0xdc20, 0x460b, { 0xb2, 0xd4, 0x74, 0xd8, 0xf5, 0x8d, 0x36, 0x15 } },
00715     "@mozilla.org/toolkit/command-line;1",
00716     nsCommandLineConstructor
00717   }
00718 };
00719 
00720 NS_IMPL_NSGETMODULE(CommandLineModule, components)