"Fossies" - the Fresh Open Source Software Archive

Member "dateutils-0.4.6/src/dzone.c" (19 Mar 2019, 8902 Bytes) of package /linux/privat/dateutils-0.4.6.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dzone.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.4.5_vs_0.4.6.

    1 /*** dzone.c -- convert date/times between timezones
    2  *
    3  * Copyright (C) 2011-2019 Sebastian Freundt
    4  *
    5  * Author:  Sebastian Freundt <freundt@ga-group.nl>
    6  *
    7  * This file is part of dateutils.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  *
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  *
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * 3. Neither the name of the author nor the names of any contributors
   21  *    may be used to endorse or promote products derived from this
   22  *    software without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
   25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   27  * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   31  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
   33  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
   34  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   35  *
   36  **/
   37 #if defined HAVE_CONFIG_H
   38 # include "config.h"
   39 #endif  /* HAVE_CONFIG_H */
   40 #include <stdio.h>
   41 #include <stdlib.h>
   42 #include <stdint.h>
   43 #include <sys/time.h>
   44 #include <time.h>
   45 
   46 #include "dt-core.h"
   47 #include "dt-io.h"
   48 #include "dt-core-tz-glue.h"
   49 #include "dt-locale.h"
   50 #include "tzraw.h"
   51 
   52 struct ztr_s {
   53     int32_t trns;
   54     int32_t offs;
   55 };
   56 
   57 /* fwd decld in tzraw.h */
   58 struct ztrdtl_s {
   59     int32_t offs;
   60     uint8_t dstp;
   61     uint8_t abbr;
   62 } __attribute__((packed));
   63 
   64 const char *prog = "dzone";
   65 static char gbuf[256U];
   66 
   67 static const char never[] = "never";
   68 static const char nindi[] = " -> ";
   69 static const char pindi[] = " <- ";
   70 
   71 
   72 static size_t
   73 xstrlcpy(char *restrict dst, const char *src, size_t dsz)
   74 {
   75     size_t ssz = strlen(src);
   76     if (ssz > dsz) {
   77         ssz = dsz - 1U;
   78     }
   79     memcpy(dst, src, ssz);
   80     dst[ssz] = '\0';
   81     return ssz;
   82 }
   83 
   84 static struct dt_dt_s
   85 dz_enrichz(struct dt_dt_s d, zif_t zone)
   86 {
   87 /* like dtz_enrichz() but with fix-up for date-only dt's */
   88     struct dt_dt_s x = d;
   89 
   90     if (UNLIKELY(zone == NULL)) {
   91         goto out;
   92     } else if (d.typ == DT_SEXY) {
   93         goto out;
   94     } else if (dt_sandwich_only_d_p(d)) {
   95         static struct dt_t_s mid = {.hms = {.h = 24}};
   96         dt_make_sandwich(&x, d.d.typ, DT_HMS);
   97         x.t = mid;
   98     }
   99     x = dtz_enrichz(x, zone);
  100 
  101     if (dt_sandwich_only_d_p(d)) {
  102         /* keep .zdiff and .neg */
  103         d.neg = x.neg;
  104         d.zdiff = x.zdiff;
  105         x = d;
  106     }
  107 out:
  108     return x;
  109 }
  110 
  111 static int
  112 dz_io_write(struct dt_dt_s d, zif_t zone, const char *name)
  113 {
  114     static const char fmt[] = "%FT%T%Z\0%F%Z";
  115     char *restrict bp = gbuf;
  116     const char *const ep = gbuf + sizeof(gbuf);
  117     size_t fof = 0U;
  118 
  119     /* pick a format */
  120     fof += dt_sandwich_only_t_p(d) * 3U;
  121     fof += dt_sandwich_only_d_p(d) * 8U;
  122 
  123     /* let's go */
  124     d = dz_enrichz(d, zone);
  125     bp += dt_strfdt(bp, ep - bp, fmt + fof, d);
  126     /* append name */
  127     if (LIKELY(name != NULL)) {
  128         *bp++ = '\t';
  129         bp += xstrlcpy(bp, name, ep - bp);
  130     }
  131     *bp++ = '\n';
  132     __io_write(gbuf, bp - gbuf, stdout);
  133     return (bp > gbuf) - 1;
  134 }
  135 
  136 static size_t
  137 dz_strftr(char *restrict buf, size_t bsz, struct ztr_s t)
  138 {
  139     static const char fmt[] = "%FT%T%Z";
  140     struct dt_dt_s d = {DT_UNK};
  141 
  142     d.typ = DT_SEXY;
  143     d.sexy = t.trns + t.offs;
  144     if (t.offs > 0) {
  145         d.zdiff = (uint16_t)(t.offs / ZDIFF_RES);
  146     } else if (t.offs < 0) {
  147         d.neg = 1;
  148         d.zdiff = (uint16_t)(-t.offs / ZDIFF_RES);
  149     }
  150     return dt_strfdt(buf, bsz, fmt, d);
  151 }
  152 
  153 static int
  154 dz_write_nxtr(struct zrng_s r, zif_t z, const char *zn)
  155 {
  156     char *restrict bp = gbuf;
  157     const char *const ep = gbuf + sizeof(gbuf);
  158     size_t ntr = zif_ntrans(z);
  159 
  160     if (r.next == INT_MAX) {
  161         bp += xstrlcpy(bp, never, bp - ep);
  162     } else {
  163         bp += dz_strftr(bp, ep - bp, (struct ztr_s){r.next, r.offs});
  164     }
  165     /* append next indicator */
  166     bp += xstrlcpy(bp, nindi, bp - ep);
  167     if (r.trno + 1U < ntr) {
  168         /* thank god there's another one */
  169         struct ztrdtl_s zd = zif_trdtl(z, r.trno + 1);
  170 
  171         if (r.next == INT_MAX) {
  172             goto never;
  173         }
  174         bp += dz_strftr(bp, ep - bp, (struct ztr_s){r.next, zd.offs});
  175     } else {
  176     never:
  177         bp += xstrlcpy(bp, never, bp - ep);
  178     }
  179 
  180     /* append name */
  181     if (LIKELY(zn != NULL)) {
  182         *bp++ = '\t';
  183         bp += xstrlcpy(bp, zn, ep - bp);
  184     }
  185     *bp++ = '\n';
  186     __io_write(gbuf, bp - gbuf, stdout);
  187     return (bp > gbuf) - 1;
  188 }
  189 
  190 static int
  191 dz_write_prtr(struct zrng_s r, zif_t UNUSED(z), const char *zn)
  192 {
  193     char *restrict bp = gbuf;
  194     const char *const ep = gbuf + sizeof(gbuf);
  195 
  196     if (r.trno >= 1) {
  197         /* there's one before that */
  198         struct ztrdtl_s zd = zif_trdtl(z, r.trno - 1);
  199 
  200         bp += dz_strftr(bp, ep - bp, (struct ztr_s){r.prev, zd.offs});
  201     } else {
  202         bp += xstrlcpy(bp, never, bp - ep);
  203     }
  204     /* append prev indicator */
  205     bp += xstrlcpy(bp, pindi, bp - ep);
  206     if (r.prev == INT_MIN) {
  207         bp += xstrlcpy(bp, never, bp - ep);
  208     } else {
  209         bp += dz_strftr(bp, ep - bp, (struct ztr_s){r.prev, r.offs});
  210     }
  211 
  212     /* append name */
  213     if (LIKELY(zn != NULL)) {
  214         *bp++ = '\t';
  215         bp += xstrlcpy(bp, zn, ep - bp);
  216     }
  217     *bp++ = '\n';
  218     __io_write(gbuf, bp - gbuf, stdout);
  219     return (bp > gbuf) - 1;
  220 }
  221 
  222 
  223 #include "dzone.yucc"
  224 
  225 int
  226 main(int argc, char *argv[])
  227 {
  228     yuck_t argi[1U];
  229     int rc = 0;
  230     zif_t fromz = NULL;
  231     char **fmt;
  232     size_t nfmt;
  233     /* all them zones to consider */
  234     struct {
  235         zif_t zone;
  236         const char *name;
  237     } *z = NULL;
  238     size_t nz = 0U;
  239     /* all them datetimes to consider */
  240     struct dt_dt_s *d = NULL;
  241     size_t nd = 0U;
  242     bool trnsp = false;
  243 
  244     if (yuck_parse(argi, argc, argv)) {
  245         rc = 1;
  246         goto out;
  247     } else if (argi->nargs == 0U) {
  248         error("Need at least a ZONENAME or a DATE/TIME");
  249         rc = 1;
  250         goto out;
  251     }
  252 
  253     if (argi->from_locale_arg) {
  254         setilocale(argi->from_locale_arg);
  255     }
  256 
  257     /* try and read the from and to time zones */
  258     if (argi->from_zone_arg) {
  259         fromz = dt_io_zone(argi->from_zone_arg);
  260     }
  261     if (argi->next_flag || argi->prev_flag) {
  262         trnsp = true;
  263     }
  264     if (argi->base_arg) {
  265         struct dt_dt_s base = dt_strpdt(argi->base_arg, NULL, NULL);
  266         dt_set_base(base);
  267     }
  268 
  269     /* very well then */
  270     fmt = argi->input_format_args;
  271     nfmt = argi->input_format_nargs;
  272 
  273     /* initially size the two beef arrays as large as there is input
  274      * we'll then sort them by traversing the input args and ass'ing
  275      * to the one or the other */
  276     nz = 0U;
  277     if (UNLIKELY((z = malloc(argi->nargs * sizeof(*z))) == NULL)) {
  278         error("failed to allocate space for zone info");
  279         goto out;
  280     }
  281     nd = 0U;
  282     if (UNLIKELY((d = malloc(argi->nargs * sizeof(*d))) == NULL)) {
  283         error("failed to allocate space for date/times");
  284         goto out;
  285     }
  286 
  287     for (size_t i = 0U; i < argi->nargs; i++) {
  288         const char *inp = argi->args[i];
  289 
  290         /* try dt_strp'ing the input or assume it's a zone  */
  291         if (!dt_unk_p(d[nd] = dt_io_strpdt(inp, fmt, nfmt, fromz))) {
  292             if (UNLIKELY(d[nd].fix) && !argi->quiet_flag) {
  293                 rc = 2;
  294             }
  295             nd++;
  296         } else if ((z[nz].zone = dt_io_zone(inp)) != NULL) {
  297             z[nz].name = inp;
  298             nz++;
  299         } else if (!argi->quiet_flag) {
  300             /* just bollocks */
  301             error("\
  302 Cannot use `%s', it does not appear to be a zonename\n\
  303 nor a date/time corresponding to the given input formats", inp);
  304             rc = 2;
  305         }
  306     }
  307     /* operate with default zone UTC and default time now */
  308     if (nz == 0U) {
  309         z[nz].zone = NULL;
  310         z[nz].name = NULL;
  311         nz++;
  312     }
  313     if (nd == 0U && !trnsp) {
  314         d[nd++] = dt_datetime((dt_dttyp_t)DT_YMD);
  315     } else if (nd == 0U) {
  316         d[nd++] = dt_datetime((dt_dttyp_t)DT_SEXY);
  317     }
  318 
  319     /* just go through them all now */
  320     if (LIKELY(!trnsp)) {
  321         for (size_t i = 0U; !trnsp && i < nd; i++) {
  322             for (size_t j = 0U; j < nz; j++) {
  323                 dz_io_write(d[i], z[j].zone, z[j].name);
  324             }
  325         }
  326     } else {
  327         /* otherwise traverse the zones and determine transitions */
  328         for (size_t i = 0U; i < nd; i++) {
  329             struct dt_dt_s di = dt_dtconv(DT_SEXY, d[i]);
  330 
  331             for (size_t j = 0U; j < nz; j++) {
  332                 const zif_t zj = z[j].zone;
  333                 const char *zn = z[j].name;
  334                 struct zrng_s r;
  335 
  336                 if (UNLIKELY(zj == NULL)) {
  337                     /* don't bother */
  338                     continue;
  339                 }
  340                 /* otherwise find the range */
  341                 r = zif_find_zrng(zj, di.sexy);
  342 
  343                 if (argi->next_flag) {
  344                     dz_write_nxtr(r, zj, zn);
  345                 }
  346 
  347                 if (argi->prev_flag) {
  348                     dz_write_prtr(r, zj, zn);
  349                 }
  350             }
  351         }
  352     }
  353 
  354 out:
  355     /* release the zones */
  356     dt_io_clear_zones();
  357     /* release those arrays */
  358     if (LIKELY(z != NULL)) {
  359         free(z);
  360     }
  361     if (LIKELY(d != NULL)) {
  362         free(d);
  363     }
  364 
  365     if (argi->from_locale_arg) {
  366         setilocale(NULL);
  367     }
  368 
  369     yuck_free(argi);
  370     return rc;
  371 }
  372 
  373 /* dzone.c ends here */