libexplain  1.4.D001
libexplain/buffer/time_t/parse.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2009, 2012, 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/assert.h>
00020 #include <libexplain/ac/ctype.h>
00021 #include <libexplain/ac/stdio.h>
00022 #include <libexplain/ac/stdlib.h>
00023 #include <libexplain/ac/string.h>
00024 
00025 #include <libexplain/buffer/time_t.h>
00026 #include <libexplain/output.h>
00027 #include <libexplain/sizeof.h>
00028 
00029 
00030 #define YEAR_BIT  (1 << 0)
00031 #define MONTH_BIT (1 << 1)
00032 #define MDAY_BIT  (1 << 2)
00033 #define HOUR_BIT  (1 << 3)
00034 #define MIN_BIT   (1 << 4)
00035 #define SEC_BIT   (1 << 5)
00036 
00037 
00038 static int
00039 all_digits(const char *text)
00040 {
00041     if (!*text)
00042         return 0;
00043     for (;;)
00044     {
00045         unsigned char c = *text++;
00046         if (!c)
00047             return 1;
00048         if (!isdigit(c))
00049             return 0;
00050     }
00051 }
00052 
00053 
00054 static unsigned
00055 pull(const char *text, size_t len)
00056 {
00057     unsigned        n;
00058 
00059     n = 0;
00060     while (len > 0)
00061     {
00062         unsigned char c = *text++;
00063         assert(isdigit(c));
00064         n = n * 10 + c - '0';
00065         --len;
00066     }
00067     return n;
00068 }
00069 
00070 
00071 static int
00072 correct_year(const struct tm *build, int year)
00073 {
00074     int             century;
00075 
00076     if (year >= 100)
00077         return (year - 1900);
00078     century = 0;
00079     for (;;)
00080     {
00081         if (abs(year + century - build->tm_year) <= 50)
00082             return (year + century);
00083         century += 100;
00084     }
00085 }
00086 
00087 
00088 static time_t
00089 explain_parse_time_t(const char *text)
00090 {
00091     static struct tm tzero;
00092     struct tm       build;
00093     unsigned        numbers[6];
00094     unsigned char   masks[SIZEOF(numbers)];
00095     time_t          now;
00096     unsigned        nnum;
00097 
00098     build = tzero;
00099     if (time(&now) != (time_t)(-1))
00100     {
00101         struct tm       *tmp;
00102 
00103         tmp = localtime(&now);
00104         if (tmp)
00105             build = *tmp;
00106     }
00107 
00108     if (all_digits(text))
00109     {
00110         size_t          len;
00111 
00112         len = strlen(text);
00113         if (len == 12)
00114         {
00115             build.tm_year = correct_year(&build, pull(text, 2));
00116             build.tm_mon = pull(text + 2, 2) - 1;
00117             if (build.tm_mon < 0 || build.tm_mon >= 12)
00118                 return -1;
00119             build.tm_mday = pull(text + 4, 2);
00120             if (build.tm_mday < 1 || build.tm_mday > 31)
00121                 return -1;
00122             build.tm_hour = pull(text + 6, 2);
00123             if (build.tm_hour >= 24)
00124                 return -1;
00125             build.tm_min = pull(text + 8, 2);
00126             if (build.tm_min >= 60)
00127                 return -1;
00128             build.tm_sec = pull(text + 10, 2);
00129             if (build.tm_sec >= 62)
00130                 return -1;
00131             return mktime(&build);
00132         }
00133 
00134         if (len == 14)
00135         {
00136             build.tm_year = pull(text, 4) - 1900;
00137             if (build.tm_year < 0 || build.tm_year > 200)
00138                 return -1;
00139             build.tm_mon = pull(text + 4, 2) - 1;
00140             if (build.tm_mon < 0 || build.tm_mon >= 12)
00141                 return -1;
00142             build.tm_mday = pull(text + 6, 2);
00143             if (build.tm_mday < 1 || build.tm_mday > 31)
00144                 return -1;
00145             build.tm_hour = pull(text + 8, 2);
00146             if (build.tm_hour >= 24)
00147                 return -1;
00148             build.tm_min = pull(text + 10, 2);
00149             if (build.tm_min >= 60)
00150                 return -1;
00151             build.tm_sec = pull(text + 12, 2);
00152             if (build.tm_sec >= 62)
00153                 return -1;
00154             return mktime(&build);
00155         }
00156 
00157         return strtol(text, 0, 10);
00158     }
00159 
00160     /*
00161      * Break the string into a bunch of numbers,
00162      * looking for patterns.
00163      */
00164     nnum = 0;
00165     while (nnum < SIZEOF(numbers))
00166     {
00167         unsigned char c = *text++;
00168         if (!c)
00169             break;
00170         switch (c)
00171         {
00172         case '0': case '1': case '2': case '3': case '4':
00173         case '5': case '6': case '7': case '8': case '9':
00174             {
00175                 unsigned        n;
00176                 unsigned char   mask;
00177                 unsigned        ndig;
00178 
00179                 n = 0;
00180                 ndig = 0;
00181                 for (;;)
00182                 {
00183                     n = n * 10 + c - '0';
00184                     ++ndig;
00185                     c = *text++;
00186                     switch (c)
00187                     {
00188                     case '0': case '1': case '2': case '3': case '4':
00189                     case '5': case '6': case '7': case '8': case '9':
00190                         continue;
00191 
00192                     default:
00193                         --text;
00194                         break;
00195                     }
00196                     break;
00197                 }
00198 
00199                 /*
00200                  * If the number is stupidly large just bail,
00201                  * because it can't be any part of a valid date.
00202                  */
00203                 if (n >= 2100)
00204                     return -1;
00205 
00206                 mask = 0;
00207                 if (n < 100 && ndig == 2)
00208                     mask |= YEAR_BIT;
00209                 if (n >= 1900 && n < 2100)
00210                     mask |= YEAR_BIT;
00211                 if (n >= 1 && n <= 12)
00212                     mask |= MONTH_BIT;
00213                 if (n >= 1 && n <= 31)
00214                     mask |= MDAY_BIT;
00215                 if (ndig == 2 && n < 24)
00216                     mask |= HOUR_BIT;
00217                 if (ndig == 2 && n < 60)
00218                     mask |= MIN_BIT;
00219                 if (ndig == 2 && n <= 61)
00220                     mask |= SEC_BIT;
00221 
00222                 if (mask)
00223                 {
00224                     numbers[nnum] = n;
00225                     masks[nnum] = mask;
00226                     ++nnum;
00227                 }
00228             }
00229             break;
00230 
00231         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
00232         case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
00233         case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
00234         case 'v': case 'w': case 'x': case 'y': case 'z':
00235         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
00236         case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
00237         case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
00238         case 'V': case 'W': case 'X': case 'Y': case 'Z':
00239             {
00240                 char            name[30];
00241                 char            *cp;
00242                 struct tm       probe;
00243                 int             m;
00244 
00245                 cp = name;
00246                 for (;;)
00247                 {
00248                     if (cp < ENDOF(name) - 1)
00249                         *cp++ = c;
00250                     c = *text++;
00251                     switch (c)
00252                     {
00253                     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
00254                     case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
00255                     case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
00256                     case 's': case 't': case 'u': case 'v': case 'w': case 'x':
00257                     case 'y': case 'z':
00258                     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
00259                     case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
00260                     case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
00261                     case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
00262                     case 'Y': case 'Z':
00263                         continue;
00264 
00265                     default:
00266                         --text;
00267                         break;
00268                     }
00269                     break;
00270                 }
00271                 *cp = '\0';
00272 
00273                 /*
00274                  * Now look at possibilities for the month name.  If
00275                  * name doesn't match anything, throw it away (it is
00276                  * probably a weekday name or a timezone name).
00277                  */
00278                 probe = tzero;
00279                 probe.tm_year = 80;
00280                 for (m = 1; m <= 12; ++m)
00281                 {
00282                     char            candidate[sizeof(name)];
00283 
00284                     probe.tm_mon = m - 1;
00285                     strftime(candidate, sizeof(candidate), "%b", &probe);
00286                     if (strcasecmp(name, candidate) == 0)
00287                     {
00288                         numbers[nnum] = m;
00289                         masks[nnum] = MONTH_BIT;
00290                         ++nnum;
00291                         break;
00292                     }
00293                     strftime(candidate, sizeof(candidate), "%B", &probe);
00294                     if (strcasecmp(name, candidate) == 0)
00295                     {
00296                         numbers[nnum] = m;
00297                         masks[nnum] = MONTH_BIT;
00298                         ++nnum;
00299                         break;
00300                     }
00301                 }
00302             }
00303             break;
00304 
00305         default:
00306             /* throw away all white space and punctuation */
00307             break;
00308         }
00309     }
00310 
00311 #if 0
00312     {
00313         unsigned        n;
00314 
00315         /*
00316          * This debug is too useful to just throw away.
00317          */
00318         for (n = 0; n < nnum; ++n)
00319         {
00320             char m[10];
00321             char *mp = m;
00322             int mask = masks[n];
00323             if (mask & YEAR_BIT) *mp++ = 'Y';
00324             if (mask & MONTH_BIT) *mp++ = 'm';
00325             if (mask & MDAY_BIT) *mp++ = 'd';
00326             if (mask & HOUR_BIT) *mp++ = 'H';
00327             if (mask & MIN_BIT) *mp++ = 'M';
00328             if (mask & SEC_BIT) *mp++ = 'S';
00329             *mp = '\0';
00330             fprintf
00331             (
00332                 stderr,
00333                 "%s: %d: %4d %s\n",
00334                 __FILE__,
00335                 __LINE__,
00336                 numbers[n],
00337                 m
00338             );
00339         }
00340     }
00341 #endif
00342 
00343     if (nnum == 6)
00344     {
00345         /* %Y%m%d%H%M%S */
00346         if
00347         (
00348             (masks[0] & YEAR_BIT)
00349         &&
00350             (masks[1] & MONTH_BIT)
00351         &&
00352             (masks[2] & MDAY_BIT)
00353         &&
00354             (masks[3] & HOUR_BIT)
00355         &&
00356             (masks[4] & MIN_BIT)
00357         &&
00358             (masks[5] & SEC_BIT)
00359         )
00360         {
00361             build.tm_year = correct_year(&build, numbers[0]);
00362             build.tm_mon = numbers[1] - 1;
00363             build.tm_mday = numbers[2];
00364             build.tm_hour = numbers[3];
00365             build.tm_min = numbers[4];
00366             build.tm_sec = numbers[5];
00367             return mktime(&build);
00368         }
00369 
00370         /* %m%d%Y%H%M%S */
00371         if
00372         (
00373             ((masks[0] & MONTH_BIT) && (masks[1] & MDAY_BIT))
00374         &&
00375             /* avoid ambiguity */
00376             !((masks[0] & MDAY_BIT) && (masks[1] & MONTH_BIT))
00377         &&
00378             (masks[2] & YEAR_BIT)
00379         &&
00380             (masks[3] & HOUR_BIT)
00381         &&
00382             (masks[4] & MIN_BIT)
00383         &&
00384             (masks[5] & SEC_BIT)
00385         )
00386         {
00387             build.tm_mon = numbers[0] - 1;
00388             build.tm_mday = numbers[1];
00389             build.tm_year = correct_year(&build, numbers[2]);
00390             build.tm_hour = numbers[3];
00391             build.tm_min = numbers[4];
00392             build.tm_sec = numbers[5];
00393             return mktime(&build);
00394         }
00395 
00396         /* %d%m%Y%H%M%S */
00397         if
00398         (
00399             ((masks[0] & MDAY_BIT) && (masks[1] & MONTH_BIT))
00400         &&
00401             /* avoid ambiguity */
00402             !((masks[0] & MONTH_BIT) && (masks[1] & MDAY_BIT))
00403         &&
00404             (masks[2] & YEAR_BIT)
00405         &&
00406             (masks[3] & HOUR_BIT)
00407         &&
00408             (masks[4] & MIN_BIT)
00409         &&
00410             (masks[5] & SEC_BIT)
00411         )
00412         {
00413             build.tm_mday = numbers[0];
00414             build.tm_mon = numbers[1] - 1;
00415             build.tm_year = correct_year(&build, numbers[2]);
00416             build.tm_hour = numbers[3];
00417             build.tm_min = numbers[4];
00418             build.tm_sec = numbers[5];
00419             return mktime(&build);
00420         }
00421 
00422         /* %d%m%H%M%S%Y */
00423         if
00424         (
00425             ((masks[0] & MDAY_BIT) && (masks[1] & MONTH_BIT))
00426         &&
00427             /* avoid ambiguity */
00428             !((masks[0] & MONTH_BIT) && (masks[1] & MDAY_BIT))
00429         &&
00430             (masks[2] & HOUR_BIT)
00431         &&
00432             (masks[3] & MIN_BIT)
00433         &&
00434             (masks[4] & SEC_BIT)
00435         &&
00436             (masks[5] & YEAR_BIT)
00437         )
00438         {
00439             build.tm_mday = numbers[0];
00440             build.tm_mon = numbers[1] - 1;
00441             build.tm_hour = numbers[2];
00442             build.tm_min = numbers[3];
00443             build.tm_sec = numbers[4];
00444             build.tm_year = correct_year(&build, numbers[5]);
00445             return mktime(&build);
00446         }
00447 
00448         /* %m%d%H%M%S%Y */
00449         if
00450         (
00451             ((masks[0] & MONTH_BIT) && (masks[1] & MDAY_BIT))
00452         &&
00453             /* avoid ambiguity */
00454             !((masks[0] & MDAY_BIT) && (masks[1] & MONTH_BIT))
00455         &&
00456             (masks[2] & HOUR_BIT)
00457         &&
00458             (masks[3] & MIN_BIT)
00459         &&
00460             (masks[4] & SEC_BIT)
00461         &&
00462             (masks[5] & YEAR_BIT)
00463         )
00464         {
00465             build.tm_mon = numbers[0] - 1;
00466             build.tm_mday = numbers[1];
00467             build.tm_hour = numbers[2];
00468             build.tm_min = numbers[3];
00469             build.tm_sec = numbers[4];
00470             build.tm_year = correct_year(&build, numbers[5]);
00471             return mktime(&build);
00472         }
00473 
00474         /* dunno */
00475         return -1;
00476     }
00477     if (nnum == 5)
00478     {
00479         /* %Y%m%d%H%M */
00480         if
00481         (
00482             (masks[0] & YEAR_BIT)
00483         &&
00484             (masks[1] & MONTH_BIT)
00485         &&
00486             (masks[2] & MDAY_BIT)
00487         &&
00488             (masks[3] & HOUR_BIT)
00489         &&
00490             (masks[4] & MIN_BIT)
00491         )
00492         {
00493             build.tm_year = correct_year(&build, numbers[0]);
00494             build.tm_mon = numbers[1] - 1;
00495             build.tm_mday = numbers[2];
00496             build.tm_hour = numbers[3];
00497             build.tm_min = numbers[4];
00498             build.tm_sec = 0;
00499             return mktime(&build);
00500         }
00501 
00502         /* %m%d%Y%H%M */
00503         if
00504         (
00505             ((masks[0] & MONTH_BIT) && (masks[1] & MDAY_BIT))
00506         &&
00507             /* avoid ambiguity */
00508             !((masks[0] & MDAY_BIT) && (masks[1] & MONTH_BIT))
00509         &&
00510             (masks[2] & YEAR_BIT)
00511         &&
00512             (masks[3] & HOUR_BIT)
00513         &&
00514             (masks[4] & MIN_BIT)
00515         )
00516         {
00517             build.tm_mon = numbers[0] - 1;
00518             build.tm_mday = numbers[1];
00519             build.tm_year = correct_year(&build, numbers[2]);
00520             build.tm_hour = numbers[3];
00521             build.tm_min = numbers[4];
00522             build.tm_sec = 0;
00523             return mktime(&build);
00524         }
00525 
00526         /* %d%m%Y%H%M */
00527         if
00528         (
00529             ((masks[0] & MDAY_BIT) && (masks[1] & MONTH_BIT))
00530         &&
00531             /* avoid ambiguity */
00532             !((masks[0] & MONTH_BIT) && (masks[1] & MDAY_BIT))
00533         &&
00534             (masks[2] & YEAR_BIT)
00535         &&
00536             (masks[3] & HOUR_BIT)
00537         &&
00538             (masks[4] & MIN_BIT)
00539         )
00540         {
00541             build.tm_mday = numbers[0];
00542             build.tm_mon = numbers[1] - 1;
00543             build.tm_year = correct_year(&build, numbers[2]);
00544             build.tm_hour = numbers[3];
00545             build.tm_min = numbers[4];
00546             build.tm_sec = 0;
00547             return mktime(&build);
00548         }
00549 
00550         /* %d%m%H%M%Y */
00551         if
00552         (
00553             ((masks[0] & MDAY_BIT) && (masks[1] & MONTH_BIT))
00554         &&
00555             /* avoid ambiguity */
00556             !((masks[0] & MONTH_BIT) && (masks[1] & MDAY_BIT))
00557         &&
00558             (masks[2] & HOUR_BIT)
00559         &&
00560             (masks[3] & MIN_BIT)
00561         &&
00562             (masks[4] & YEAR_BIT)
00563         )
00564         {
00565             build.tm_mday = numbers[0];
00566             build.tm_mon = numbers[1] - 1;
00567             build.tm_hour = numbers[2];
00568             build.tm_min = numbers[3];
00569             build.tm_sec = 0;
00570             build.tm_year = correct_year(&build, numbers[4]);
00571             return mktime(&build);
00572         }
00573 
00574         /* %m%d%H%M%Y */
00575         if
00576         (
00577             ((masks[0] & MONTH_BIT) && (masks[1] & MDAY_BIT))
00578         &&
00579             /* avoid ambiguity */
00580             !((masks[0] & MDAY_BIT) && (masks[1] & MONTH_BIT))
00581         &&
00582             (masks[2] & HOUR_BIT)
00583         &&
00584             (masks[3] & MIN_BIT)
00585         &&
00586             (masks[4] & YEAR_BIT)
00587         )
00588         {
00589             build.tm_mon = numbers[0] - 1;
00590             build.tm_mday = numbers[1];
00591             build.tm_hour = numbers[2];
00592             build.tm_min = numbers[3];
00593             build.tm_sec = 0;
00594             build.tm_year = correct_year(&build, numbers[4]);
00595             return mktime(&build);
00596         }
00597 
00598         /* dunno */
00599         return -1;
00600     }
00601     if (nnum == 3)
00602     {
00603         /* %Y%m%d */
00604         if
00605         (
00606             (masks[0] & YEAR_BIT)
00607         &&
00608             (masks[1] & MONTH_BIT)
00609         &&
00610             (masks[2] & MDAY_BIT)
00611         )
00612         {
00613             build.tm_year = correct_year(&build, numbers[0]);
00614             build.tm_mon = numbers[1] - 1;
00615             build.tm_mday = numbers[2];
00616             return mktime(&build);
00617         }
00618 
00619         /* %d%m%Y */
00620         if
00621         (
00622             ((masks[0] & MDAY_BIT) && (masks[1] & MONTH_BIT))
00623         &&
00624             /* avoid ambiguity */
00625             !((masks[0] & MONTH_BIT) && (masks[1] & MDAY_BIT))
00626         &&
00627             (masks[2] & YEAR_BIT)
00628         )
00629         {
00630             build.tm_mday = numbers[0];
00631             build.tm_mon = numbers[1] - 1;
00632             build.tm_year = correct_year(&build, numbers[2]);
00633             return mktime(&build);
00634         }
00635 
00636         /* %m%d%Y */
00637         if
00638         (
00639             ((masks[0] & MONTH_BIT) && (masks[1] & MDAY_BIT))
00640         &&
00641             /* avoid ambiguity */
00642             !((masks[0] & MDAY_BIT) && (masks[1] & MONTH_BIT))
00643         &&
00644             (masks[2] & YEAR_BIT)
00645         )
00646         {
00647             build.tm_mday = numbers[0];
00648             build.tm_mon = numbers[1] - 1;
00649             build.tm_year = correct_year(&build, numbers[2]);
00650             return mktime(&build);
00651         }
00652 
00653         /* %H%M%S */
00654         if
00655         (
00656             (masks[0] & HOUR_BIT)
00657         &&
00658             (masks[1] & MIN_BIT)
00659         &&
00660             (masks[2] & SEC_BIT)
00661         )
00662         {
00663             build.tm_hour = numbers[0];
00664             build.tm_min = numbers[1];
00665             build.tm_sec = numbers[2];
00666             return mktime(&build);
00667         }
00668 
00669         /* dunno */
00670         return -1;
00671     }
00672 
00673     if (nnum == 2)
00674     {
00675         /* %H%M */
00676         if ((masks[0] & HOUR_BIT) && (masks[1] & MIN_BIT))
00677         {
00678             build.tm_hour = numbers[0];
00679             build.tm_min = numbers[1];
00680             build.tm_sec = 0;
00681             return mktime(&build);
00682         }
00683 
00684         /* %m%d */
00685         if
00686         (
00687             ((masks[0] & MONTH_BIT) && (masks[1] & MDAY_BIT))
00688         &&
00689             /* avoid ambiguity */
00690             !((masks[0] & MDAY_BIT) && (masks[1] & MONTH_BIT))
00691         )
00692         {
00693             build.tm_mon = numbers[0] - 1;
00694             build.tm_mday = numbers[1];
00695             return mktime(&build);
00696         }
00697 
00698         /* %d%m */
00699         if
00700         (
00701             ((masks[0] & MDAY_BIT) && (masks[1] & MONTH_BIT))
00702         &&
00703             /* avoid ambiguity */
00704             !((masks[0] & MONTH_BIT) && (masks[1] & MDAY_BIT))
00705         )
00706         {
00707             build.tm_mday = numbers[0];
00708             build.tm_mon = numbers[1] - 1;
00709             return mktime(&build);
00710         }
00711 
00712         /* dunno */
00713         return -1;
00714     }
00715 
00716     /* dunno */
00717     return -1;
00718 }
00719 
00720 
00721 static time_t
00722 explain_parse_time_t_on_error(const char *text, const char *caption)
00723 {
00724     time_t          result;
00725 
00726     result = explain_parse_time_t(text);
00727     if (result == (time_t)(-1))
00728     {
00729         char            qtext[900];
00730         explain_string_buffer_t qtext_sb;
00731         char            message[1000];
00732         explain_string_buffer_t message_sb;
00733 
00734         explain_string_buffer_init(&qtext_sb, qtext, sizeof(qtext));
00735         explain_string_buffer_puts_quoted(&qtext_sb, text);
00736         explain_string_buffer_init(&message_sb, message, sizeof(message));
00737 
00738         /* FIXME: i18n */
00739         if (caption && *caption)
00740         {
00741             explain_string_buffer_printf
00742             (
00743                 &message_sb,
00744                 "%s: can't parse %s into a date and time",
00745                 caption,
00746                 qtext
00747             );
00748         }
00749         else
00750         {
00751             explain_string_buffer_printf
00752             (
00753                 &message_sb,
00754                 "unable to parse %s into a date and time",
00755                 qtext
00756             );
00757         }
00758 
00759         explain_output_error("%s", message);
00760     }
00761     return result;
00762 }
00763 
00764 
00765 time_t
00766 explain_parse_time_t_or_die(const char *text, const char *caption)
00767 {
00768     time_t          result;
00769 
00770     result = explain_parse_time_t_on_error(text, caption);
00771     if (result == (time_t)(-1))
00772     {
00773         explain_output_exit_failure();
00774     }
00775     return result;
00776 }
00777 
00778 
00779 /* vim: set ts=8 sw=4 et : */