(root)/
glibc-2.38/
time/
asctime.c
       1  /* Copyright (C) 1991-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include "../locale/localeinfo.h"
      19  #include <errno.h>
      20  #include <limits.h>
      21  #include <stdio.h>
      22  #include <time.h>
      23  
      24  /* This is defined in locale/C-time.c in the GNU libc.  */
      25  extern const struct __locale_data _nl_C_LC_TIME attribute_hidden;
      26  #define ab_day_name(DAY) (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)+(DAY)].string)
      27  #define ab_month_name(MON) (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)+(MON)].string)
      28  
      29  static const char format[] = "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n";
      30  static char result[		 3+1+ 3+1+20+1+20+1+20+1+20+1+20+1 + 1];
      31  
      32  
      33  static char *
      34  asctime_internal (const struct tm *tp, char *buf, size_t buflen)
      35  {
      36    if (tp == NULL)
      37      {
      38        __set_errno (EINVAL);
      39        return NULL;
      40      }
      41  
      42    /* We limit the size of the year which can be printed.  Using the %d
      43       format specifier used the addition of 1900 would overflow the
      44       number and a negative value is printed.  For some architectures we
      45       could in theory use %ld or an evern larger integer format but
      46       this would mean the output needs more space.  This would not be a
      47       problem if the 'asctime_r' interface would be defined sanely and
      48       a buffer size would be passed.  */
      49    if (__glibc_unlikely (tp->tm_year > INT_MAX - 1900))
      50      {
      51      eoverflow:
      52        __set_errno (EOVERFLOW);
      53        return NULL;
      54      }
      55  
      56    int n = __snprintf (buf, buflen, format,
      57  		      (tp->tm_wday < 0 || tp->tm_wday >= 7
      58  		       ? "???" : ab_day_name (tp->tm_wday)),
      59  		      (tp->tm_mon < 0 || tp->tm_mon >= 12
      60  		       ? "???" : ab_month_name (tp->tm_mon)),
      61  		      tp->tm_mday, tp->tm_hour, tp->tm_min,
      62  		      tp->tm_sec, 1900 + tp->tm_year);
      63    if (n < 0)
      64      return NULL;
      65    if (n >= buflen)
      66      goto eoverflow;
      67  
      68    return buf;
      69  }
      70  
      71  
      72  /* Like asctime, but write result to the user supplied buffer.  The
      73     buffer is only guaranteed to be 26 bytes in length.  */
      74  char *
      75  __asctime_r (const struct tm *tp, char *buf)
      76  {
      77    return asctime_internal (tp, buf, 26);
      78  }
      79  weak_alias (__asctime_r, asctime_r)
      80  
      81  
      82  /* Returns a string of the form "Day Mon dd hh:mm:ss yyyy\n"
      83     which is the representation of TP in that form.  */
      84  char *
      85  asctime (const struct tm *tp)
      86  {
      87    return asctime_internal (tp, result, sizeof (result));
      88  }
      89  libc_hidden_def (asctime)