LCOV - code coverage report
Current view: top level - glib/glib - gtimer.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 160 161 99.4 %
Date: 2024-04-16 05:15:53 Functions: 13 13 100.0 %
Branches: 81 84 96.4 %

           Branch data     Line data    Source code
       1                 :            : /* GLIB - Library of useful routines for C programming
       2                 :            :  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
       3                 :            :  *
       4                 :            :  * SPDX-License-Identifier: LGPL-2.1-or-later
       5                 :            :  *
       6                 :            :  * This library is free software; you can redistribute it and/or
       7                 :            :  * modify it under the terms of the GNU Lesser General Public
       8                 :            :  * License as published by the Free Software Foundation; either
       9                 :            :  * version 2.1 of the License, or (at your option) any later version.
      10                 :            :  *
      11                 :            :  * This library is distributed in the hope that it will be useful,
      12                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14                 :            :  * Lesser General Public License for more details.
      15                 :            :  *
      16                 :            :  * You should have received a copy of the GNU Lesser General Public
      17                 :            :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18                 :            :  */
      19                 :            : 
      20                 :            : /*
      21                 :            :  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
      22                 :            :  * file for a list of people on the GLib Team.  See the ChangeLog
      23                 :            :  * files for a list of changes.  These files are distributed with
      24                 :            :  * GLib at ftp://ftp.gtk.org/pub/gtk/.
      25                 :            :  */
      26                 :            : 
      27                 :            : /*
      28                 :            :  * MT safe
      29                 :            :  */
      30                 :            : 
      31                 :            : #include "config.h"
      32                 :            : #include "glibconfig.h"
      33                 :            : 
      34                 :            : #include <stdlib.h>
      35                 :            : 
      36                 :            : #ifdef G_OS_UNIX
      37                 :            : #include <unistd.h>
      38                 :            : #endif /* G_OS_UNIX */
      39                 :            : 
      40                 :            : #ifdef HAVE_SYS_TIME_H
      41                 :            : #include <sys/time.h>
      42                 :            : #endif
      43                 :            : #include <time.h>
      44                 :            : #ifndef G_OS_WIN32
      45                 :            : #include <errno.h>
      46                 :            : #endif /* G_OS_WIN32 */
      47                 :            : 
      48                 :            : #ifdef G_OS_WIN32
      49                 :            : #include <windows.h>
      50                 :            : #endif /* G_OS_WIN32 */
      51                 :            : 
      52                 :            : #include "gtimer.h"
      53                 :            : 
      54                 :            : #include "gmem.h"
      55                 :            : #include "gstrfuncs.h"
      56                 :            : #include "gtestutils.h"
      57                 :            : #include "gmain.h"
      58                 :            : 
      59                 :            : /**
      60                 :            :  * GTimer:
      61                 :            :  *
      62                 :            :  * `GTimer` records a start time, and counts microseconds elapsed since
      63                 :            :  * that time.
      64                 :            :  *
      65                 :            :  * This is done somewhat differently on different platforms, and can be
      66                 :            :  * tricky to get exactly right, so `GTimer` provides a portable/convenient interface.
      67                 :            :  */
      68                 :            : struct _GTimer
      69                 :            : {
      70                 :            :   guint64 start;
      71                 :            :   guint64 end;
      72                 :            : 
      73                 :            :   guint active : 1;
      74                 :            : };
      75                 :            : 
      76                 :            : /**
      77                 :            :  * g_timer_new: (constructor)
      78                 :            :  *
      79                 :            :  * Creates a new timer, and starts timing (i.e. g_timer_start() is
      80                 :            :  * implicitly called for you).
      81                 :            :  *
      82                 :            :  * Returns: (transfer full): a new #GTimer.
      83                 :            :  **/
      84                 :            : GTimer*
      85                 :       7064 : g_timer_new (void)
      86                 :            : {
      87                 :            :   GTimer *timer;
      88                 :            : 
      89                 :       7064 :   timer = g_new (GTimer, 1);
      90                 :       7064 :   timer->active = TRUE;
      91                 :            : 
      92                 :       7064 :   timer->start = g_get_monotonic_time ();
      93                 :            : 
      94                 :       7064 :   return timer;
      95                 :            : }
      96                 :            : 
      97                 :            : /**
      98                 :            :  * g_timer_destroy:
      99                 :            :  * @timer: a #GTimer to destroy.
     100                 :            :  *
     101                 :            :  * Destroys a timer, freeing associated resources.
     102                 :            :  **/
     103                 :            : void
     104                 :       6937 : g_timer_destroy (GTimer *timer)
     105                 :            : {
     106                 :       6937 :   g_return_if_fail (timer != NULL);
     107                 :            : 
     108                 :       6937 :   g_free (timer);
     109                 :            : }
     110                 :            : 
     111                 :            : /**
     112                 :            :  * g_timer_start:
     113                 :            :  * @timer: a #GTimer.
     114                 :            :  *
     115                 :            :  * Marks a start time, so that future calls to g_timer_elapsed() will
     116                 :            :  * report the time since g_timer_start() was called. g_timer_new()
     117                 :            :  * automatically marks the start time, so no need to call
     118                 :            :  * g_timer_start() immediately after creating the timer.
     119                 :            :  **/
     120                 :            : void
     121                 :       7257 : g_timer_start (GTimer *timer)
     122                 :            : {
     123                 :       7257 :   g_return_if_fail (timer != NULL);
     124                 :            : 
     125                 :       7257 :   timer->active = TRUE;
     126                 :            : 
     127                 :       7257 :   timer->start = g_get_monotonic_time ();
     128                 :            : }
     129                 :            : 
     130                 :            : /**
     131                 :            :  * g_timer_stop:
     132                 :            :  * @timer: a #GTimer.
     133                 :            :  *
     134                 :            :  * Marks an end time, so calls to g_timer_elapsed() will return the
     135                 :            :  * difference between this end time and the start time.
     136                 :            :  **/
     137                 :            : void
     138                 :       7090 : g_timer_stop (GTimer *timer)
     139                 :            : {
     140                 :       7090 :   g_return_if_fail (timer != NULL);
     141                 :            : 
     142                 :       7090 :   timer->active = FALSE;
     143                 :            : 
     144                 :       7090 :   timer->end = g_get_monotonic_time ();
     145                 :            : }
     146                 :            : 
     147                 :            : /**
     148                 :            :  * g_timer_reset:
     149                 :            :  * @timer: a #GTimer.
     150                 :            :  *
     151                 :            :  * This function is useless; it's fine to call g_timer_start() on an
     152                 :            :  * already-started timer to reset the start time, so g_timer_reset()
     153                 :            :  * serves no purpose.
     154                 :            :  **/
     155                 :            : void
     156                 :          5 : g_timer_reset (GTimer *timer)
     157                 :            : {
     158                 :          5 :   g_return_if_fail (timer != NULL);
     159                 :            : 
     160                 :          5 :   timer->start = g_get_monotonic_time ();
     161                 :            : }
     162                 :            : 
     163                 :            : /**
     164                 :            :  * g_timer_continue:
     165                 :            :  * @timer: a #GTimer.
     166                 :            :  *
     167                 :            :  * Resumes a timer that has previously been stopped with
     168                 :            :  * g_timer_stop(). g_timer_stop() must be called before using this
     169                 :            :  * function.
     170                 :            :  *
     171                 :            :  * Since: 2.4
     172                 :            :  **/
     173                 :            : void
     174                 :          2 : g_timer_continue (GTimer *timer)
     175                 :            : {
     176                 :            :   guint64 elapsed;
     177                 :            : 
     178                 :          2 :   g_return_if_fail (timer != NULL);
     179                 :          2 :   g_return_if_fail (timer->active == FALSE);
     180                 :            : 
     181                 :            :   /* Get elapsed time and reset timer start time
     182                 :            :    *  to the current time minus the previously
     183                 :            :    *  elapsed interval.
     184                 :            :    */
     185                 :            : 
     186                 :          1 :   elapsed = timer->end - timer->start;
     187                 :            : 
     188                 :          1 :   timer->start = g_get_monotonic_time ();
     189                 :            : 
     190                 :          1 :   timer->start -= elapsed;
     191                 :            : 
     192                 :          1 :   timer->active = TRUE;
     193                 :            : }
     194                 :            : 
     195                 :            : /**
     196                 :            :  * g_timer_elapsed:
     197                 :            :  * @timer: a #GTimer.
     198                 :            :  * @microseconds: return location for the fractional part of seconds
     199                 :            :  *                elapsed, in microseconds (that is, the total number
     200                 :            :  *                of microseconds elapsed, modulo 1000000), or %NULL
     201                 :            :  *
     202                 :            :  * If @timer has been started but not stopped, obtains the time since
     203                 :            :  * the timer was started. If @timer has been stopped, obtains the
     204                 :            :  * elapsed time between the time it was started and the time it was
     205                 :            :  * stopped. The return value is the number of seconds elapsed,
     206                 :            :  * including any fractional part. The @microseconds out parameter is
     207                 :            :  * essentially useless.
     208                 :            :  *
     209                 :            :  * Returns: seconds elapsed as a floating point value, including any
     210                 :            :  *          fractional part.
     211                 :            :  **/
     212                 :            : gdouble
     213                 :       7249 : g_timer_elapsed (GTimer *timer,
     214                 :            :                  gulong *microseconds)
     215                 :            : {
     216                 :            :   gdouble total;
     217                 :            :   gint64 elapsed;
     218                 :            : 
     219                 :       7249 :   g_return_val_if_fail (timer != NULL, 0);
     220                 :            : 
     221         [ +  + ]:       7249 :   if (timer->active)
     222                 :        178 :     timer->end = g_get_monotonic_time ();
     223                 :            : 
     224                 :       7249 :   elapsed = timer->end - timer->start;
     225                 :            : 
     226                 :       7249 :   total = elapsed / 1e6;
     227                 :            : 
     228         [ +  + ]:       7249 :   if (microseconds)
     229                 :          1 :     *microseconds = elapsed % 1000000;
     230                 :            : 
     231                 :       7249 :   return total;
     232                 :            : }
     233                 :            : 
     234                 :            : /**
     235                 :            :  * g_timer_is_active:
     236                 :            :  * @timer: a #GTimer.
     237                 :            :  * 
     238                 :            :  * Exposes whether the timer is currently active.
     239                 :            :  *
     240                 :            :  * Returns: %TRUE if the timer is running, %FALSE otherwise
     241                 :            :  * Since: 2.62
     242                 :            :  **/
     243                 :            : gboolean
     244                 :          2 : g_timer_is_active (GTimer *timer)
     245                 :            : {
     246                 :          2 :   g_return_val_if_fail (timer != NULL, FALSE);
     247                 :            : 
     248                 :          2 :   return timer->active;
     249                 :            : }
     250                 :            : 
     251                 :            : /**
     252                 :            :  * g_usleep:
     253                 :            :  * @microseconds: number of microseconds to pause
     254                 :            :  *
     255                 :            :  * Pauses the current thread for the given number of microseconds.
     256                 :            :  *
     257                 :            :  * There are 1 million microseconds per second (represented by the
     258                 :            :  * %G_USEC_PER_SEC macro). g_usleep() may have limited precision,
     259                 :            :  * depending on hardware and operating system; don't rely on the exact
     260                 :            :  * length of the sleep.
     261                 :            :  */
     262                 :            : void
     263                 :      76766 : g_usleep (gulong microseconds)
     264                 :            : {
     265         [ +  + ]:      76766 :   if G_UNLIKELY (microseconds == 0)
     266                 :       1187 :     return;
     267                 :            : 
     268                 :            : #ifdef G_OS_WIN32
     269                 :            :   /* Round up to the next millisecond */
     270                 :            :   Sleep (microseconds ? (1 + (microseconds - 1) / 1000) : 0);
     271                 :            : #else
     272                 :            :   struct timespec request, remaining;
     273                 :      75579 :   request.tv_sec = microseconds / G_USEC_PER_SEC;
     274                 :      75579 :   request.tv_nsec = 1000 * (microseconds % G_USEC_PER_SEC);
     275   [ -  +  -  - ]:      75579 :   while (nanosleep (&request, &remaining) == -1 && errno == EINTR)
     276                 :          0 :     request = remaining;
     277                 :            : #endif
     278                 :            : }
     279                 :            : 
     280                 :            : /**
     281                 :            :  * g_time_val_add:
     282                 :            :  * @time_: a #GTimeVal
     283                 :            :  * @microseconds: number of microseconds to add to @time
     284                 :            :  *
     285                 :            :  * Adds the given number of microseconds to @time_. @microseconds can
     286                 :            :  * also be negative to decrease the value of @time_.
     287                 :            :  *
     288                 :            :  * Deprecated: 2.62: #GTimeVal is not year-2038-safe. Use `guint64` for
     289                 :            :  *    representing microseconds since the epoch, or use #GDateTime.
     290                 :            :  **/
     291                 :            : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     292                 :            : void 
     293                 :          7 : g_time_val_add (GTimeVal *time_, glong microseconds)
     294                 :            : {
     295                 :          7 :   g_return_if_fail (time_ != NULL &&
     296                 :            :                     time_->tv_usec >= 0 &&
     297                 :            :                     time_->tv_usec < G_USEC_PER_SEC);
     298                 :            : 
     299         [ +  + ]:          7 :   if (microseconds >= 0)
     300                 :            :     {
     301                 :          5 :       time_->tv_usec += microseconds % G_USEC_PER_SEC;
     302                 :          5 :       time_->tv_sec += microseconds / G_USEC_PER_SEC;
     303         [ +  + ]:          5 :       if (time_->tv_usec >= G_USEC_PER_SEC)
     304                 :            :        {
     305                 :          1 :          time_->tv_usec -= G_USEC_PER_SEC;
     306                 :          1 :          time_->tv_sec++;
     307                 :            :        }
     308                 :            :     }
     309                 :            :   else
     310                 :            :     {
     311                 :          2 :       microseconds *= -1;
     312                 :          2 :       time_->tv_usec -= microseconds % G_USEC_PER_SEC;
     313                 :          2 :       time_->tv_sec -= microseconds / G_USEC_PER_SEC;
     314         [ +  + ]:          2 :       if (time_->tv_usec < 0)
     315                 :            :        {
     316                 :          1 :          time_->tv_usec += G_USEC_PER_SEC;
     317                 :          1 :          time_->tv_sec--;
     318                 :            :        }      
     319                 :            :     }
     320                 :            : }
     321                 :            : G_GNUC_END_IGNORE_DEPRECATIONS
     322                 :            : 
     323                 :            : /* converts a broken down date representation, relative to UTC,
     324                 :            :  * to a timestamp; it uses timegm() if it's available.
     325                 :            :  */
     326                 :            : static time_t
     327                 :         48 : mktime_utc (struct tm *tm)
     328                 :            : {
     329                 :            :   time_t retval;
     330                 :            :   
     331                 :            : #ifndef HAVE_TIMEGM
     332                 :            :   static const gint days_before[] =
     333                 :            :   {
     334                 :            :     0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
     335                 :            :   };
     336                 :            : #endif
     337                 :            : 
     338                 :            : #ifndef HAVE_TIMEGM
     339                 :            :   if (tm->tm_mon < 0 || tm->tm_mon > 11)
     340                 :            :     return (time_t) -1;
     341                 :            : 
     342                 :            :   retval = (tm->tm_year - 70) * 365;
     343                 :            :   retval += (tm->tm_year - 68) / 4;
     344                 :            :   retval += days_before[tm->tm_mon] + tm->tm_mday - 1;
     345                 :            :   
     346                 :            :   if (tm->tm_year % 4 == 0 && tm->tm_mon < 2)
     347                 :            :     retval -= 1;
     348                 :            :   
     349                 :            :   retval = ((((retval * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60 + tm->tm_sec;
     350                 :            : #else
     351                 :         48 :   retval = timegm (tm);
     352                 :            : #endif /* !HAVE_TIMEGM */
     353                 :            :   
     354                 :         48 :   return retval;
     355                 :            : }
     356                 :            : 
     357                 :            : /**
     358                 :            :  * g_time_val_from_iso8601:
     359                 :            :  * @iso_date: an ISO 8601 encoded date string
     360                 :            :  * @time_: (out): a #GTimeVal
     361                 :            :  *
     362                 :            :  * Converts a string containing an ISO 8601 encoded date and time
     363                 :            :  * to a #GTimeVal and puts it into @time_.
     364                 :            :  *
     365                 :            :  * @iso_date must include year, month, day, hours, minutes, and
     366                 :            :  * seconds. It can optionally include fractions of a second and a time
     367                 :            :  * zone indicator. (In the absence of any time zone indication, the
     368                 :            :  * timestamp is assumed to be in local time.)
     369                 :            :  *
     370                 :            :  * Any leading or trailing space in @iso_date is ignored.
     371                 :            :  *
     372                 :            :  * This function was deprecated, along with #GTimeVal itself, in GLib 2.62.
     373                 :            :  * Equivalent functionality is available using code like:
     374                 :            :  * |[
     375                 :            :  * GDateTime *dt = g_date_time_new_from_iso8601 (iso8601_string, NULL);
     376                 :            :  * gint64 time_val = g_date_time_to_unix (dt);
     377                 :            :  * g_date_time_unref (dt);
     378                 :            :  * ]|
     379                 :            :  *
     380                 :            :  * Returns: %TRUE if the conversion was successful.
     381                 :            :  *
     382                 :            :  * Since: 2.12
     383                 :            :  * Deprecated: 2.62: #GTimeVal is not year-2038-safe. Use
     384                 :            :  *    g_date_time_new_from_iso8601() instead.
     385                 :            :  */
     386                 :            : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     387                 :            : gboolean
     388                 :        124 : g_time_val_from_iso8601 (const gchar *iso_date,
     389                 :            :                          GTimeVal    *time_)
     390                 :            : {
     391                 :        124 :   struct tm tm = {0};
     392                 :            :   long val;
     393                 :            :   long mday, mon, year;
     394                 :            :   long hour, min, sec;
     395                 :            : 
     396                 :        124 :   g_return_val_if_fail (iso_date != NULL, FALSE);
     397                 :        124 :   g_return_val_if_fail (time_ != NULL, FALSE);
     398                 :            : 
     399                 :            :   /* Ensure that the first character is a digit, the first digit
     400                 :            :    * of the date, otherwise we don't have an ISO 8601 date
     401                 :            :    */
     402         [ +  + ]:        134 :   while (g_ascii_isspace (*iso_date))
     403                 :         10 :     iso_date++;
     404                 :            : 
     405         [ +  + ]:        124 :   if (*iso_date == '\0')
     406                 :          2 :     return FALSE;
     407                 :            : 
     408   [ +  +  +  + ]:        122 :   if (!g_ascii_isdigit (*iso_date) && *iso_date != '+')
     409                 :          6 :     return FALSE;
     410                 :            : 
     411                 :        116 :   val = strtoul (iso_date, (char **)&iso_date, 10);
     412         [ +  + ]:        116 :   if (*iso_date == '-')
     413                 :            :     {
     414                 :            :       /* YYYY-MM-DD */
     415                 :         76 :       year = val;
     416                 :         76 :       iso_date++;
     417                 :            : 
     418                 :         76 :       mon = strtoul (iso_date, (char **)&iso_date, 10);
     419         [ +  + ]:         76 :       if (*iso_date++ != '-')
     420                 :          2 :         return FALSE;
     421                 :            :       
     422                 :         74 :       mday = strtoul (iso_date, (char **)&iso_date, 10);
     423                 :            :     }
     424                 :            :   else
     425                 :            :     {
     426                 :            :       /* YYYYMMDD */
     427                 :         40 :       mday = val % 100;
     428                 :         40 :       mon = (val % 10000) / 100;
     429                 :         40 :       year = val / 10000;
     430                 :            :     }
     431                 :            : 
     432                 :            :   /* Validation. */
     433   [ +  +  +  + ]:        114 :   if (year < 1900 || year > G_MAXINT)
     434                 :          8 :     return FALSE;
     435   [ +  +  +  + ]:        106 :   if (mon < 1 || mon > 12)
     436                 :          8 :     return FALSE;
     437   [ +  +  +  + ]:         98 :   if (mday < 1 || mday > 31)
     438                 :          8 :     return FALSE;
     439                 :            : 
     440                 :         90 :   tm.tm_mday = mday;
     441                 :         90 :   tm.tm_mon = mon - 1;
     442                 :         90 :   tm.tm_year = year - 1900;
     443                 :            : 
     444         [ +  + ]:         90 :   if (*iso_date != 'T')
     445                 :          8 :     return FALSE;
     446                 :            : 
     447                 :         82 :   iso_date++;
     448                 :            : 
     449                 :            :   /* If there is a 'T' then there has to be a time */
     450         [ +  + ]:         82 :   if (!g_ascii_isdigit (*iso_date))
     451                 :          4 :     return FALSE;
     452                 :            : 
     453                 :         78 :   val = strtoul (iso_date, (char **)&iso_date, 10);
     454         [ +  + ]:         78 :   if (*iso_date == ':')
     455                 :            :     {
     456                 :            :       /* hh:mm:ss */
     457                 :         52 :       hour = val;
     458                 :         52 :       iso_date++;
     459                 :         52 :       min = strtoul (iso_date, (char **)&iso_date, 10);
     460                 :            :       
     461         [ +  + ]:         52 :       if (*iso_date++ != ':')
     462                 :          2 :         return FALSE;
     463                 :            :       
     464                 :         50 :       sec = strtoul (iso_date, (char **)&iso_date, 10);
     465                 :            :     }
     466                 :            :   else
     467                 :            :     {
     468                 :            :       /* hhmmss */
     469                 :         26 :       sec = val % 100;
     470                 :         26 :       min = (val % 10000) / 100;
     471                 :         26 :       hour = val / 10000;
     472                 :            :     }
     473                 :            : 
     474                 :            :   /* Validation. Allow up to 2 leap seconds when validating @sec. */
     475         [ +  + ]:         76 :   if (hour > 23)
     476                 :          4 :     return FALSE;
     477         [ +  + ]:         72 :   if (min > 59)
     478                 :          4 :     return FALSE;
     479         [ +  + ]:         68 :   if (sec > 61)
     480                 :          4 :     return FALSE;
     481                 :            : 
     482                 :         64 :   tm.tm_hour = hour;
     483                 :         64 :   tm.tm_min = min;
     484                 :         64 :   tm.tm_sec = sec;
     485                 :            : 
     486                 :         64 :   time_->tv_usec = 0;
     487                 :            :   
     488   [ +  +  +  + ]:         64 :   if (*iso_date == ',' || *iso_date == '.')
     489                 :            :     {
     490                 :         33 :       glong mul = 100000;
     491                 :            : 
     492   [ +  +  +  + ]:        207 :       while (mul >= 1 && g_ascii_isdigit (*++iso_date))
     493                 :            :         {
     494                 :        174 :           time_->tv_usec += (*iso_date - '0') * mul;
     495                 :        174 :           mul /= 10;
     496                 :            :         }
     497                 :            : 
     498                 :            :       /* Skip any remaining digits after we’ve reached our limit of precision. */
     499         [ +  + ]:        118 :       while (g_ascii_isdigit (*iso_date))
     500                 :         85 :         iso_date++;
     501                 :            :     }
     502                 :            :     
     503                 :            :   /* Now parse the offset and convert tm to a time_t */
     504         [ +  + ]:         64 :   if (*iso_date == 'Z')
     505                 :            :     {
     506                 :         20 :       iso_date++;
     507                 :         20 :       time_->tv_sec = mktime_utc (&tm);
     508                 :            :     }
     509   [ +  +  +  + ]:         44 :   else if (*iso_date == '+' || *iso_date == '-')
     510                 :         28 :     {
     511         [ +  + ]:         36 :       gint sign = (*iso_date == '+') ? -1 : 1;
     512                 :            :       
     513                 :         36 :       val = strtoul (iso_date + 1, (char **)&iso_date, 10);
     514                 :            :       
     515         [ +  + ]:         36 :       if (*iso_date == ':')
     516                 :            :         {
     517                 :            :           /* hh:mm */
     518                 :         20 :           hour = val;
     519                 :         20 :           min = strtoul (iso_date + 1, (char **)&iso_date, 10);
     520                 :            :         }
     521                 :            :       else
     522                 :            :         {
     523                 :            :           /* hhmm */
     524                 :         16 :           hour = val / 100;
     525                 :         16 :           min = val % 100;
     526                 :            :         }
     527                 :            : 
     528         [ +  + ]:         36 :       if (hour > 99)
     529                 :          4 :         return FALSE;
     530         [ +  + ]:         32 :       if (min > 59)
     531                 :          4 :         return FALSE;
     532                 :            : 
     533                 :         28 :       time_->tv_sec = mktime_utc (&tm) + (time_t) (60 * (gint64) (60 * hour + min) * sign);
     534                 :            :     }
     535                 :            :   else
     536                 :            :     {
     537                 :            :       /* No "Z" or offset, so local time */
     538                 :          8 :       tm.tm_isdst = -1; /* locale selects DST */
     539                 :          8 :       time_->tv_sec = mktime (&tm);
     540                 :            :     }
     541                 :            : 
     542         [ +  + ]:         72 :   while (g_ascii_isspace (*iso_date))
     543                 :         16 :     iso_date++;
     544                 :            : 
     545                 :         56 :   return *iso_date == '\0';
     546                 :            : }
     547                 :            : G_GNUC_END_IGNORE_DEPRECATIONS
     548                 :            : 
     549                 :            : /**
     550                 :            :  * g_time_val_to_iso8601:
     551                 :            :  * @time_: a #GTimeVal
     552                 :            :  * 
     553                 :            :  * Converts @time_ into an RFC 3339 encoded string, relative to the
     554                 :            :  * Coordinated Universal Time (UTC). This is one of the many formats
     555                 :            :  * allowed by ISO 8601.
     556                 :            :  *
     557                 :            :  * ISO 8601 allows a large number of date/time formats, with or without
     558                 :            :  * punctuation and optional elements. The format returned by this function
     559                 :            :  * is a complete date and time, with optional punctuation included, the
     560                 :            :  * UTC time zone represented as "Z", and the @tv_usec part included if
     561                 :            :  * and only if it is nonzero, i.e. either
     562                 :            :  * "YYYY-MM-DDTHH:MM:SSZ" or "YYYY-MM-DDTHH:MM:SS.fffffZ".
     563                 :            :  *
     564                 :            :  * This corresponds to the Internet date/time format defined by
     565                 :            :  * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt),
     566                 :            :  * and to either of the two most-precise formats defined by
     567                 :            :  * the W3C Note
     568                 :            :  * [Date and Time Formats](http://www.w3.org/TR/NOTE-datetime-19980827).
     569                 :            :  * Both of these documents are profiles of ISO 8601.
     570                 :            :  *
     571                 :            :  * Use g_date_time_format() or g_strdup_printf() if a different
     572                 :            :  * variation of ISO 8601 format is required.
     573                 :            :  *
     574                 :            :  * If @time_ represents a date which is too large to fit into a `struct tm`,
     575                 :            :  * %NULL will be returned. This is platform dependent. Note also that since
     576                 :            :  * `GTimeVal` stores the number of seconds as a `glong`, on 32-bit systems it
     577                 :            :  * is subject to the year 2038 problem. Accordingly, since GLib 2.62, this
     578                 :            :  * function has been deprecated. Equivalent functionality is available using:
     579                 :            :  * |[
     580                 :            :  * GDateTime *dt = g_date_time_new_from_unix_utc (time_val);
     581                 :            :  * iso8601_string = g_date_time_format_iso8601 (dt);
     582                 :            :  * g_date_time_unref (dt);
     583                 :            :  * ]|
     584                 :            :  *
     585                 :            :  * The return value of g_time_val_to_iso8601() has been nullable since GLib
     586                 :            :  * 2.54; before then, GLib would crash under the same conditions.
     587                 :            :  *
     588                 :            :  * Returns: (nullable): a newly allocated string containing an ISO 8601 date,
     589                 :            :  *    or %NULL if @time_ was too large
     590                 :            :  *
     591                 :            :  * Since: 2.12
     592                 :            :  * Deprecated: 2.62: #GTimeVal is not year-2038-safe. Use
     593                 :            :  *    g_date_time_format_iso8601(dt) instead.
     594                 :            :  */
     595                 :            : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     596                 :            : gchar *
     597                 :          3 : g_time_val_to_iso8601 (GTimeVal *time_)
     598                 :            : {
     599                 :            :   gchar *retval;
     600                 :            :   struct tm *tm;
     601                 :            : #ifdef HAVE_GMTIME_R
     602                 :            :   struct tm tm_;
     603                 :            : #endif
     604                 :            :   time_t secs;
     605                 :            : 
     606                 :          3 :   g_return_val_if_fail (time_ != NULL &&
     607                 :            :                         time_->tv_usec >= 0 &&
     608                 :            :                         time_->tv_usec < G_USEC_PER_SEC, NULL);
     609                 :            : 
     610                 :          3 :   secs = time_->tv_sec;
     611                 :            : #ifdef _WIN32
     612                 :            :   tm = gmtime (&secs);
     613                 :            : #else
     614                 :            : #ifdef HAVE_GMTIME_R
     615                 :          3 :   tm = gmtime_r (&secs, &tm_);
     616                 :            : #else
     617                 :            :   tm = gmtime (&secs);
     618                 :            : #endif
     619                 :            : #endif
     620                 :            : 
     621                 :            :   /* If the gmtime() call has failed, time_->tv_sec is too big. */
     622         [ +  + ]:          3 :   if (tm == NULL)
     623                 :          1 :     return NULL;
     624                 :            : 
     625         [ +  + ]:          2 :   if (time_->tv_usec != 0)
     626                 :            :     {
     627                 :            :       /* ISO 8601 date and time format, with fractionary seconds:
     628                 :            :        *   YYYY-MM-DDTHH:MM:SS.MMMMMMZ
     629                 :            :        */
     630                 :          1 :       retval = g_strdup_printf ("%4d-%02d-%02dT%02d:%02d:%02d.%06ldZ",
     631                 :          1 :                                 tm->tm_year + 1900,
     632                 :          1 :                                 tm->tm_mon + 1,
     633                 :            :                                 tm->tm_mday,
     634                 :            :                                 tm->tm_hour,
     635                 :            :                                 tm->tm_min,
     636                 :            :                                 tm->tm_sec,
     637                 :            :                                 time_->tv_usec);
     638                 :            :     }
     639                 :            :   else
     640                 :            :     {
     641                 :            :       /* ISO 8601 date and time format:
     642                 :            :        *   YYYY-MM-DDTHH:MM:SSZ
     643                 :            :        */
     644                 :          1 :       retval = g_strdup_printf ("%4d-%02d-%02dT%02d:%02d:%02dZ",
     645                 :          1 :                                 tm->tm_year + 1900,
     646                 :          1 :                                 tm->tm_mon + 1,
     647                 :            :                                 tm->tm_mday,
     648                 :            :                                 tm->tm_hour,
     649                 :            :                                 tm->tm_min,
     650                 :            :                                 tm->tm_sec);
     651                 :            :     }
     652                 :            :   
     653                 :          2 :   return retval;
     654                 :            : }
     655                 :            : G_GNUC_END_IGNORE_DEPRECATIONS

Generated by: LCOV version 1.14