Back to index

lightning-sunbird  0.9+nobinonly
nsCommandLineService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
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 of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or 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 
00039 #include "nsICmdLineService.h"
00040 #include "nsCommandLineService.h"
00041 #include "nsIComponentManager.h"
00042 #include "nsILocalFile.h"
00043 #include "nsString.h"
00044 #include "plstr.h"
00045 #include "nsCRT.h"
00046 #include "nsNetUtil.h"
00047 #ifdef XP_MACOSX
00048 #include "nsCommandLineServiceMac.h"
00049 #endif
00050 
00051 nsCmdLineService::nsCmdLineService()
00052        :  mArgCount(0), mArgc(0), mArgv(0)
00053 {
00054 }
00055 
00056 /*
00057  * Implement the nsISupports methods...
00058  */
00059 NS_IMPL_ISUPPORTS1(nsCmdLineService, nsICmdLineService)
00060 
00061 static void* ProcessURLArg(char* str)
00062 {
00063   // Problem: since the arg parsing code doesn't know which flags
00064   // take arguments, it always calls this method for the last
00065   // non-flag argument. But sometimes that argument is actually
00066   // the arg for the last switch, e.g. -width 500 or -Profile default.
00067   // nsLocalFile will only work on absolute pathnames, so return
00068   // if str doesn't start with '/' or '\'.
00069   if (str && (*str == '\\' || *str == '/'))
00070   {
00071     nsCOMPtr<nsIURI> uri;
00072     nsresult rv = NS_NewURI(getter_AddRefs(uri), str);
00073     if (NS_FAILED(rv))
00074     {
00075       nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
00076       if (file)
00077       {
00078         rv = file->InitWithNativePath(nsDependentCString(str));
00079         if (NS_SUCCEEDED(rv))
00080         {
00081           nsCAutoString fileurl;
00082           rv = NS_GetURLSpecFromFile(file, fileurl);
00083           if (NS_SUCCEEDED(rv))
00084             return NS_REINTERPRET_CAST(void*, ToNewCString(fileurl));
00085         }
00086       }
00087     }
00088   }
00089 
00090   return NS_REINTERPRET_CAST(void*, nsCRT::strdup(str));
00091 }
00092 
00093 NS_IMETHODIMP
00094 nsCmdLineService::Initialize(int aArgc, char ** aArgv)
00095 {
00096 
00097 
00098   PRInt32   i=0;
00099   nsresult  rv = nsnull;
00100 
00101 #ifdef XP_MACOSX
00102   rv = InitializeMacCommandLine(aArgc, aArgv);
00103   NS_ASSERTION(NS_SUCCEEDED(rv), "Initializing AppleEvents failed");
00104 #endif
00105 
00106   // Save aArgc and argv
00107   mArgc = aArgc;
00108   mArgv = new char*[ aArgc ];
00109   for(i=0; i<aArgc; i++) {
00110     mArgv[i] = nsCRT::strdup( aArgv[i] ? aArgv[i] : "" );
00111   }
00112   //Insert the program name 
00113   if (aArgc > 0 && aArgv[0])
00114   {
00115     mArgList.AppendElement(NS_REINTERPRET_CAST(void*, nsCRT::strdup("-progname")));
00116     mArgValueList.AppendElement(NS_REINTERPRET_CAST(void*, nsCRT::strdup(aArgv[0])));
00117     mArgCount++;
00118     i++;
00119   }
00120 
00121   for(i=1; i<aArgc; i++) {
00122 
00123     if ((aArgv[i][0] == '-')
00124 #if defined(XP_WIN) || defined(XP_OS2)
00125         || (aArgv[i][0] == '/')
00126 #endif
00127       ) {
00128        /* An option that starts with -. May or may not
00129            * have a value after it. 
00130            */
00131           mArgList.AppendElement(NS_REINTERPRET_CAST(void*, nsCRT::strdup(aArgv[i])));
00132           //Increment the index to look ahead at the next option.
00133        i++;
00134 
00135 
00136      //Look ahead if this option has a value like -w 60
00137 
00138           if (i == aArgc) {
00139             /* All args have been parsed. Append a PR_TRUE for the
00140              * previous option in the mArgValueList
00141              */
00142             mArgValueList.AppendElement(NS_REINTERPRET_CAST(void*, nsCRT::strdup("1")));
00143             mArgCount++;
00144             break;
00145           }
00146      if ((aArgv[i][0] == '-')
00147 #if defined(XP_WIN) || defined(XP_OS2)
00148          || (aArgv[i][0] == '/')
00149 #endif
00150        ) {
00151         /* An other option. The previous one didn't have a value.
00152          * So, store the previous one's value as PR_TRUE in the
00153             * mArgValue array and retract the index so that this option 
00154             * will get stored in the next iteration
00155             */
00156         mArgValueList.AppendElement(NS_REINTERPRET_CAST(void*, nsCRT::strdup("1")));
00157            mArgCount++;
00158         i--;
00159         continue;
00160            }
00161       else {
00162         /* The next argument does not start with '-'. This 
00163             * could be value to the previous option 
00164             */
00165              if (i == (aArgc-1)) {
00166               /* This is the last argument and a URL 
00167             * Append a PR_TRUE for the previous option in the value array
00168             */
00169            //mArgValueList.AppendElement((void *)PL_strdup("1"));
00170                 //mArgCount++;
00171 
00172                      // Append the url to the arrays
00173            //mArgList.AppendElement((void *)PL_strdup("-url"));
00174                      mArgValueList.AppendElement(ProcessURLArg(aArgv[i]));
00175                      mArgCount++;
00176            continue;
00177         }
00178              else {
00179                 /* This is a value to the previous option.
00180                  * Store it in the mArgValue array 
00181                  */
00182              mArgValueList.AppendElement(NS_REINTERPRET_CAST(void*, nsCRT::strdup(aArgv[i])));
00183                 mArgCount++;
00184              }
00185           }
00186   }
00187   else {
00188        if (i == (aArgc-1)) {
00189              /* This must be the  URL at the end 
00190               * Append the url to the arrays
00191            */
00192            mArgList.AppendElement(NS_REINTERPRET_CAST(void*, nsCRT::strdup("-url")));
00193                 mArgValueList.AppendElement(ProcessURLArg(aArgv[i]));
00194                 mArgCount++;
00195             }
00196             else {
00197               /* A bunch of unrecognized arguments */
00198               rv = NS_ERROR_INVALID_ARG;
00199             }
00200   }
00201        
00202  }  // for
00203 
00204 #if 0
00205   for (i=0; i<mArgCount; i++)
00206   {
00207        printf("Argument: %s, ****** Value: %s\n", (char *)mArgList.ElementAt(i), (char *) mArgValueList.ElementAt(i));      
00208   }
00209 #endif /* 0 */
00210 
00211    return rv;
00212        
00213 }
00214 
00215 NS_IMETHODIMP
00216 nsCmdLineService::GetURLToLoad(char ** aResult)
00217 {
00218   nsresult rv = GetCmdLineValue("-url", aResult);
00219   if (NS_SUCCEEDED(rv) && *aResult && !strncmp(*aResult, "chrome:", 7)) {
00220     nsMemory::Free(*aResult);
00221     *aResult = nsnull;
00222     return NS_ERROR_INVALID_ARG;
00223   }
00224   return rv;
00225 }
00226 
00227 NS_IMETHODIMP
00228 nsCmdLineService::GetProgramName(char ** aResult)
00229 {
00230   *aResult = nsCRT::strdup((char *)mArgValueList.SafeElementAt(0));
00231   return NS_OK;
00232 }
00233 
00234 PRBool nsCmdLineService::ArgsMatch(const char *lookingFor, const char *userGave)
00235 {
00236     if (!lookingFor || !userGave) return PR_FALSE;
00237 
00238     if (!PL_strcasecmp(lookingFor,userGave)) return PR_TRUE;
00239 
00240 #if defined(XP_UNIX) || defined(XP_BEOS)
00241     /* on unix and beos, we'll allow --mail for -mail */
00242     if (lookingFor && userGave && (lookingFor[0] != '\0') && (userGave[0] != '\0') && (userGave[1] != '\0')) {
00243         if (!PL_strcasecmp(lookingFor+1,userGave+2) && (lookingFor[0] == '-') && (userGave[0] == '-') && (userGave[1] == '-')) return PR_TRUE;
00244     }
00245 #endif
00246 #if defined(XP_WIN) || defined(XP_OS2)
00247     /* on windows /mail is the same as -mail */
00248     if (lookingFor && userGave && (lookingFor[0] != '\0') && (userGave[0] != '\0')) {
00249         if (!PL_strcasecmp(lookingFor+1,userGave+1) && (lookingFor[0] == '-') && (userGave[0] == '/')) return PR_TRUE;
00250     }
00251 #endif 
00252     return PR_FALSE;
00253 }
00254 
00255 NS_IMETHODIMP
00256 nsCmdLineService::GetCmdLineValue(const char * aArg, char ** aResult)
00257 {
00258    nsresult  rv = NS_OK;
00259    
00260    if (nsnull == aArg || nsnull == aResult ) {
00261            return NS_ERROR_NULL_POINTER;
00262    }
00263 
00264    for (int i = 0; i<mArgCount; i++)
00265    {
00266      if (ArgsMatch(aArg,(char *) mArgList.ElementAt(i))) {
00267        *aResult = nsCRT::strdup((char *)mArgValueList.ElementAt(i));
00268         return NS_OK;
00269      }
00270    }
00271 
00272    *aResult = nsnull;
00273    return rv;
00274        
00275 }
00276 
00277 NS_IMETHODIMP
00278 nsCmdLineService::GetArgc(PRInt32 * aResult)
00279 {
00280 
00281     if (nsnull == aResult)
00282         return NS_ERROR_NULL_POINTER;
00283 
00284     // if we are null, we were never initialized.
00285     if (mArgc == 0)
00286       return NS_ERROR_FAILURE;
00287 
00288     *aResult =  mArgc;
00289     return NS_OK;
00290 }
00291 
00292 NS_IMETHODIMP
00293 nsCmdLineService::GetArgv(char *** aResult)
00294 {
00295     if (nsnull == aResult)
00296       return NS_ERROR_NULL_POINTER;
00297 
00298     // if we are 0, we were never set.
00299     if (!mArgv)
00300       return NS_ERROR_FAILURE;
00301 
00302     *aResult = mArgv;
00303 
00304     return NS_OK;
00305 }
00306 
00307 nsCmdLineService::~nsCmdLineService()
00308 {
00309   PRInt32 curr = mArgList.Count();
00310   while ( curr ) {
00311     char* str = NS_REINTERPRET_CAST(char*, mArgList[curr-1]);
00312     if ( str )
00313       nsMemory::Free(str);
00314     --curr;
00315   }
00316   
00317   curr = mArgValueList.Count();
00318   while ( curr ) {
00319     char* str = NS_REINTERPRET_CAST(char*, mArgValueList[curr-1]);
00320     if ( str )
00321       nsMemory::Free(str);
00322     --curr;
00323   }
00324 
00325   curr = mArgc;
00326   while ( curr ) {
00327     char *str = mArgv ? mArgv[curr-1] : 0;
00328     if ( str )
00329       nsMemory::Free( mArgv[curr-1] );
00330     --curr;
00331   }
00332   delete [] mArgv;
00333 }
00334 
00335 NS_IMETHODIMP
00336 nsCmdLineService::GetHandlerForParam(const char *aParam,
00337                                      nsICmdLineHandler** aResult)
00338 {
00339   nsresult rv;
00340 
00341   // allocate temp on the stack
00342   nsAutoVoidArray oneParameter;
00343 
00344   nsVoidArray *paramList;
00345   
00346   // if user passed in "null", then we want to go through each one
00347   if (!aParam)
00348     paramList = &mArgList;
00349   else {
00350     oneParameter.AppendElement((void *)aParam);
00351     paramList = &oneParameter;
00352   }
00353 
00354   PRUint32 i;
00355   for (i=0; i < (PRUint32)paramList->Count(); i++) {
00356     const char *param = (const char*)paramList->ElementAt(i);
00357     
00358     // skip past leading / and -
00359     if (*param == '-' || *param == '/') {
00360       ++param;
00361       if (*param == *(param-1)) // skip "--" or "//"
00362         ++param;
00363     }
00364     
00365     nsCAutoString
00366       contractID("@mozilla.org/commandlinehandler/general-startup;1?type=");
00367     
00368     contractID += param;
00369 
00370     nsCOMPtr<nsICmdLineHandler> handler =
00371       do_GetService(contractID.get(), &rv);
00372     if (NS_FAILED(rv)) continue;
00373 
00374     *aResult = handler;
00375     NS_ADDREF(*aResult);
00376     return NS_OK;
00377   }
00378 
00379   // went through all the parameters, didn't find one
00380   return NS_ERROR_FAILURE;
00381 }
00382 
00383 #if 0
00384 NS_IMETHODIMP
00385 nsCmdLineService::PrintCmdArgs()
00386 {
00387 
00388    if (mArgCount == 0) {
00389      printf("No command line options provided\n");
00390      return;
00391    }
00392    
00393    for (int i=0; i<mArgCount; i++)
00394    {
00395        printf("Argument: %s, ****** Value: %s\n", mArgList.ElementAt(i), mArgValueList.ElementAt(i));      
00396 
00397    }
00398 
00399   return NS_OK;
00400 
00401 }
00402 #endif
00403