intl/locale/src/unix/nsDateTimeFormatUnix.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/locale/src/unix/nsDateTimeFormatUnix.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,286 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include <locale.h>
    1.10 +#include "plstr.h"
    1.11 +#include "nsIServiceManager.h"
    1.12 +#include "nsDateTimeFormatUnix.h"
    1.13 +#include "nsIComponentManager.h"
    1.14 +#include "nsILocaleService.h"
    1.15 +#include "nsIPlatformCharset.h"
    1.16 +#include "nsPosixLocale.h"
    1.17 +#include "nsCRT.h"
    1.18 +#include "nsReadableUtils.h"
    1.19 +#include "nsUnicharUtils.h"
    1.20 +
    1.21 +NS_IMPL_ISUPPORTS(nsDateTimeFormatUnix, nsIDateTimeFormat)
    1.22 +
    1.23 +// init this interface to a specified locale
    1.24 +nsresult nsDateTimeFormatUnix::Initialize(nsILocale* locale)
    1.25 +{
    1.26 +  nsAutoString localeStr;
    1.27 +  NS_NAMED_LITERAL_STRING(aCategory, "NSILOCALE_TIME##PLATFORM");
    1.28 +  nsresult res = NS_OK;
    1.29 +
    1.30 +  // use cached info if match with stored locale
    1.31 +  if (!locale) {
    1.32 +    if (!mLocale.IsEmpty() &&
    1.33 +        mLocale.Equals(mAppLocale, nsCaseInsensitiveStringComparator())) {
    1.34 +      return NS_OK;
    1.35 +    }
    1.36 +  }
    1.37 +  else {
    1.38 +    res = locale->GetCategory(aCategory, localeStr);
    1.39 +    if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
    1.40 +      if (!mLocale.IsEmpty() &&
    1.41 +          mLocale.Equals(localeStr,
    1.42 +                         nsCaseInsensitiveStringComparator())) {
    1.43 +        return NS_OK;
    1.44 +      }
    1.45 +    }
    1.46 +  }
    1.47 +
    1.48 +  mCharset.AssignLiteral("ISO-8859-1");
    1.49 +  mPlatformLocale.Assign("en_US");
    1.50 +
    1.51 +  // get locale name string, use app default if no locale specified
    1.52 +  if (!locale) {
    1.53 +    nsCOMPtr<nsILocaleService> localeService = 
    1.54 +             do_GetService(NS_LOCALESERVICE_CONTRACTID, &res);
    1.55 +    if (NS_SUCCEEDED(res)) {
    1.56 +      nsCOMPtr<nsILocale> appLocale;
    1.57 +      res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
    1.58 +      if (NS_SUCCEEDED(res)) {
    1.59 +        res = appLocale->GetCategory(aCategory, localeStr);
    1.60 +        if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
    1.61 +          NS_ASSERTION(NS_SUCCEEDED(res), "failed to get app locale info");
    1.62 +          mAppLocale = localeStr; // cache app locale name
    1.63 +        }
    1.64 +      }
    1.65 +    }
    1.66 +  }
    1.67 +  else {
    1.68 +    res = locale->GetCategory(aCategory, localeStr);
    1.69 +    NS_ASSERTION(NS_SUCCEEDED(res), "failed to get locale info");
    1.70 +  }
    1.71 +
    1.72 +  if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
    1.73 +    mLocale = localeStr; // cache locale name
    1.74 +
    1.75 +    nsPosixLocale::GetPlatformLocale(mLocale, mPlatformLocale);
    1.76 +
    1.77 +    nsCOMPtr <nsIPlatformCharset> platformCharset = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &res);
    1.78 +    if (NS_SUCCEEDED(res)) {
    1.79 +      nsAutoCString mappedCharset;
    1.80 +      res = platformCharset->GetDefaultCharsetForLocale(mLocale, mappedCharset);
    1.81 +      if (NS_SUCCEEDED(res)) {
    1.82 +        mCharset = mappedCharset;
    1.83 +      }
    1.84 +    }
    1.85 +  }
    1.86 +
    1.87 +  // Initialize unicode decoder
    1.88 +  nsCOMPtr <nsICharsetConverterManager>  charsetConverterManager;
    1.89 +  charsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &res);
    1.90 +  if (NS_SUCCEEDED(res)) {
    1.91 +    res = charsetConverterManager->GetUnicodeDecoder(mCharset.get(), getter_AddRefs(mDecoder));
    1.92 +  }
    1.93 +
    1.94 +  LocalePreferred24hour();
    1.95 +
    1.96 +  return res;
    1.97 +}
    1.98 +
    1.99 +void nsDateTimeFormatUnix::LocalePreferred24hour()
   1.100 +{
   1.101 +  char str[100];
   1.102 +  time_t tt;
   1.103 +  struct tm *tmc;
   1.104 +  int i;
   1.105 +
   1.106 +  tt = time(nullptr);
   1.107 +  tmc = localtime(&tt);
   1.108 +
   1.109 +  tmc->tm_hour=22;    // put the test sample hour to 22:00 which is 10PM
   1.110 +  tmc->tm_min=0;      // set the min & sec other number than '2'
   1.111 +  tmc->tm_sec=0;
   1.112 +
   1.113 +  char *temp = setlocale(LC_TIME, mPlatformLocale.get());
   1.114 +  strftime(str, (size_t)99, "%X", (struct tm *)tmc);
   1.115 +
   1.116 +  (void) setlocale(LC_TIME, temp);
   1.117 +
   1.118 +  mLocalePreferred24hour = false;
   1.119 +  for (i=0; str[i]; i++) {
   1.120 +    if (str[i] == '2') {    // if there is any '2', that locale use 0-23 time format
   1.121 +        mLocalePreferred24hour = true;
   1.122 +        break;
   1.123 +    }
   1.124 +  }
   1.125 +
   1.126 +  mLocaleAMPMfirst = true;
   1.127 +  if (mLocalePreferred24hour == false) {
   1.128 +    if (str[0] && str[0] == '1') { // if the first character is '1' of 10:00,
   1.129 +			           // AMPM string is located after 10:00
   1.130 +      mLocaleAMPMfirst = false;
   1.131 +    }
   1.132 +  }
   1.133 +}
   1.134 +
   1.135 +nsresult nsDateTimeFormatUnix::FormatTime(nsILocale* locale, 
   1.136 +                                      const nsDateFormatSelector  dateFormatSelector, 
   1.137 +                                      const nsTimeFormatSelector timeFormatSelector, 
   1.138 +                                      const time_t  timetTime, 
   1.139 +                                      nsAString& stringOut) 
   1.140 +{
   1.141 +  struct tm tmTime;
   1.142 +  memcpy(&tmTime, localtime(&timetTime), sizeof(struct tm));
   1.143 +  return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, &tmTime, stringOut);
   1.144 +}
   1.145 +
   1.146 +// performs a locale sensitive date formatting operation on the struct tm parameter
   1.147 +nsresult nsDateTimeFormatUnix::FormatTMTime(nsILocale* locale, 
   1.148 +                                        const nsDateFormatSelector  dateFormatSelector, 
   1.149 +                                        const nsTimeFormatSelector timeFormatSelector, 
   1.150 +                                        const struct tm*  tmTime, 
   1.151 +                                        nsAString& stringOut) 
   1.152 +{
   1.153 +#define NSDATETIME_FORMAT_BUFFER_LEN  80
   1.154 +  char strOut[NSDATETIME_FORMAT_BUFFER_LEN*2];  // buffer for date and time
   1.155 +  char fmtD[NSDATETIME_FORMAT_BUFFER_LEN], fmtT[NSDATETIME_FORMAT_BUFFER_LEN];
   1.156 +  nsresult rv;
   1.157 +
   1.158 +  
   1.159 +  // set up locale data
   1.160 +  (void) Initialize(locale);
   1.161 +  NS_ENSURE_TRUE(mDecoder, NS_ERROR_NOT_INITIALIZED);
   1.162 +
   1.163 +  // set date format
   1.164 +  if (dateFormatSelector == kDateFormatLong && timeFormatSelector == kTimeFormatSeconds) {
   1.165 +    PL_strncpy(fmtD, "%c", NSDATETIME_FORMAT_BUFFER_LEN);
   1.166 +    PL_strncpy(fmtT, "", NSDATETIME_FORMAT_BUFFER_LEN); 
   1.167 +  } else {
   1.168 +
   1.169 +    switch (dateFormatSelector) {
   1.170 +      case kDateFormatNone:
   1.171 +        PL_strncpy(fmtD, "", NSDATETIME_FORMAT_BUFFER_LEN);
   1.172 +        break; 
   1.173 +      case kDateFormatLong:
   1.174 +      case kDateFormatShort:
   1.175 +        PL_strncpy(fmtD, "%x", NSDATETIME_FORMAT_BUFFER_LEN);
   1.176 +        break; 
   1.177 +      case kDateFormatYearMonth:
   1.178 +        PL_strncpy(fmtD, "%Y/%m", NSDATETIME_FORMAT_BUFFER_LEN);
   1.179 +        break; 
   1.180 +      case kDateFormatWeekday:
   1.181 +        PL_strncpy(fmtD, "%a", NSDATETIME_FORMAT_BUFFER_LEN);
   1.182 +        break;
   1.183 +      default:
   1.184 +        PL_strncpy(fmtD, "", NSDATETIME_FORMAT_BUFFER_LEN); 
   1.185 +    }
   1.186 +
   1.187 +    // set time format
   1.188 +    switch (timeFormatSelector) {
   1.189 +      case kTimeFormatNone:
   1.190 +        PL_strncpy(fmtT, "", NSDATETIME_FORMAT_BUFFER_LEN); 
   1.191 +        break;
   1.192 +      case kTimeFormatSeconds:
   1.193 +        PL_strncpy(fmtT, "%X", NSDATETIME_FORMAT_BUFFER_LEN);
   1.194 +        break;
   1.195 +      case kTimeFormatNoSeconds:
   1.196 +        PL_strncpy(fmtT, 
   1.197 +                   mLocalePreferred24hour ? "%H:%M" : mLocaleAMPMfirst ? "%p %I:%M" : "%I:%M %p", 
   1.198 +                   NSDATETIME_FORMAT_BUFFER_LEN);
   1.199 +        break;
   1.200 +      case kTimeFormatSecondsForce24Hour:
   1.201 +        PL_strncpy(fmtT, "%H:%M:%S", NSDATETIME_FORMAT_BUFFER_LEN);
   1.202 +        break;
   1.203 +      case kTimeFormatNoSecondsForce24Hour:
   1.204 +        PL_strncpy(fmtT, "%H:%M", NSDATETIME_FORMAT_BUFFER_LEN);
   1.205 +        break;
   1.206 +      default:
   1.207 +        PL_strncpy(fmtT, "", NSDATETIME_FORMAT_BUFFER_LEN); 
   1.208 +    }
   1.209 +  }
   1.210 +
   1.211 +  // generate data/time string
   1.212 +  char *old_locale = setlocale(LC_TIME, nullptr);
   1.213 +  (void) setlocale(LC_TIME, mPlatformLocale.get());
   1.214 +  if (strlen(fmtD) && strlen(fmtT)) {
   1.215 +    PL_strncat(fmtD, " ", NSDATETIME_FORMAT_BUFFER_LEN);
   1.216 +    PL_strncat(fmtD, fmtT, NSDATETIME_FORMAT_BUFFER_LEN);
   1.217 +    strftime(strOut, NSDATETIME_FORMAT_BUFFER_LEN, fmtD, tmTime);
   1.218 +  }
   1.219 +  else if (strlen(fmtD) && !strlen(fmtT)) {
   1.220 +    strftime(strOut, NSDATETIME_FORMAT_BUFFER_LEN, fmtD, tmTime);
   1.221 +  }
   1.222 +  else if (!strlen(fmtD) && strlen(fmtT)) {
   1.223 +    strftime(strOut, NSDATETIME_FORMAT_BUFFER_LEN, fmtT, tmTime);
   1.224 +  }
   1.225 +  else {
   1.226 +    PL_strncpy(strOut, "", NSDATETIME_FORMAT_BUFFER_LEN);
   1.227 +  }
   1.228 +  (void) setlocale(LC_TIME, old_locale);
   1.229 +
   1.230 +  // convert result to unicode
   1.231 +  int32_t srcLength = (int32_t) strlen(strOut);
   1.232 +  int32_t unicharLength = NSDATETIME_FORMAT_BUFFER_LEN*2;
   1.233 +  char16_t unichars[NSDATETIME_FORMAT_BUFFER_LEN*2];   // buffer for date and time
   1.234 +
   1.235 +  rv = mDecoder->Convert(strOut, &srcLength, unichars, &unicharLength);
   1.236 +  if (NS_FAILED(rv))
   1.237 +    return rv;
   1.238 +  stringOut.Assign(unichars, unicharLength);
   1.239 +
   1.240 +  return rv;
   1.241 +}
   1.242 +
   1.243 +// performs a locale sensitive date formatting operation on the PRTime parameter
   1.244 +nsresult nsDateTimeFormatUnix::FormatPRTime(nsILocale* locale, 
   1.245 +                                           const nsDateFormatSelector  dateFormatSelector, 
   1.246 +                                           const nsTimeFormatSelector timeFormatSelector, 
   1.247 +                                           const PRTime  prTime, 
   1.248 +                                           nsAString& stringOut)
   1.249 +{
   1.250 +  PRExplodedTime explodedTime;
   1.251 +  PR_ExplodeTime(prTime, PR_LocalTimeParameters, &explodedTime);
   1.252 +
   1.253 +  return FormatPRExplodedTime(locale, dateFormatSelector, timeFormatSelector, &explodedTime, stringOut);
   1.254 +}
   1.255 +
   1.256 +// performs a locale sensitive date formatting operation on the PRExplodedTime parameter
   1.257 +nsresult nsDateTimeFormatUnix::FormatPRExplodedTime(nsILocale* locale, 
   1.258 +                                                   const nsDateFormatSelector  dateFormatSelector, 
   1.259 +                                                   const nsTimeFormatSelector timeFormatSelector, 
   1.260 +                                                   const PRExplodedTime*  explodedTime, 
   1.261 +                                                   nsAString& stringOut)
   1.262 +{
   1.263 +  struct tm  tmTime;
   1.264 +  /* be safe and set all members of struct tm to zero
   1.265 +   *
   1.266 +   * there are other fields in the tm struct that we aren't setting
   1.267 +   * (tm_isdst, tm_gmtoff, tm_zone, should we set these?) and since
   1.268 +   * tmTime is on the stack, it may be filled with garbage, but
   1.269 +   * the garbage may vary.  (this may explain why some saw bug #10412, and
   1.270 +   * others did not.
   1.271 +   *
   1.272 +   * when tmTime is passed to strftime() with garbage bad things may happen. 
   1.273 +   * see bug #10412
   1.274 +   */
   1.275 +  memset( &tmTime, 0, sizeof(tmTime) );
   1.276 +
   1.277 +  tmTime.tm_yday = explodedTime->tm_yday;
   1.278 +  tmTime.tm_wday = explodedTime->tm_wday;
   1.279 +  tmTime.tm_year = explodedTime->tm_year;
   1.280 +  tmTime.tm_year -= 1900;
   1.281 +  tmTime.tm_mon = explodedTime->tm_month;
   1.282 +  tmTime.tm_mday = explodedTime->tm_mday;
   1.283 +  tmTime.tm_hour = explodedTime->tm_hour;
   1.284 +  tmTime.tm_min = explodedTime->tm_min;
   1.285 +  tmTime.tm_sec = explodedTime->tm_sec;
   1.286 +
   1.287 +  return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, &tmTime, stringOut);
   1.288 +}
   1.289 +

mercurial