pjs/cmd/xfe/locale.c

598 строки
9.7 KiB
C

/* -*- 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 */