/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ /* * locale.c * -------- * Implement FE functions to support xp_locale and other locale stuff */ #include <xplocale.h> #include "xfe.h" #include "felocale.h" #include "csid.h" int16 fe_LocaleCharSetID = CS_LATIN1; char fe_LocaleCharSetName[128] = { 0 }; int (*fe_collation_func)(const char *, const char *) = strcoll; void fe_InitCollation(void) { /* * Check to see if strcoll() is broken */ if ( ((strcoll("A", "B") < 0) && (strcoll("a", "B") >= 0)) || /* * Unlikely, but just in case... */ ((strcoll("A", "B") > 0) && (strcoll("a", "B") <= 0)) || (strcoll("A", "B") == 0) ) { /* * strcoll() is broken, so we use our own routine */ fe_collation_func = strcasecomp; } } int FE_StrColl(const char *s1, const char *s2) { return (*fe_collation_func)(s1, s2); } size_t FE_StrfTime(MWContext *context, char *result, size_t maxsize, int format, const struct tm *timeptr) { char *fmt; switch (format) { case XP_TIME_FORMAT: /* fmt = "%X"; */ fmt = "%H:%M"; break; case XP_WEEKDAY_TIME_FORMAT: /* fmt = "%a %X"; */ fmt = "%a %H:%M"; break; case XP_DATE_TIME_FORMAT: /* fmt = "%x %X"; */ fmt = "%x %H:%M"; break; case XP_LONG_DATE_TIME_FORMAT: fmt = "%c"; break; default: fmt = "%c"; break; } return strftime(result, maxsize, fmt, timeptr); } char * fe_GetNormalizedLocaleName(void) { #ifdef _HPUX_SOURCE int len; char *locale; locale = setlocale(LC_CTYPE, NULL); if (locale && *locale) { len = strlen(locale); } else { locale = "C"; len = 1; } if ( (!strncmp(locale, "/\x03:", 3)) && (!strcmp(&locale[len - 2], ";/")) ) { locale += 3; len -= 5; } locale = strdup(locale); if (locale) { locale[len] = 0; } return locale; #else char *locale; locale = setlocale(LC_CTYPE, NULL); if (locale && *locale) { return strdup(locale); } return strdup("C"); #endif } unsigned char * fe_ConvertToLocaleEncoding(int16 charset, unsigned char *str) { CCCDataObject obj; unsigned char *le_string; /* Locally Encoded STRING */ if ((charset == fe_LocaleCharSetID) || (!str) || (!*str)) { return str; } if (IS_UTF8_CSID(charset)) { int32 le_len; uint16 *ucs2_chars; int32 num_ucs2_chars; /* * Convert utf8 to ucs2 */ ucs2_chars = INTL_UTF8ToUCS2(str, &num_ucs2_chars); /* * Convert ucs2 to local encoding */ le_len = INTL_UnicodeToStrLen(fe_LocaleCharSetID, ucs2_chars, num_ucs2_chars); le_string = (unsigned char *)XP_ALLOC(le_len+1); INTL_UnicodeToStr(fe_LocaleCharSetID, ucs2_chars, num_ucs2_chars, le_string, le_len); le_string[le_len] = '\0'; /* null terminate */ XP_FREE(ucs2_chars); return le_string; } obj = INTL_CreateCharCodeConverter(); if (!obj) { return str; } if (INTL_GetCharCodeConverter(charset, fe_LocaleCharSetID, obj)) { le_string = INTL_CallCharCodeConverter(obj, str, strlen((char *) str)); if (!le_string) { le_string = str; } } else { le_string = str; } INTL_DestroyCharCodeConverter(obj); return le_string; } /* * fe_ConvertToXmString - convert text/encoding to XmString/XmFontList * * NOTE: if the calling code does not yet set the XmFontList * then pass in font==NULL */ XmString fe_ConvertToXmString(unsigned char *str, int16 charset, fe_Font font, XmFontType type, XmFontList *fontList_p) { unsigned char *loc; XmString xms; XmFontList font_list; XmFontListEntry flentry; /* * init default return values */ *fontList_p = NULL; if ((!IS_UNICODE_CSID(charset)) || (!font)) { loc = fe_ConvertToLocaleEncoding(charset, str); if (loc) { xms = XmStringCreate((char *) loc, XmFONTLIST_DEFAULT_TAG); if (loc != str) { free(loc); } } else { xms = NULL; } if (font) { flentry = XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, type, font); if (flentry) { font_list = XmFontListAppendEntry(NULL, flentry); if (font_list) *fontList_p = font_list; XmFontListEntryFree(&flentry); } } return xms; } else { xms = fe_utf8_to_XmString(font, str, strlen(str), fontList_p); return xms; } return xms; } unsigned char * fe_ConvertFromLocaleEncoding(int16 charset, unsigned char *str) { CCCDataObject obj; unsigned char *ret; if ((charset == fe_LocaleCharSetID) || (!str) || (!*str)) { return str; } /* handle UTF8 */ if (IS_UTF8_CSID(charset)) { uint16 *ucs2_chars; uint32 ucs2_buflen, num_ucs2_chars; unsigned char *utf8p; /* * Convert local encoding to ucs2 */ ucs2_buflen = INTL_StrToUnicodeLen(fe_LocaleCharSetID, str); ucs2_chars = (uint16 *) XP_CALLOC(sizeof(uint16), ucs2_buflen+1); num_ucs2_chars = INTL_StrToUnicode(fe_LocaleCharSetID, str, ucs2_chars, ucs2_buflen); utf8p = INTL_UCS2ToUTF8(ucs2_chars, num_ucs2_chars); XP_FREE(ucs2_chars); return utf8p; } obj = INTL_CreateCharCodeConverter(); if (!obj) { return str; } if (INTL_GetCharCodeConverter(fe_LocaleCharSetID, charset, obj)) { ret = INTL_CallCharCodeConverter(obj, str, strlen((char *) str)); if (!ret) { ret = str; } } else { ret = str; } INTL_DestroyCharCodeConverter(obj); return ret; } /* fe_GetTextSelection() is a direct replacement for XmTextGetSelection -- * use XtFree() to free the returned string. */ char * fe_GetTextSelection(Widget widget) { char *loc; char *str; XP_ASSERT(XmIsText(widget) || XmIsTextField(widget)); loc = NULL; if (XmIsText(widget)) { loc = XmTextGetSelection(widget); } else { loc = XmTextFieldGetSelection(widget); } if (!loc) { return NULL; } str = (char *) fe_ConvertFromLocaleEncoding( INTL_DefaultWinCharSetID(NULL), (unsigned char *) loc); if (str == loc) { str = XtNewString(str); if (!str) { return NULL; } } XtFree(loc); return str; } /* fe_GetTextField() is a direct replacement for XmTextGetString -- * use XtFree() to free the returned string. */ char * fe_GetTextField(Widget widget) { char *loc; char *str; XP_ASSERT(XmIsText(widget) || XmIsTextField(widget)); loc = NULL; XtVaGetValues(widget, XmNvalue, &loc, 0); if (!loc) { return NULL; } str = (char *) fe_ConvertFromLocaleEncoding( INTL_DefaultWinCharSetID(NULL), (unsigned char *) loc); if (str == loc) { str = XtNewString(str); if (!str) { return NULL; } } XtFree(loc); return str; } void fe_SetTextField(Widget widget, const char *str) { unsigned char *loc; XP_ASSERT(XmIsText(widget) || XmIsTextField(widget)); if ((NULL==str) || ('\0'==*str)) { XtVaSetValues(widget, XmNvalue, str, 0); return; } loc = fe_ConvertToLocaleEncoding(INTL_DefaultWinCharSetID(NULL), (unsigned char *) str); XtVaSetValues(widget, XmNvalue, loc, 0); if (loc != ((unsigned char *) str)) { XP_FREE(loc); } } void fe_SetTextFieldAndCallBack(Widget widget, const char *str) { unsigned char *loc = NULL; XP_ASSERT(XmIsText(widget) || XmIsTextField(widget)); if ((NULL != str) && ('\0' != *str)) { loc = fe_ConvertToLocaleEncoding(INTL_DefaultWinCharSetID(NULL), (unsigned char *) str); } /* * Warning: on SGI, XtVaSetValues() doesn't run the * valueChangedCallback, but XmTextFieldSetString() does. */ if (XmIsText(widget)) XmTextSetString(widget, (char *) str); else if (XmIsTextField(widget)) XmTextFieldSetString(widget, (char *) str); if (loc != ((unsigned char *) str)) { XP_FREE(loc); } } /* * We link statically on AIX to force it to pick up our thread-safe malloc. * But AIX has a bug where linking statically results in a broken mbstowcs * (and wcstombs) being linked in. So we re-implement these here, so that * these are used. See bug # 13574. */ #ifdef AIXV3 size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n) { int charlen; size_t inlen; size_t ret; wchar_t wc; if (!s) { return 0; } ret = 0; inlen = strlen(s) + 1; while (1) { wc = 0; charlen = mbtowc(&wc, s, inlen); if (charlen < 0) { return -1; } else if (charlen == 0) { if (pwcs) { if (n > 0) { *pwcs = 0; } } break; } else { if (pwcs) { if (n > 0) { *pwcs++ = wc; ret++; n--; if (n == 0) { break; } } else { break; } } else { ret++; } inlen -= charlen; s += charlen; } } return ret; } size_t wcstombs(char *s, const wchar_t *pwcs, size_t n) { char buf[MB_LEN_MAX]; int charlen; int i; size_t ret; if (!pwcs) { return 0; } ret = 0; while (1) { buf[0] = 0; charlen = wctomb(buf, *pwcs); if (charlen <= 0) { return -1; } else { if (s) { if (n >= charlen) { for (i = 0; i < charlen; i++) { *s++ = buf[i]; } if (*pwcs) { ret += charlen; } else { break; } n -= charlen; if (n == 0) { break; } } else { break; } } else { if (*pwcs) { ret += charlen; } else { break; } } pwcs++; } } return ret; } #endif /* AIXV3 */