libexplain  1.4.D001
libexplain/buffer/timeval.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008-2011, 2013 Peter Miller
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU Lesser General Public License as
00007  * published by the Free Software Foundation; either version 3 of the
00008  * License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include <libexplain/ac/stdlib.h>
00020 #include <libexplain/ac/string.h>
00021 #include <libexplain/ac/sys/stat.h>
00022 #include <libexplain/ac/sys/time.h>
00023 #include <libexplain/ac/time.h>
00024 #include <libexplain/ac/limits.h>
00025 #include <libexplain/ac/math.h>
00026 
00027 #include <libexplain/buffer/pointer.h>
00028 #include <libexplain/buffer/timeval.h>
00029 #include <libexplain/buffer/time_t.h>
00030 #include <libexplain/is_efault.h>
00031 
00032 
00033 #if 0
00034 #ifndef MAX_TIME_T
00035 #define MAX_TIME_T ((~(time_t)0) >> 1)
00036 #endif
00037 #ifndef MIN_TIME_T
00038 #define MIN_TIME_T (-MAX_TIME_T - 1)
00039 #endif
00040 #endif
00041 
00042 
00043 static void
00044 print(explain_string_buffer_t *sb, const struct timeval *data)
00045 {
00046     if (data->tv_usec == UTIME_NOW)
00047     {
00048         explain_string_buffer_puts(sb, "{ tv_usec = UTIME_NOW }");
00049     }
00050     else if (data->tv_usec == UTIME_OMIT)
00051     {
00052         explain_string_buffer_puts(sb, "{ tv_usec = UTIME_OMIT }");
00053     }
00054     else if (data->tv_usec < 0u || data->tv_usec >= 1000000u)
00055     {
00056         explain_string_buffer_printf
00057         (
00058             sb,
00059             "{ tv_sec = %ld, tv_usec = %ld }",
00060             (long)data->tv_sec,
00061             (long)data->tv_usec
00062         );
00063     }
00064     else
00065     {
00066         /* FIXME: localime? */
00067         explain_string_buffer_printf
00068         (
00069             sb,
00070             "{ %.8g seconds }",
00071             data->tv_sec + 1e-6 * data->tv_usec
00072         );
00073     }
00074 }
00075 
00076 
00077 void
00078 explain_buffer_timeval(explain_string_buffer_t *sb, const struct timeval *data)
00079 {
00080     if (explain_is_efault_pointer(data, sizeof(*data)))
00081         explain_buffer_pointer(sb, data);
00082     else
00083         print(sb, data);
00084 }
00085 
00086 
00087 void
00088 explain_buffer_timeval_array(explain_string_buffer_t *sb,
00089     const struct timeval *data, unsigned data_size)
00090 {
00091     unsigned        j;
00092 
00093     if (explain_is_efault_pointer(data, sizeof(*data) * data_size))
00094     {
00095         explain_buffer_pointer(sb, data);
00096         return;
00097     }
00098     explain_string_buffer_putc(sb, '{');
00099     for (j = 0; j < data_size; ++j)
00100     {
00101         if (j)
00102             explain_string_buffer_puts(sb, ", ");
00103         print(sb, data + j);
00104     }
00105     explain_string_buffer_putc(sb, '}');
00106 }
00107 
00108 
00109 void
00110 explain_parse_timeval_or_die(const char *text, const char *caption,
00111     struct timeval *result)
00112 {
00113     if (0 == strcmp(text, "UTIME_NOW"))
00114     {
00115         result->tv_sec = 0;
00116         result->tv_usec = UTIME_NOW;
00117         return;
00118     }
00119     if (0 == strcmp(text, "UTIME_OMIT"))
00120     {
00121         result->tv_sec = 0;
00122         result->tv_usec = UTIME_OMIT;
00123         return;
00124     }
00125 
00126     {
00127         char *ep = 0;
00128         double n = strtod(text, &ep);
00129         if (ep != text && !*ep)
00130         {
00131             /* cope with overflow */
00132             if (n + 0.5 >= MAX_TIME_T)
00133             {
00134                 result->tv_sec = MAX_TIME_T;
00135                 result->tv_usec = 0;
00136                 return;
00137             }
00138 
00139             /* cope with underflow */
00140             if (n - 0.5 <= MIN_TIME_T)
00141             {
00142                 result->tv_sec = MIN_TIME_T;
00143                 result->tv_usec = 0;
00144                 return;
00145             }
00146 
00147             /*
00148              * Note: tv_sec is signed, but tv_usec is required to be in
00149              * the range 0..<1e6, because negative values mean something
00150              * else.  The floor() function will push negative tv_sec
00151              * values more negative, which means adding the positive
00152              * tv_usec part brings them back up to the appropriate
00153              * floating point value.
00154              */
00155             result->tv_sec = floor(n);
00156             result->tv_usec = floor((n - result->tv_sec) * 1e6 + 0.5);
00157             if (result->tv_usec >= 1000000)
00158             {
00159                 /* could have overflowed on rounding */
00160                 result->tv_sec++;
00161                 result->tv_usec = 0;
00162             }
00163             return;
00164         }
00165     }
00166 
00167     {
00168         time_t n = explain_parse_time_t_or_die(text, caption);
00169         result->tv_sec = n;
00170         result->tv_usec = 0;
00171     }
00172 }
00173 
00174 
00175 /* vim: set ts=8 sw=4 et : */