libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2009-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/limits.h> 00020 #include <libexplain/ac/math.h> 00021 #include <libexplain/ac/stdlib.h> 00022 #include <libexplain/ac/string.h> 00023 #include <libexplain/ac/sys/stat.h> /* for UTIME_NOW, etc */ 00024 00025 #include <libexplain/buffer/long.h> 00026 #include <libexplain/buffer/pointer.h> 00027 #include <libexplain/buffer/time_t.h> 00028 #include <libexplain/buffer/timespec.h> 00029 #include <libexplain/is_efault.h> 00030 #include <libexplain/option.h> 00031 00032 00038 static void 00039 print_longish(explain_string_buffer_t *sb, long x) 00040 { 00041 if (x == UTIME_NOW) 00042 { 00043 explain_string_buffer_puts(sb, "UTIME_NOW"); 00044 return; 00045 } 00046 if (x == UTIME_OMIT) 00047 { 00048 explain_string_buffer_puts(sb, "UTIME_OMIT"); 00049 return; 00050 } 00051 explain_buffer_long(sb, x); 00052 } 00053 00054 00055 static void 00056 print(explain_string_buffer_t *sb, const struct timespec *data) 00057 { 00067 if (data->tv_nsec < 0 || data->tv_nsec >= 1000000000L) 00068 { 00069 explain_string_buffer_puts(sb, "{ tv_sec = "); 00070 if 00071 ( 00072 data->tv_sec == 0 00073 && 00074 (data->tv_nsec == UTIME_OMIT || data->tv_nsec == UTIME_NOW) 00075 ) 00076 explain_string_buffer_puts(sb, "0"); 00077 else 00078 explain_buffer_time_t(sb, data->tv_sec); 00079 explain_string_buffer_puts(sb, ", tv_nsec = "); 00080 print_longish(sb, data->tv_nsec); 00081 explain_string_buffer_puts(sb, " }"); 00082 } 00083 else 00084 { 00085 /* 00086 * This is a heuristic to distinguish between event dalta times and 00087 * high-precision system time and date usage. It may need tuning. 00088 */ 00089 if (data->tv_sec < 1000) 00090 { 00091 explain_string_buffer_printf 00092 ( 00093 sb, 00094 "{ %.11g seconds }", 00095 data->tv_sec + 1e-9 * data->tv_nsec 00096 ); 00097 } 00098 else 00099 { 00100 explain_string_buffer_printf 00101 ( 00102 sb, 00103 "{ %11.9f seconds", 00104 data->tv_sec + 1e-9 * data->tv_nsec 00105 ); 00106 if (explain_option_dialect_specific()) 00107 { 00108 struct tm *tmp; 00109 00110 tmp = localtime(&data->tv_sec); 00111 if (tmp) 00112 { 00113 char buffer[200]; 00114 00115 strftime 00116 ( 00117 buffer, 00118 sizeof(buffer), 00119 " \"%a, %Y-%b-%d %H:%M:%S %z\"", 00120 tmp 00121 ); 00122 explain_string_buffer_puts(sb, buffer); 00123 } 00124 } 00125 explain_string_buffer_puts(sb, " }"); 00126 } 00127 } 00128 } 00129 00130 00131 void 00132 explain_buffer_timespec(explain_string_buffer_t *sb, 00133 const struct timespec *data) 00134 { 00135 if (explain_is_efault_pointer(data, sizeof(*data))) 00136 explain_buffer_pointer(sb, data); 00137 else 00138 print(sb, data); 00139 } 00140 00141 00142 void 00143 explain_buffer_timespec_array(explain_string_buffer_t *sb, 00144 const struct timespec *data, unsigned data_size) 00145 { 00146 unsigned j; 00147 00148 if (explain_is_efault_pointer(data, sizeof(*data) * data_size)) 00149 { 00150 explain_buffer_pointer(sb, data); 00151 return; 00152 } 00153 explain_string_buffer_putc(sb, '{'); 00154 for (j = 0; j < data_size; ++j) 00155 { 00156 if (j) 00157 explain_string_buffer_puts(sb, ", "); 00158 print(sb, data + j); 00159 } 00160 explain_string_buffer_putc(sb, '}'); 00161 } 00162 00163 00164 void 00165 explain_parse_timespec_or_die(const char *text, const char *caption, 00166 struct timespec *result) 00167 { 00168 if (0 == strcmp(text, "UTIME_NOW")) 00169 { 00170 result->tv_sec = 0; 00171 result->tv_nsec = UTIME_NOW; 00172 return; 00173 } 00174 if (0 == strcmp(text, "UTIME_OMIT")) 00175 { 00176 result->tv_sec = 0; 00177 result->tv_nsec = UTIME_OMIT; 00178 return; 00179 } 00180 00181 { 00182 char *ep = 0; 00183 double n = strtod(text, &ep); 00184 if (ep != text && !*ep) 00185 { 00186 /* cope with overflow */ 00187 if (n + 0.5 >= MAX_TIME_T) 00188 { 00189 result->tv_sec = MAX_TIME_T; 00190 result->tv_nsec = 0; 00191 return; 00192 } 00193 00194 /* cope with underflow */ 00195 if (n - 0.5 <= MIN_TIME_T) 00196 { 00197 result->tv_sec = MIN_TIME_T; 00198 result->tv_nsec = 0; 00199 return; 00200 } 00201 00202 /* 00203 * Note: tv_sec is signed, but tv_nsec is required to be in 00204 * the range 0..<1e9, because negative values mean something 00205 * else. The floor() function will push negative tv_sec 00206 * values more negative, which means adding the positive 00207 * tv_nsec part brings them back up to the appropriate 00208 * floating point value. 00209 */ 00210 result->tv_sec = floor(n); 00211 result->tv_nsec = floor((n - result->tv_sec) * 1e9 + 0.5); 00212 if (result->tv_nsec >= 1000000000) 00213 { 00214 /* could have overflowed on rounding */ 00215 result->tv_sec++; 00216 result->tv_nsec = 0; 00217 } 00218 return; 00219 } 00220 } 00221 00222 { 00223 time_t n = explain_parse_time_t_or_die(text, caption); 00224 result->tv_sec = n; 00225 result->tv_nsec = 0; 00226 } 00227 } 00228 00229 00230 /* vim: set ts=8 sw=4 et : */