intl/locale/src/nsLocaleService.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifdef MOZ_WIDGET_QT
     7 #include <QString>
     8 #include <QtCore/QLocale>
     9 #endif
    11 #include "nsCOMPtr.h"
    12 #include "nsAutoPtr.h"
    13 #include "nsILocale.h"
    14 #include "nsILocaleService.h"
    15 #include "nsLocale.h"
    16 #include "nsCRT.h"
    17 #include "prprf.h"
    18 #include "nsTArray.h"
    19 #include "nsString.h"
    21 #include <ctype.h>
    23 #if defined(XP_WIN)
    24 #  include "nsWin32Locale.h"
    25 #elif defined(XP_MACOSX)
    26 #  include <Carbon/Carbon.h>
    27 #elif defined(XP_UNIX)
    28 #  include <locale.h>
    29 #  include <stdlib.h>
    30 #  include "nsPosixLocale.h"
    31 #endif
    33 //
    34 // implementation constants
    35 const int LocaleListLength = 6;
    36 const char* LocaleList[LocaleListLength] = 
    37 {
    38 	NSILOCALE_COLLATE,
    39 	NSILOCALE_CTYPE,
    40 	NSILOCALE_MONETARY,
    41 	NSILOCALE_NUMERIC,
    42 	NSILOCALE_TIME,
    43 	NSILOCALE_MESSAGE
    44 };
    46 #define NSILOCALE_MAX_ACCEPT_LANGUAGE	16
    47 #define NSILOCALE_MAX_ACCEPT_LENGTH		18
    49 #if (defined(XP_UNIX) && !defined(XP_MACOSX))
    50 static int posix_locale_category[LocaleListLength] =
    51 {
    52   LC_COLLATE,
    53   LC_CTYPE,
    54   LC_MONETARY,
    55   LC_NUMERIC,
    56   LC_TIME,
    57 #ifdef HAVE_I18N_LC_MESSAGES
    58   LC_MESSAGES
    59 #else
    60   LC_CTYPE
    61 #endif
    62 };
    63 #endif
    65 //
    66 // nsILocaleService implementation
    67 //
    68 class nsLocaleService: public nsILocaleService {
    70 public:
    72 	//
    73 	// nsISupports
    74 	//
    75 	NS_DECL_THREADSAFE_ISUPPORTS
    77 	//
    78 	// nsILocaleService
    79 	//
    80     NS_DECL_NSILOCALESERVICE
    83 	nsLocaleService(void);
    84 	virtual ~nsLocaleService(void);
    86 protected:
    88 	nsresult SetSystemLocale(void);
    89 	nsresult SetApplicationLocale(void);
    91 	nsCOMPtr<nsILocale>				mSystemLocale;
    92 	nsCOMPtr<nsILocale>				mApplicationLocale;
    94 };
    96 //
    97 // nsLocaleService methods
    98 //
    99 nsLocaleService::nsLocaleService(void) 
   100 {
   101 #ifdef XP_WIN
   102     nsAutoString        xpLocale;
   103     //
   104     // get the system LCID
   105     //
   106     LCID win_lcid = GetSystemDefaultLCID();
   107     NS_ENSURE_TRUE_VOID(win_lcid);
   108     nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
   109     nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
   110     NS_ENSURE_SUCCESS_VOID(rv);
   112     //
   113     // get the application LCID
   114     //
   115     win_lcid = GetUserDefaultLCID();
   116     NS_ENSURE_TRUE_VOID(win_lcid);
   117     nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
   118     rv = NewLocale(xpLocale, getter_AddRefs(mApplicationLocale));
   119     NS_ENSURE_SUCCESS_VOID(rv);
   120 #endif
   121 #if defined(XP_UNIX) && !defined(XP_MACOSX)
   122     nsRefPtr<nsLocale> resultLocale(new nsLocale());
   123     NS_ENSURE_TRUE_VOID(resultLocale);
   125 #ifdef MOZ_WIDGET_QT
   126     const char* lang = QLocale::system().name().toUtf8();
   127 #else
   128     // Get system configuration
   129     const char* lang = getenv("LANG");
   130 #endif
   132     nsAutoString xpLocale, platformLocale;
   133     nsAutoString category, category_platform;
   134     int i;
   136     for( i = 0; i < LocaleListLength; i++ ) {
   137         nsresult result;
   138         // setlocale( , "") evaluates LC_* and LANG
   139         char* lc_temp = setlocale(posix_locale_category[i], "");
   140         CopyASCIItoUTF16(LocaleList[i], category);
   141         category_platform = category;
   142         category_platform.AppendLiteral("##PLATFORM");
   143         if (lc_temp != nullptr) {
   144             result = nsPosixLocale::GetXPLocale(lc_temp, xpLocale);
   145             CopyASCIItoUTF16(lc_temp, platformLocale);
   146         } else {
   147             if ( lang == nullptr ) {
   148                 platformLocale.AssignLiteral("en_US");
   149                 result = nsPosixLocale::GetXPLocale("en-US", xpLocale);
   150             } else {
   151                 CopyASCIItoUTF16(lang, platformLocale);
   152                 result = nsPosixLocale::GetXPLocale(lang, xpLocale);
   153             }
   154         }
   155         if (NS_FAILED(result)) {
   156             return;
   157         }
   158         resultLocale->AddCategory(category, xpLocale);
   159         resultLocale->AddCategory(category_platform, platformLocale);
   160     }
   161     mSystemLocale = do_QueryInterface(resultLocale);
   162     mApplicationLocale = do_QueryInterface(resultLocale);
   164 #endif // XP_UNIX
   166 #ifdef XP_MACOSX
   167     // Get string representation of user's current locale
   168     CFLocaleRef userLocaleRef = ::CFLocaleCopyCurrent();
   169     CFStringRef userLocaleStr = ::CFLocaleGetIdentifier(userLocaleRef);
   170     ::CFRetain(userLocaleStr);
   172     nsAutoTArray<UniChar, 32> buffer;
   173     int size = ::CFStringGetLength(userLocaleStr);
   174     buffer.SetLength(size + 1);
   175     CFRange range = ::CFRangeMake(0, size);
   176     ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements());
   177     buffer[size] = 0;
   179     // Convert the locale string to the format that Mozilla expects
   180     nsAutoString xpLocale(reinterpret_cast<char16_t*>(buffer.Elements()));
   181     xpLocale.ReplaceChar('_', '-');
   183     nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
   184     if (NS_SUCCEEDED(rv)) {
   185         mApplicationLocale = mSystemLocale;
   186     }
   188     ::CFRelease(userLocaleStr);
   189     ::CFRelease(userLocaleRef);
   191     NS_ASSERTION(mApplicationLocale, "Failed to create locale objects");
   192 #endif // XP_MACOSX
   193 }
   195 nsLocaleService::~nsLocaleService(void)
   196 {
   197 }
   199 NS_IMPL_ISUPPORTS(nsLocaleService, nsILocaleService)
   201 NS_IMETHODIMP
   202 nsLocaleService::NewLocale(const nsAString &aLocale, nsILocale **_retval)
   203 {
   204     nsresult result;
   206     *_retval = nullptr;
   208     nsRefPtr<nsLocale> resultLocale(new nsLocale());
   209     if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY;
   211     for (int32_t i = 0; i < LocaleListLength; i++) {
   212       NS_ConvertASCIItoUTF16 category(LocaleList[i]);
   213       result = resultLocale->AddCategory(category, aLocale);
   214       if (NS_FAILED(result)) return result;
   215 #if defined(XP_UNIX) && !defined(XP_MACOSX)
   216       category.AppendLiteral("##PLATFORM");
   217       result = resultLocale->AddCategory(category, aLocale);
   218       if (NS_FAILED(result)) return result;
   219 #endif
   220     }
   222     NS_ADDREF(*_retval = resultLocale);
   223     return NS_OK;
   224 }
   227 NS_IMETHODIMP
   228 nsLocaleService::GetSystemLocale(nsILocale **_retval)
   229 {
   230 	if (mSystemLocale) {
   231 		NS_ADDREF(*_retval = mSystemLocale);
   232 		return NS_OK;
   233 	}
   235 	*_retval = (nsILocale*)nullptr;
   236 	return NS_ERROR_FAILURE;
   237 }
   239 NS_IMETHODIMP
   240 nsLocaleService::GetApplicationLocale(nsILocale **_retval)
   241 {
   242 	if (mApplicationLocale) {
   243 		NS_ADDREF(*_retval = mApplicationLocale);
   244 		return NS_OK;
   245 	}
   247 	*_retval=(nsILocale*)nullptr;
   248 	return NS_ERROR_FAILURE;
   249 }
   251 NS_IMETHODIMP
   252 nsLocaleService::GetLocaleFromAcceptLanguage(const char *acceptLanguage, nsILocale **_retval)
   253 {
   254   char* cPtr;
   255   char* cPtr1;
   256   char* cPtr2;
   257   int i;
   258   int j;
   259   int countLang = 0;
   260   char	acceptLanguageList[NSILOCALE_MAX_ACCEPT_LANGUAGE][NSILOCALE_MAX_ACCEPT_LENGTH];
   261   nsresult	result;
   263   nsAutoArrayPtr<char> input(new char[strlen(acceptLanguage)+1]);
   265   strcpy(input, acceptLanguage);
   266   cPtr1 = input-1;
   267   cPtr2 = input;
   269   /* put in standard form */
   270   while (*(++cPtr1)) {
   271     if      (isalpha(*cPtr1))  *cPtr2++ = tolower(*cPtr1); /* force lower case */
   272     else if (isspace(*cPtr1))  ;                           /* ignore any space */
   273     else if (*cPtr1=='-')      *cPtr2++ = '_';             /* "-" -> "_"       */
   274     else if (*cPtr1=='*')      ;                           /* ignore "*"       */
   275     else                       *cPtr2++ = *cPtr1;          /* else unchanged   */
   276   }
   277   *cPtr2 = '\0';
   279   countLang = 0;
   281   if (strchr(input,';')) {
   282     /* deal with the quality values */
   284     float qvalue[NSILOCALE_MAX_ACCEPT_LANGUAGE];
   285     float qSwap;
   286     float bias = 0.0f;
   287     char* ptrLanguage[NSILOCALE_MAX_ACCEPT_LANGUAGE];
   288     char* ptrSwap;
   290     cPtr = nsCRT::strtok(input,",",&cPtr2);
   291     while (cPtr) {
   292       qvalue[countLang] = 1.0f;
   293       /* add extra parens to get rid of warning */
   294       if ((cPtr1 = strchr(cPtr,';')) != nullptr) {
   295         PR_sscanf(cPtr1,";q=%f",&qvalue[countLang]);
   296         *cPtr1 = '\0';
   297       }
   298       if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LANGUAGE) {     /* ignore if too long */
   299         qvalue[countLang] -= (bias += 0.0001f); /* to insure original order */
   300         ptrLanguage[countLang++] = cPtr;
   301         if (countLang>=NSILOCALE_MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
   302       }
   303       cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
   304     }
   306     /* sort according to decending qvalue */
   307     /* not a very good algorithm, but count is not likely large */
   308     for ( i=0 ; i<countLang-1 ; i++ ) {
   309       for ( j=i+1 ; j<countLang ; j++ ) {
   310         if (qvalue[i]<qvalue[j]) {
   311           qSwap     = qvalue[i];
   312           qvalue[i] = qvalue[j];
   313           qvalue[j] = qSwap;
   314           ptrSwap        = ptrLanguage[i];
   315           ptrLanguage[i] = ptrLanguage[j];
   316           ptrLanguage[j] = ptrSwap;
   317         }
   318       }
   319     }
   320     for ( i=0 ; i<countLang ; i++ ) {
   321       PL_strncpyz(acceptLanguageList[i],ptrLanguage[i],NSILOCALE_MAX_ACCEPT_LENGTH);
   322     }
   324   } else {
   325     /* simple case: no quality values */
   327     cPtr = nsCRT::strtok(input,",",&cPtr2);
   328     while (cPtr) {
   329       if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LENGTH) {        /* ignore if too long */
   330         PL_strncpyz(acceptLanguageList[countLang++],cPtr,NSILOCALE_MAX_ACCEPT_LENGTH);
   331         if (countLang>=NSILOCALE_MAX_ACCEPT_LENGTH) break; /* quit if too many */
   332       }
   333       cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
   334     }
   335   }
   337   //
   338   // now create the locale 
   339   //
   340   result = NS_ERROR_FAILURE;
   341   if (countLang>0) {
   342 	  result = NewLocale(NS_ConvertASCIItoUTF16(acceptLanguageList[0]), _retval);
   343   }
   345   //
   346   // clean up
   347   //
   348   return result;
   349 }
   352 nsresult
   353 nsLocaleService::GetLocaleComponentForUserAgent(nsAString& retval)
   354 {
   355     nsCOMPtr<nsILocale>     system_locale;
   356     nsresult                result;
   358     result = GetSystemLocale(getter_AddRefs(system_locale));
   359     if (NS_SUCCEEDED(result))
   360     {
   361         result = system_locale->
   362                  GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), retval);
   363         return result;
   364     }
   366     return result;
   367 }
   371 nsresult
   372 NS_NewLocaleService(nsILocaleService** result)
   373 {
   374   if(!result)
   375     return NS_ERROR_NULL_POINTER;
   376   *result = new nsLocaleService();
   377   if (! *result)
   378     return NS_ERROR_OUT_OF_MEMORY;
   379   NS_ADDREF(*result);
   380   return NS_OK;
   381 }

mercurial