* locale/lc-time.c (_nl_init_era_entries, _nl_get_era_entry,

_nl_select_era_entry): Moved to ...
	* time/era.c: ... here, new file.
	(_nl_init_era_entries, _nl_get_era_entry, _nl_select_era_entry):
	Add internal_function to definitions.  Take an additional argument
	giving the `struct locale_data *' to use.
	* locale/lc-time.c (_get_alt_digit, _nl_get_walt_digit,
	_nl_parse_alt_digit): Moved to ...
	* time/alt_digit.c: ... here, new file.
	* time/lc-time-cleanup.c: New file.
	* locale/lc-time.c (_nl_postload_time, free_mem): Functions removed.
	* locale/localeinfo.h (_nl_postload_time): Remove decl.
	(_nl_cleanup_time): Declare it.
	(_nl_get_era_entry, _nl_select_era_entry): Update decls.
	(_get_alt_digit, _nl_get_walt_digit, _nl_parse_alt_digit): Likewise.
	* time/Makefile (aux): New variable: era, alt_digit, lc-time-cleanup.
	* time/strftime.c: Pass locale data to helper functions.
	* time/strptime.c: Likewise.

	* locale/localeinfo.h (struct locale_data): New member `private'
	* locale/loadlocale.c (_nl_intern_locale_data): Initialize it.
	(_nl_unload_locale): Call LOCALE->private.cleanup if it is set.
	* locale/C-collate.c: Update initializer.
	* locale/C-identification.c: Likewise.
	* locale/C-measurement.c: Likewise.
	* locale/C-telephone.c: Likewise.
	* locale/C-address.c: Likewise.
	* locale/C-name.c: Likewise.
	* locale/C-paper.c: Likewise.
	* locale/C-time.c: Likewise.
	* locale/C-numeric.c: Likewise.
	* locale/C-monetary.c: Likewise.
	* locale/C-messages.c : Likewise.
	* locale/C-ctype.c: Likewise.

	* time/strptime.c [USE_IN_EXTENDED_LOCALE_MODEL] (_NL_CURRENT_WORD):
	Redefine this too.
This commit is contained in:
Roland McGrath 2002-08-28 23:11:21 +00:00
parent 6e68eecf7b
commit df9f41c942
21 changed files with 540 additions and 323 deletions

View File

@ -1,3 +1,43 @@
2002-08-28 Roland McGrath <roland@redhat.com>
* locale/lc-time.c (_nl_init_era_entries, _nl_get_era_entry,
_nl_select_era_entry): Moved to ...
* time/era.c: ... here, new file.
(_nl_init_era_entries, _nl_get_era_entry, _nl_select_era_entry):
Add internal_function to definitions. Take an additional argument
giving the `struct locale_data *' to use.
* locale/lc-time.c (_get_alt_digit, _nl_get_walt_digit,
_nl_parse_alt_digit): Moved to ...
* time/alt_digit.c: ... here, new file.
* time/lc-time-cleanup.c: New file.
* locale/lc-time.c (_nl_postload_time, free_mem): Functions removed.
* locale/localeinfo.h (_nl_postload_time): Remove decl.
(_nl_cleanup_time): Declare it.
(_nl_get_era_entry, _nl_select_era_entry): Update decls.
(_get_alt_digit, _nl_get_walt_digit, _nl_parse_alt_digit): Likewise.
* time/Makefile (aux): New variable: era, alt_digit, lc-time-cleanup.
* time/strftime.c: Pass locale data to helper functions.
* time/strptime.c: Likewise.
* locale/localeinfo.h (struct locale_data): New member `private'
* locale/loadlocale.c (_nl_intern_locale_data): Initialize it.
(_nl_unload_locale): Call LOCALE->private.cleanup if it is set.
* locale/C-collate.c: Update initializer.
* locale/C-identification.c: Likewise.
* locale/C-measurement.c: Likewise.
* locale/C-telephone.c: Likewise.
* locale/C-address.c: Likewise.
* locale/C-name.c: Likewise.
* locale/C-paper.c: Likewise.
* locale/C-time.c: Likewise.
* locale/C-numeric.c: Likewise.
* locale/C-monetary.c: Likewise.
* locale/C-messages.c : Likewise.
* locale/C-ctype.c: Likewise.
* time/strptime.c [USE_IN_EXTENDED_LOCALE_MODEL] (_NL_CURRENT_WORD):
Redefine this too.
2002-08-28 Jakub Jelinek <jakub@redhat.com>
* sysdeps/ia64/elf/configure.in (PI_STATIC_AND_HIDDEN): Define

