(root)/
glibc-2.38/
time/
era.c
       1  /* Helper functions used by strftime/strptime to handle locale-specific "eras".
       2     Copyright (C) 1995-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include "../locale/localeinfo.h"
      20  #include <libc-lock.h>
      21  #include <stdlib.h>
      22  #include <wchar.h>
      23  #include <string.h>
      24  #include <stdint.h>
      25  
      26  /* Some of the functions here must not be used while setlocale is called.  */
      27  __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
      28  
      29  #define CURRENT(item)		(current->values[_NL_ITEM_INDEX (item)].string)
      30  #define CURRENT_WORD(item)	(current->values[_NL_ITEM_INDEX (item)].word)
      31  
      32  #define ERA_DATE_CMP(a, b) \
      33    (a[0] < b[0] || (a[0] == b[0] && (a[1] < b[1]				      \
      34  				    || (a[1] == b[1] && a[2] <= b[2]))))
      35  
      36  /* Look up the era information in CURRENT's locale strings and
      37     cache it in CURRENT->private.  */
      38  static struct lc_time_data *
      39  _nl_init_era_entries (struct __locale_data *current)
      40  {
      41    size_t cnt;
      42    struct lc_time_data *data;
      43  
      44    /* Avoid touching CURRENT if there is no data at all, for _nl_C_LC_TIME.  */
      45    if (CURRENT_WORD (_NL_TIME_ERA_NUM_ENTRIES) == 0)
      46      return NULL;
      47  
      48    data = current->private;
      49    if (data != NULL && atomic_load_acquire (&data->era_initialized))
      50      return data;
      51  
      52    __libc_rwlock_wrlock (__libc_setlocale_lock);
      53  
      54    data = current->private;
      55    if (data == NULL)
      56      {
      57        data = calloc (sizeof *data, 1);
      58        if (data == NULL)
      59  	goto out;
      60        current->private = data;
      61      }
      62  
      63    if (! data->era_initialized)
      64      {
      65        size_t new_num_eras = CURRENT_WORD (_NL_TIME_ERA_NUM_ENTRIES);
      66        if (new_num_eras == 0)
      67  	{
      68  	  if (data->eras != NULL)
      69  	    {
      70  	      free (data->eras);
      71  	      data->eras = NULL;
      72  	    }
      73  	}
      74        else
      75  	{
      76  	  struct era_entry *new_eras = data->eras;
      77  
      78  	  if (data->num_eras != new_num_eras)
      79  	    new_eras =
      80  	      (struct era_entry *) realloc (data->eras,
      81  					    new_num_eras
      82  					    * sizeof (struct era_entry));
      83  	  if (new_eras == NULL)
      84  	    {
      85  	      free (data->eras);
      86  	      data->num_eras = 0;
      87  	      data->eras = NULL;
      88  	    }
      89  	  else
      90  	    {
      91  	      const char *ptr = CURRENT (_NL_TIME_ERA_ENTRIES);
      92  	      data->num_eras = new_num_eras;
      93  	      data->eras = new_eras;
      94  
      95  	      for (cnt = 0; cnt < new_num_eras; ++cnt)
      96  		{
      97  		  const char *base_ptr = ptr;
      98  		  memcpy ((void *) (new_eras + cnt), (const void *) ptr,
      99  			  sizeof (uint32_t) * 8);
     100  
     101  		  if (ERA_DATE_CMP(new_eras[cnt].start_date,
     102  				   new_eras[cnt].stop_date))
     103  		    if (new_eras[cnt].direction == (uint32_t) '+')
     104  		      new_eras[cnt].absolute_direction = 1;
     105  		    else
     106  		      new_eras[cnt].absolute_direction = -1;
     107  		  else
     108  		    if (new_eras[cnt].direction == (uint32_t) '+')
     109  		      new_eras[cnt].absolute_direction = -1;
     110  		    else
     111  		      new_eras[cnt].absolute_direction = 1;
     112  
     113  		  /* Skip numeric values.  */
     114  		  ptr += sizeof (uint32_t) * 8;
     115  
     116  		  /* Set and skip era name.  */
     117  		  new_eras[cnt].era_name = ptr;
     118  		  ptr = strchr (ptr, '\0') + 1;
     119  
     120  		  /* Set and skip era format.  */
     121  		  new_eras[cnt].era_format = ptr;
     122  		  ptr = strchr (ptr, '\0') + 1;
     123  
     124  		  ptr += 3 - (((ptr - (const char *) base_ptr) + 3) & 3);
     125  
     126  		  /* Set and skip wide era name.  */
     127  		  new_eras[cnt].era_wname = (wchar_t *) ptr;
     128  		  ptr = (char *) (__wcschr ((wchar_t *) ptr, L'\0') + 1);
     129  
     130  		  /* Set and skip wide era format.  */
     131  		  new_eras[cnt].era_wformat = (wchar_t *) ptr;
     132  		  ptr = (char *) (__wcschr ((wchar_t *) ptr, L'\0') + 1);
     133  		}
     134  	    }
     135  	}
     136  
     137        atomic_store_release (&data->era_initialized, 1);
     138      }
     139  
     140   out:
     141    __libc_rwlock_unlock (__libc_setlocale_lock);
     142    return data;
     143  }
     144  
     145  struct era_entry *
     146  _nl_get_era_entry (const struct tm *tp, struct __locale_data *current)
     147  {
     148    struct lc_time_data *data = _nl_init_era_entries (current);
     149  
     150    if (data != NULL)
     151      {
     152        /* Now compare date with the available eras.  */
     153        const int32_t tdate[3] = { tp->tm_year, tp->tm_mon, tp->tm_mday };
     154        size_t cnt;
     155        for (cnt = 0; cnt < data->num_eras; ++cnt)
     156  	if ((ERA_DATE_CMP (data->eras[cnt].start_date, tdate)
     157  	     && ERA_DATE_CMP (tdate, data->eras[cnt].stop_date))
     158  	    || (ERA_DATE_CMP (data->eras[cnt].stop_date, tdate)
     159  		&& ERA_DATE_CMP (tdate, data->eras[cnt].start_date)))
     160  	  return &data->eras[cnt];
     161      }
     162  
     163    return NULL;
     164  }
     165  
     166  
     167  struct era_entry *
     168  _nl_select_era_entry (int cnt, struct __locale_data *current)
     169  {
     170    struct lc_time_data *data = _nl_init_era_entries (current);
     171    return data == NULL ? NULL : &data->eras[cnt];
     172  }