View File

@ -28,6 +28,7 @@ const struct locale_data _nl_C_LC_ADDRESS attribute_hidden =
{
_nl_C_name,
NULL, 0, 0, /* no file mapped */
{ NULL, }, /* no cached data */
UNDELETABLE,
0,
13,

View File

@ -102,6 +102,7 @@ const struct locale_data _nl_C_LC_COLLATE attribute_hidden =
{
_nl_C_name,
NULL, 0, 0, /* no file mapped */
{ NULL, }, /* no cached data */
UNDELETABLE,
0,
19,

View File

@ -542,6 +542,7 @@ const struct locale_data _nl_C_LC_CTYPE attribute_hidden =
{
_nl_C_name,
NULL, 0, 0, /* no file mapped */
{ NULL, }, /* no cached data */
UNDELETABLE,
1, /* Enable transliteration by default. */
NR_FIXED + NR_CLASSES + NR_MAPS,

View File

@ -28,6 +28,7 @@ const struct locale_data _nl_C_LC_IDENTIFICATION attribute_hidden =
{
_nl_C_name,
NULL, 0, 0, /* no file mapped */
{ NULL, }, /* no cached data */
UNDELETABLE,
0,
16,

View File

@ -28,6 +28,7 @@ const struct locale_data _nl_C_LC_MEASUREMENT attribute_hidden =
{
_nl_C_name,
NULL, 0, 0, /* no file mapped */
{ NULL, }, /* no cached data */
UNDELETABLE,
0,
2,

View File

@ -28,6 +28,7 @@ const struct locale_data _nl_C_LC_MESSAGES attribute_hidden =
{
_nl_C_name,
NULL, 0, 0, /* no file mapped */
{ NULL, }, /* no cached data */
UNDELETABLE,
0,
5,

View File

@ -32,6 +32,7 @@ const struct locale_data _nl_C_LC_MONETARY attribute_hidden =
{
_nl_C_name,
NULL, 0, 0, /* no file mapped */
{ NULL, }, /* no cached data */
UNDELETABLE,
0,
46,

View File

@ -28,6 +28,7 @@ const struct locale_data _nl_C_LC_NAME attribute_hidden =
{
_nl_C_name,
NULL, 0, 0, /* no file mapped */
{ NULL, }, /* no cached data */
UNDELETABLE,
0,
7,

View File

@ -25,6 +25,7 @@ const struct locale_data _nl_C_LC_NUMERIC attribute_hidden =
{
_nl_C_name,
NULL, 0, 0, /* no file mapped */
{ NULL, }, /* no cached data */
UNDELETABLE,
0,
6,

View File

@ -28,6 +28,7 @@ const struct locale_data _nl_C_LC_PAPER attribute_hidden =
{
_nl_C_name,
NULL, 0, 0, /* no file mapped */
{ NULL, }, /* no cached data */
UNDELETABLE,
0,
3,

View File

@ -28,6 +28,7 @@ const struct locale_data _nl_C_LC_TELEPHONE attribute_hidden =
{
_nl_C_name,
NULL, 0, 0, /* no file mapped */
{ NULL, }, /* no cached data */
UNDELETABLE,
0,
5,

View File

@ -27,6 +27,7 @@ const struct locale_data _nl_C_LC_TIME attribute_hidden =
{
_nl_C_name,
NULL, 0, 0, /* no file mapped */
{ NULL, }, /* no cached data */
UNDELETABLE,
0,
111,

View File

@ -17,305 +17,6 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <bits/libc-lock.h>
#include <endian.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <wchar.h>
#include "localeinfo.h"
_NL_CURRENT_DEFINE (LC_TIME);
/* Some of the functions here must not be used while setlocale is called. */
__libc_lock_define (extern, __libc_setlocale_lock attribute_hidden)
static int era_initialized;
static struct era_entry *eras;
static size_t num_eras;
static int alt_digits_initialized;
static const char **alt_digits;
static int walt_digits_initialized;
static const wchar_t **walt_digits;
void
_nl_postload_time (void)
{
/* Prepare lazy initialization of `era' and `alt_digits' array. */
era_initialized = 0;
alt_digits_initialized = 0;
walt_digits_initialized = 0;
}
#define ERA_DATE_CMP(a, b) \
(a[0] < b[0] || (a[0] == b[0] && (a[1] < b[1] \
|| (a[1] == b[1] && a[2] <= b[2]))))
static void
_nl_init_era_entries (void)
{
size_t cnt;
__libc_lock_lock (__libc_setlocale_lock);
if (era_initialized == 0)
{
size_t new_num_eras = _NL_CURRENT_WORD (LC_TIME,
_NL_TIME_ERA_NUM_ENTRIES);
if (new_num_eras == 0)
{
free (eras);
eras = NULL;
}
else
{
struct era_entry *new_eras = eras;
if (num_eras != new_num_eras)
new_eras =
(struct era_entry *) realloc (eras,
new_num_eras
* sizeof (struct era_entry));
if (new_eras == NULL)
{
free (eras);
num_eras = 0;
eras = NULL;
}
else
{
const char *ptr = _NL_CURRENT (LC_TIME, _NL_TIME_ERA_ENTRIES);
num_eras = new_num_eras;
eras = new_eras;
for (cnt = 0; cnt < num_eras; ++cnt)
{
const char *base_ptr = ptr;
memcpy ((void *) (eras + cnt), (const void *) ptr,
sizeof (uint32_t) * 8);
if (ERA_DATE_CMP(eras[cnt].start_date,
eras[cnt].stop_date))
if (eras[cnt].direction == (uint32_t) '+')
eras[cnt].absolute_direction = 1;
else
eras[cnt].absolute_direction = -1;
else
if (eras[cnt].direction == (uint32_t) '+')
eras[cnt].absolute_direction = -1;
else
eras[cnt].absolute_direction = 1;
/* Skip numeric values. */
ptr += sizeof (uint32_t) * 8;
/* Set and skip era name. */
eras[cnt].era_name = ptr;
ptr = strchr (ptr, '\0') + 1;
/* Set and skip era format. */
eras[cnt].era_format = ptr;
ptr = strchr (ptr, '\0') + 1;
ptr += 3 - (((ptr - (const char *) base_ptr) + 3) & 3);
/* Set and skip wide era name. */
eras[cnt].era_wname = (wchar_t *) ptr;
ptr = (char *) (wcschr ((wchar_t *) ptr, L'\0') + 1);
/* Set and skip wide era format. */
eras[cnt].era_wformat = (wchar_t *) ptr;
ptr = (char *) (wcschr ((wchar_t *) ptr, L'\0') + 1);
}
}
}
era_initialized = 1;
}
__libc_lock_unlock (__libc_setlocale_lock);
}
struct era_entry *
_nl_get_era_entry (const struct tm *tp)
{
struct era_entry *result;
int32_t tdate[3];
size_t cnt;
tdate[0] = tp->tm_year;
tdate[1] = tp->tm_mon;
tdate[2] = tp->tm_mday;
if (era_initialized == 0)
_nl_init_era_entries ();
/* Now compare date with the available eras. */
for (cnt = 0; cnt < num_eras; ++cnt)
if ((ERA_DATE_CMP(eras[cnt].start_date, tdate)
&& ERA_DATE_CMP(tdate, eras[cnt].stop_date))
|| (ERA_DATE_CMP(eras[cnt].stop_date, tdate)
&& ERA_DATE_CMP(tdate, eras[cnt].start_date)))
break;
result = cnt < num_eras ? &eras[cnt] : NULL;
return result;
}
struct era_entry *
_nl_select_era_entry (int cnt)
{
if (era_initialized == 0)
_nl_init_era_entries ();
return &eras[cnt];
}
const char *
_nl_get_alt_digit (unsigned int number)
{
const char *result;
__libc_lock_lock (__libc_setlocale_lock);
if (alt_digits_initialized == 0)
{
alt_digits_initialized = 1;
if (alt_digits == NULL)
alt_digits = malloc (100 * sizeof (const char *));
if (alt_digits != NULL)
{
const char *ptr = _NL_CURRENT (LC_TIME, ALT_DIGITS);
size_t cnt;
if (alt_digits != NULL)
for (cnt = 0; cnt < 100; ++cnt)
{
alt_digits[cnt] = ptr;
/* Skip digit format. */
ptr = strchr (ptr, '\0') + 1;
}
}
}
result = alt_digits != NULL && number < 100 ? alt_digits[number] : NULL;
__libc_lock_unlock (__libc_setlocale_lock);
return result;
}
const wchar_t *
_nl_get_walt_digit (unsigned int number)
{
const wchar_t *result;
__libc_lock_lock (__libc_setlocale_lock);
if (walt_digits_initialized == 0)
{
walt_digits_initialized = 1;
if (walt_digits == NULL)
walt_digits = malloc (100 * sizeof (const uint32_t *));
if (walt_digits != NULL)
{
const wchar_t *ptr = _NL_CURRENT_WSTR (LC_TIME, _NL_WALT_DIGITS);
size_t cnt;
for (cnt = 0; cnt < 100; ++cnt)
{
walt_digits[cnt] = ptr;
/* Skip digit format. */
ptr = wcschr (ptr, L'\0') + 1;
}
}
}
result = walt_digits != NULL && number < 100 ? walt_digits[number] : NULL;
__libc_lock_unlock (__libc_setlocale_lock);
return (wchar_t *) result;
}
int
_nl_parse_alt_digit (const char **strp)
{
const char *str = *strp;
int result = -1;
size_t cnt;
size_t maxlen = 0;
__libc_lock_lock (__libc_setlocale_lock);
if (alt_digits_initialized == 0)
{
alt_digits_initialized = 1;
if (alt_digits == NULL)
alt_digits = malloc (100 * sizeof (const char *));
if (alt_digits != NULL)
{
const char *ptr = _NL_CURRENT (LC_TIME, ALT_DIGITS);
if (alt_digits != NULL)
for (cnt = 0; cnt < 100; ++cnt)
{
alt_digits[cnt] = ptr;
/* Skip digit format. */
ptr = strchr (ptr, '\0') + 1;
}
}
}
/* Matching is not unambiguos. The alternative digits could be like
I, II, III, ... and the first one is a substring of the second
and third. Therefore we must keep on searching until we found
the longest possible match. Note that this is not specified in
the standard. */
for (cnt = 0; cnt < 100; ++cnt)
{
size_t len = strlen (alt_digits[cnt]);
if (len > maxlen && strncmp (alt_digits[cnt], str, len) == 0)
{
maxlen = len;
result = (int) cnt;
}
}
__libc_lock_unlock (__libc_setlocale_lock);
if (result != -1)
*strp += maxlen;
return result;
}
static void
free_mem (void)
{
free (alt_digits);
free (walt_digits);
}
text_set_element (__libc_subfreeres, free_mem);

View File

@ -99,6 +99,8 @@ _nl_intern_locale_data (int category, const void *data, size_t datasize)
newdata->filedata = (void *) filedata;
newdata->filesize = datasize;
newdata->private.data = NULL;
newdata->private.cleanup = NULL;
newdata->usage_count = 0;
newdata->use_translit = 0;
newdata->nstrings = filedata->nstrings;
@ -251,6 +253,9 @@ void
internal_function
_nl_unload_locale (struct locale_data *locale)
{
if (locale->private.cleanup)
(*locale->private.cleanup) (locale);
switch (__builtin_expect (locale->alloc, ld_mapped))
{
case ld_malloced:

View File

@ -54,6 +54,19 @@ struct locale_data
ld_archive /* Both point into mmap'd archive regions. */
} alloc;
/* This provides a slot for category-specific code to cache data computed
about this locale. That code can set a cleanup function to deallocate
the data. */
struct
{
void (*cleanup) (struct locale_data *) internal_function;
union
{
void *data;
struct lc_time_data *time;
};
} private;
unsigned int usage_count; /* Counter for users. */
int use_translit; /* Nonzero if the mb*towv*() and wc*tomb()
@ -124,6 +137,19 @@ struct era_entry
-1 indicates that year number is higher in the past. (like B.C.) */
};
/* Structure caching computed data about information from LC_TIME.
The `private.time' member of `struct locale_data' points to this. */
struct lc_time_data
{
struct era_entry *eras;
size_t num_eras;
int era_initialized;
const char **alt_digits;
const wchar_t **walt_digits;
int alt_digits_initialized, walt_digits_initialized;
};
/* LC_CTYPE specific:
Hardwired indices for standard wide character translation mappings. */
@ -303,23 +329,36 @@ extern struct locale_data *_nl_intern_locale_data (int category,
/* Return `era' entry which corresponds to TP. Used in strftime. */
extern struct era_entry *_nl_get_era_entry (const struct tm *tp);
extern struct era_entry *_nl_get_era_entry (const struct tm *tp,
struct locale_data *lc_time)
internal_function attribute_hidden;
/* Return `era' cnt'th entry . Used in strptime. */
extern struct era_entry *_nl_select_era_entry (int cnt);
extern struct era_entry *_nl_select_era_entry (int cnt,
struct locale_data *lc_time)
internal_function attribute_hidden;
/* Return `alt_digit' which corresponds to NUMBER. Used in strftime. */
extern const char *_nl_get_alt_digit (unsigned int number);
extern const char *_nl_get_alt_digit (unsigned int number,
struct locale_data *lc_time)
internal_function attribute_hidden;
/* Similar, but now for wide characters. */
extern const wchar_t *_nl_get_walt_digit (unsigned int number);
extern const wchar_t *_nl_get_walt_digit (unsigned int number,
struct locale_data *lc_time)
internal_function attribute_hidden;
/* Parse string as alternative digit and return numeric value. */
extern int _nl_parse_alt_digit (const char **strp);
extern int _nl_parse_alt_digit (const char **strp,
struct locale_data *lc_time)
internal_function attribute_hidden;
/* Postload processing. */
extern void _nl_postload_ctype (void);
extern void _nl_postload_time (void);
/* Functions used for the `private.cleanup' hook. */
extern void _nl_cleanup_time (struct locale_data *)
internal_function attribute_hidden;
#endif /* localeinfo.h */

View File

@ -30,6 +30,7 @@ routines := offtime asctime clock ctime ctime_r difftime \
stime dysize timegm ftime \
getdate strptime strptime_l \
strftime wcsftime strftime_l wcsftime_l
aux := era alt_digit lc-time-cleanup
distribute := datemsk
tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \

193
time/alt_digit.c Normal file
View File

@ -0,0 +1,193 @@
/* Helper functions used by strftime/strptime to handle alternate digits.
Copyright (C) 1995-2001,02 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "../locale/localeinfo.h"
#include <bits/libc-lock.h>
#include <stdlib.h>
#include <wchar.h>
#include <string.h>
/* Some of the functions here must not be used while setlocale is called. */
__libc_lock_define (extern, __libc_setlocale_lock attribute_hidden)
#define CURRENT(item) (current->values[_NL_ITEM_INDEX (item)].string)
#define CURRENT_WSTR(item) \
((wchar_t *) current->values[_NL_ITEM_INDEX (item)].wstr)
static void
_nl_init_alt_digit (struct locale_data *current)
{
struct lc_time_data *data;
if (current->private.time == NULL)
{
current->private.time = malloc (sizeof *current->private.time);
if (current->private.time == NULL)
return;
memset (current->private.time, 0, sizeof *current->private.time);
current->private.cleanup = &_nl_cleanup_time;
}
data = current->private.time;
if (! data->alt_digits_initialized)
{
const char *ptr = CURRENT (ALT_DIGITS);
size_t cnt;
data->alt_digits_initialized = 1;
if (ptr != NULL)
{
data->alt_digits = malloc (100 * sizeof (const char *));
if (data->alt_digits != NULL)
for (cnt = 0; cnt < 100; ++cnt)
{
data->alt_digits[cnt] = ptr;
/* Skip digit format. */
ptr = strchr (ptr, '\0') + 1;
}
}
}
}
const char *
internal_function
_nl_get_alt_digit (unsigned int number, struct locale_data *current)
{
const char *result;
if (number >= 100 || CURRENT (ALT_DIGITS)[0] == '\0')
return NULL;
__libc_lock_lock (__libc_setlocale_lock);
if (current->private.time == NULL
|| ! current->private.time->alt_digits_initialized)
_nl_init_alt_digit (current);
result = ((current->private.time != NULL
&& current->private.time->alt_digits != NULL)
? current->private.time->alt_digits[number]
: NULL);
__libc_lock_unlock (__libc_setlocale_lock);
return result;
}
const wchar_t *
internal_function
_nl_get_walt_digit (unsigned int number, struct locale_data *current)
{
const wchar_t *result = NULL;
struct lc_time_data *data;
if (number >= 100 || CURRENT_WSTR (_NL_WALT_DIGITS)[0] == L'\0')
return NULL;
__libc_lock_lock (__libc_setlocale_lock);
if (current->private.time == NULL)
{
current->private.time = malloc (sizeof *current->private.time);
if (current->private.time == NULL)
goto out;
memset (current->private.time, 0, sizeof *current->private.time);
current->private.cleanup = &_nl_cleanup_time;
}
data = current->private.time;
if (! data->walt_digits_initialized)
{
const wchar_t *ptr = CURRENT_WSTR (_NL_WALT_DIGITS);
size_t cnt;
data->walt_digits_initialized = 1;
if (ptr != NULL)
{
data->walt_digits = malloc (100 * sizeof (const uint32_t *));
if (data->walt_digits != NULL)
for (cnt = 0; cnt < 100; ++cnt)
{
data->walt_digits[cnt] = ptr;
/* Skip digit format. */
ptr = wcschr (ptr, L'\0') + 1;
}
}
}
if (data->walt_digits != NULL)
result = data->walt_digits[number];
out:
__libc_lock_unlock (__libc_setlocale_lock);
return (wchar_t *) result;
}
int
internal_function
_nl_parse_alt_digit (const char **strp, struct locale_data *current)
{
const char *str = *strp;
int result = -1;
size_t cnt;
size_t maxlen = 0;
if (CURRENT_WSTR (_NL_WALT_DIGITS)[0] == L'\0')
return result;
__libc_lock_lock (__libc_setlocale_lock);
if (current->private.time == NULL
|| ! current->private.time->alt_digits_initialized)
_nl_init_alt_digit (current);
if (current->private.time != NULL &&
current->private.time->alt_digits != NULL)
/* Matching is not unambiguous. The alternative digits could be like
I, II, III, ... and the first one is a substring of the second
and third. Therefore we must keep on searching until we found
the longest possible match. Note that this is not specified in
the standard. */
for (cnt = 0; cnt < 100; ++cnt)
{
const char *const dig = current->private.time->alt_digits[cnt];
size_t len = strlen (dig);
if (len > maxlen && strncmp (dig, str, len) == 0)
{
maxlen = len;
result = (int) cnt;
}
}
__libc_lock_unlock (__libc_setlocale_lock);
if (result != -1)
*strp += maxlen;
return result;
}

177
time/era.c Normal file
View File

@ -0,0 +1,177 @@
/* Helper functions used by strftime/strptime to handle locale-specific "eras".
Copyright (C) 1995-2001,02 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "../locale/localeinfo.h"
#include <bits/libc-lock.h>
#include <stdlib.h>
#include <wchar.h>
#include <string.h>
/* Some of the functions here must not be used while setlocale is called. */
__libc_lock_define (extern, __libc_setlocale_lock attribute_hidden)
#define CURRENT(item) (current->values[_NL_ITEM_INDEX (item)].string)
#define CURRENT_WORD(item) (current->values[_NL_ITEM_INDEX (item)].word)
#define ERA_DATE_CMP(a, b) \
(a[0] < b[0] || (a[0] == b[0] && (a[1] < b[1] \
|| (a[1] == b[1] && a[2] <= b[2]))))
/* Look up the era information in CURRENT's locale strings and
cache it in CURRENT->private. */
static void internal_function
_nl_init_era_entries (struct locale_data *current)
{
size_t cnt;
struct lc_time_data *data;
/* Avoid touching CURRENT if there is no data at all, for _nl_C_LC_TIME. */
if (CURRENT_WORD (_NL_TIME_ERA_NUM_ENTRIES) == 0)
return;
__libc_lock_lock (__libc_setlocale_lock);
if (current->private.time == NULL)
{
current->private.time = malloc (sizeof *current->private.time);
if (current->private.time == NULL)
goto out;
memset (current->private.time, 0, sizeof *current->private.time);
current->private.cleanup = &_nl_cleanup_time;
}
data = current->private.time;
if (! data->era_initialized)
{
size_t new_num_eras = CURRENT_WORD (_NL_TIME_ERA_NUM_ENTRIES);
if (new_num_eras == 0)
{
if (data->eras != NULL)
{
free (data->eras);
data->eras = NULL;
}
}
else
{
struct era_entry *new_eras = data->eras;
if (data->num_eras != new_num_eras)
new_eras =
(struct era_entry *) realloc (data->eras,
new_num_eras
* sizeof (struct era_entry));
if (new_eras == NULL)
{
free (data->eras);
data->num_eras = 0;
data->eras = NULL;
}
else
{
const char *ptr = CURRENT (_NL_TIME_ERA_ENTRIES);
data->num_eras = new_num_eras;
data->eras = new_eras;
for (cnt = 0; cnt < new_num_eras; ++cnt)
{
const char *base_ptr = ptr;
memcpy ((void *) (new_eras + cnt), (const void *) ptr,
sizeof (uint32_t) * 8);
if (ERA_DATE_CMP(new_eras[cnt].start_date,
new_eras[cnt].stop_date))
if (new_eras[cnt].direction == (uint32_t) '+')
new_eras[cnt].absolute_direction = 1;
else
new_eras[cnt].absolute_direction = -1;
else
if (new_eras[cnt].direction == (uint32_t) '+')
new_eras[cnt].absolute_direction = -1;
else
new_eras[cnt].absolute_direction = 1;
/* Skip numeric values. */
ptr += sizeof (uint32_t) * 8;
/* Set and skip era name. */
new_eras[cnt].era_name = ptr;
ptr = strchr (ptr, '\0') + 1;
/* Set and skip era format. */
new_eras[cnt].era_format = ptr;
ptr = strchr (ptr, '\0') + 1;
ptr += 3 - (((ptr - (const char *) base_ptr) + 3) & 3);
/* Set and skip wide era name. */
new_eras[cnt].era_wname = (wchar_t *) ptr;
ptr = (char *) (wcschr ((wchar_t *) ptr, L'\0') + 1);
/* Set and skip wide era format. */
new_eras[cnt].era_wformat = (wchar_t *) ptr;
ptr = (char *) (wcschr ((wchar_t *) ptr, L'\0') + 1);
}
}
}
data->era_initialized = 1;
}
out:
__libc_lock_unlock (__libc_setlocale_lock);
}
struct era_entry *
internal_function
_nl_get_era_entry (const struct tm *tp, struct locale_data *current)
{
if (current->private.time == NULL || !current->private.time->era_initialized)
_nl_init_era_entries (current);
if (current->private.time != NULL)
{
/* Now compare date with the available eras. */
const int32_t tdate[3] = { tp->tm_year, tp->tm_mon, tp->tm_mday };
size_t cnt;
for (cnt = 0; cnt < current->private.time->num_eras; ++cnt)
if ((ERA_DATE_CMP (current->private.time->eras[cnt].start_date, tdate)
&& ERA_DATE_CMP (tdate,
current->private.time->eras[cnt].stop_date))
|| (ERA_DATE_CMP (current->private.time->eras[cnt].stop_date,
tdate)
&& ERA_DATE_CMP (tdate,
current->private.time->eras[cnt].start_date)))
return &current->private.time->eras[cnt];
}
return NULL;
}
struct era_entry *
internal_function
_nl_select_era_entry (int cnt, struct locale_data *current)
{
if (current->private.time == NULL || !current->private.time->era_initialized)
_nl_init_era_entries (current);
return (current->private.time == NULL
? NULL : &current->private.time->eras[cnt]);
}

41
time/lc-time-cleanup.c Normal file
View File

@ -0,0 +1,41 @@
/* Cleanup code for data structures kept by strftime/strptime helper functions.
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "../locale/localeinfo.h"
#include <stdlib.h>
void internal_function
_nl_cleanup_time (struct locale_data *locale)
{
struct lc_time_data *const data = locale->private.time;
if (data != NULL)
{
locale->private.time = NULL;
locale->private.cleanup = NULL;
if (data->eras != NULL)
free (data->eras);
if (data->alt_digits != NULL)
free (data->alt_digits);
if (data->walt_digits != NULL)
free (data->walt_digits);
free (data);
}
}

View File

@ -315,10 +315,16 @@ static const CHAR_T zeroes[16] = /* "0000000000000000" */
# define LOCALE_PARAM , loc
# define LOCALE_ARG , loc
# define LOCALE_PARAM_DECL __locale_t loc;
# define HELPER_LOCALE_ARG , current
#else
# define LOCALE_PARAM
# define LOCALE_ARG
# define LOCALE_PARAM_DECL
# ifdef _LIBC
# define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
# else
# define HELPER_LOCALE_ARG
# endif
#endif
#ifdef COMPILE_WIDE
@ -494,7 +500,7 @@ my_strftime (s, maxsize, format, tp ut_argument LOCALE_PARAM)
LOCALE_PARAM_DECL
{
#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
const struct locale_data *const current = loc->__locales[LC_TIME];
struct locale_data *const current = loc->__locales[LC_TIME];
#endif
int hour12 = tp->tm_hour;
@ -880,7 +886,7 @@ my_strftime (s, maxsize, format, tp ut_argument LOCALE_PARAM)
if (modifier == L_('E'))
{
#if HAVE_STRUCT_ERA_ENTRY
struct era_entry *era = _nl_get_era_entry (tp);
struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
if (era)
{
# ifdef COMPILE_WIDE
@ -956,9 +962,11 @@ my_strftime (s, maxsize, format, tp ut_argument LOCALE_PARAM)
/* Get the locale specific alternate representation of
the number NUMBER_VALUE. If none exist NULL is returned. */
# ifdef COMPILE_WIDE
const wchar_t *cp = _nl_get_walt_digit (number_value);
const wchar_t *cp = _nl_get_walt_digit (number_value
HELPER_LOCALE_ARG);
# else
const char *cp = _nl_get_alt_digit (number_value);
const char *cp = _nl_get_alt_digit (number_value
HELPER_LOCALE_ARG);
# endif
if (cp != NULL)
@ -1238,7 +1246,7 @@ my_strftime (s, maxsize, format, tp ut_argument LOCALE_PARAM)
if (modifier == 'E')
{
#if HAVE_STRUCT_ERA_ENTRY
struct era_entry *era = _nl_get_era_entry (tp);
struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
if (era)
{
# ifdef COMPILE_WIDE
@ -1263,7 +1271,7 @@ my_strftime (s, maxsize, format, tp ut_argument LOCALE_PARAM)
if (modifier == L_('E'))
{
#if HAVE_STRUCT_ERA_ENTRY
struct era_entry *era = _nl_get_era_entry (tp);
struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
if (era)
{
int delta = tp->tm_year - era->start_date[0];