"Fossies" - the Fresh Open Source Software Archive

Member "dateutils-0.4.6/src/dadd.c" (19 Mar 2019, 10984 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 "dadd.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 /*** dadd.c -- perform simple date arithmetic, date plus duration
    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 "prchunk.h"
   51 
   52 const char *prog = "dadd";
   53 
   54 
   55 static bool
   56 durs_only_d_p(struct dt_dtdur_s dur[], size_t ndur)
   57 {
   58     for (size_t i = 0; i < ndur; i++) {
   59         if (dur[i].durtyp >= (dt_dtdurtyp_t)DT_NDURTYP) {
   60             return false;
   61         }
   62     }
   63     return true;
   64 }
   65 
   66 static struct dt_dt_s
   67 dadd_add(struct dt_dt_s d, struct dt_dtdur_s dur[], size_t ndur)
   68 {
   69     for (size_t i = 0; i < ndur; i++) {
   70         d = dt_dtadd(d, dur[i]);
   71     }
   72     return d;
   73 }
   74 
   75 
   76 struct mass_add_clo_s {
   77     void *pctx;
   78     const struct grep_atom_soa_s *gra;
   79     struct __strpdtdur_st_s st;
   80     struct dt_dt_s rd;
   81     zif_t fromz;
   82     zif_t hackz;
   83     zif_t z;
   84     const char *ofmt;
   85     int sed_mode_p;
   86     int quietp;
   87 };
   88 
   89 static int
   90 proc_line(const struct mass_add_clo_s *clo, char *line, size_t llen)
   91 {
   92     struct dt_dt_s d;
   93     char *sp = NULL;
   94     char *ep = NULL;
   95     int rc = 0;
   96 
   97     do {
   98         /* check if line matches, */
   99         d = dt_io_find_strpdt2(
  100             line, llen, clo->gra, &sp, &ep, clo->fromz);
  101 
  102         if (!dt_unk_p(d)) {
  103             if (UNLIKELY(d.fix) && !clo->quietp) {
  104                 rc = 2;
  105             }
  106             /* perform addition now */
  107             d = dadd_add(d, clo->st.durs, clo->st.ndurs);
  108 
  109             if (clo->hackz == NULL && clo->fromz != NULL) {
  110                 /* fixup zone */
  111                 d = dtz_forgetz(d, clo->fromz);
  112             }
  113 
  114             if (clo->sed_mode_p) {
  115                 __io_write(line, sp - line, stdout);
  116                 dt_io_write(d, clo->ofmt, clo->z, '\0');
  117                 llen -= (ep - line);
  118                 line = ep;
  119             } else {
  120                 dt_io_write(d, clo->ofmt, clo->z, '\n');
  121                 break;
  122             }
  123         } else if (clo->sed_mode_p) {
  124             line[llen] = '\n';
  125             __io_write(line, llen + 1, stdout);
  126             break;
  127         } else {
  128             /* obviously unmatched, warn about it in non -q mode */
  129             if (!clo->quietp) {
  130                 dt_io_warn_strpdt(line);
  131                 rc = 2;
  132             }
  133             break;
  134         }
  135     } while (1);
  136     return rc;
  137 }
  138 
  139 static int
  140 mass_add_dur(const struct mass_add_clo_s *clo)
  141 {
  142 /* read lines from stdin
  143  * interpret as dates
  144  * add to reference duration
  145  * output */
  146     size_t lno = 0;
  147     int rc = 0;
  148 
  149     for (char *line; prchunk_haslinep(clo->pctx); lno++) {
  150         size_t llen = prchunk_getline(clo->pctx, &line);
  151 
  152         rc |= proc_line(clo, line, llen);
  153     }
  154     return rc;
  155 }
  156 
  157 static int
  158 mass_add_d(const struct mass_add_clo_s *clo)
  159 {
  160 /* read lines from stdin
  161  * interpret as durations
  162  * add to reference date
  163  * output */
  164     size_t lno = 0;
  165     struct dt_dt_s d;
  166     struct __strpdtdur_st_s st = {0};
  167     int rc = 0;
  168 
  169     for (char *line; prchunk_haslinep(clo->pctx); lno++) {
  170         size_t llen;
  171         int has_dur_p  = 1;
  172 
  173         llen = prchunk_getline(clo->pctx, &line);
  174 
  175         /* check for durations on this line */
  176         do {
  177             if (dt_io_strpdtdur(&st, line) < 0) {
  178                 has_dur_p = 0;
  179             }
  180         } while (__strpdtdur_more_p(&st));
  181 
  182         /* finish with newline again */
  183         line[llen] = '\n';
  184 
  185         if (has_dur_p) {
  186             if (UNLIKELY(clo->rd.fix) && !clo->quietp) {
  187                 rc = 2;
  188             }
  189             /* perform addition now */
  190             d = dadd_add(clo->rd, st.durs, st.ndurs);
  191 
  192             if (clo->hackz == NULL && clo->fromz != NULL) {
  193                 /* fixup zone */
  194                 d = dtz_forgetz(d, clo->fromz);
  195             }
  196 
  197             /* no sed mode here */
  198             dt_io_write(d, clo->ofmt, clo->z, '\n');
  199         } else if (clo->sed_mode_p) {
  200             __io_write(line, llen + 1, stdout);
  201         } else if (!clo->quietp) {
  202             line[llen] = '\0';
  203             dt_io_warn_strpdt(line);
  204             rc = 2;
  205         }
  206         /* just reset the ndurs slot */
  207         st.ndurs = 0;
  208     }
  209     /* free associated duration resources */
  210     __strpdtdur_free(&st);
  211     return rc;
  212 }
  213 
  214 
  215 #include "dadd.yucc"
  216 
  217 int
  218 main(int argc, char *argv[])
  219 {
  220     yuck_t argi[1U];
  221     struct dt_dt_s d;
  222     struct __strpdtdur_st_s st = {0};
  223     const char *ofmt;
  224     char **fmt;
  225     size_t nfmt;
  226     int rc = 0;
  227     bool dt_given_p = false;
  228     zif_t fromz = NULL;
  229     zif_t z = NULL;
  230     zif_t hackz = NULL;
  231 
  232     if (yuck_parse(argi, argc, argv)) {
  233         rc = 1;
  234         goto out;
  235     } else if (argi->nargs == 0) {
  236         error("Error: DATE or DURATION must be specified\n");
  237         yuck_auto_help(argi);
  238         rc = 1;
  239         goto out;
  240     }
  241     /* init and unescape sequences, maybe */
  242     ofmt = argi->format_arg;
  243     fmt = argi->input_format_args;
  244     nfmt = argi->input_format_nargs;
  245     if (argi->backslash_escapes_flag) {
  246         dt_io_unescape(argi->format_arg);
  247         for (size_t i = 0; i < nfmt; i++) {
  248             dt_io_unescape(fmt[i]);
  249         }
  250     }
  251 
  252     if (argi->from_locale_arg) {
  253         setilocale(argi->from_locale_arg);
  254     }
  255     if (argi->locale_arg) {
  256         setflocale(argi->locale_arg);
  257     }
  258 
  259     /* try and read the from and to time zones */
  260     if (argi->from_zone_arg) {
  261         fromz = dt_io_zone(argi->from_zone_arg);
  262     }
  263     if (argi->zone_arg) {
  264         z = dt_io_zone(argi->zone_arg);
  265     }
  266     if (argi->base_arg) {
  267         struct dt_dt_s base = dt_strpdt(argi->base_arg, NULL, NULL);
  268         dt_set_base(base);
  269     }
  270 
  271     /* sanity checks, decide whether we're a mass date adder
  272      * or a mass duration adder, or both, a date and durations are
  273      * present on the command line */
  274     with (const char *inp = argi->args[0U]) {
  275         /* date parsing needed postponing as we need to find out
  276          * about the durations */
  277         if (!dt_unk_p(dt_io_strpdt(inp, fmt, nfmt, NULL))) {
  278             dt_given_p = true;
  279         }
  280     }
  281 
  282     /* check first arg, if it's a date the rest of the arguments are
  283      * durations, if not, dates must be read from stdin */
  284     for (size_t i = dt_given_p; i < argi->nargs; i++) {
  285         const char *inp = argi->args[i];
  286         do {
  287             if (dt_io_strpdtdur(&st, inp) < 0) {
  288                 serror("Error: \
  289 cannot parse duration string `%s'", st.istr);
  290                 rc = 1;
  291                 goto clear;
  292             }
  293         } while (__strpdtdur_more_p(&st));
  294     }
  295     /* check if there's only d durations */
  296     hackz = durs_only_d_p(st.durs, st.ndurs) ? NULL : fromz;
  297 
  298     /* read the first argument again in light of a completely parsed
  299      * duration sequence */
  300     if (dt_given_p) {
  301         const char *inp = argi->args[0U];
  302         if (dt_unk_p(d = dt_io_strpdt(inp, fmt, nfmt, hackz))) {
  303             error("\
  304 Error: cannot interpret date/time string `%s'", inp);
  305             rc = 1;
  306             goto clear;
  307         }
  308     }
  309 
  310     /* start the actual work */
  311     if (dt_given_p && st.ndurs) {
  312         if (!dt_unk_p(d = dadd_add(d, st.durs, st.ndurs))) {
  313             if (UNLIKELY(d.fix) && !argi->quiet_flag) {
  314                 rc = 2;
  315             }
  316             if (hackz == NULL && fromz != NULL) {
  317                 /* fixup zone */
  318                 d = dtz_forgetz(d, fromz);
  319             }
  320             dt_io_write(d, ofmt, z, '\n');
  321         } else {
  322             rc = 1;
  323         }
  324 
  325     } else if (st.ndurs && argi->empty_mode_flag) {
  326         size_t lno = 0U;
  327         void *pctx;
  328 
  329         /* no threads reading this stream */
  330         __io_setlocking_bycaller(stdout);
  331 
  332         /* using the prchunk reader now */
  333         if ((pctx = init_prchunk(STDIN_FILENO)) == NULL) {
  334             serror("could not open stdin");
  335             goto clear;
  336         }
  337 
  338         while (prchunk_fill(pctx) >= 0) {
  339             for (char *line; prchunk_haslinep(pctx); lno++) {
  340                 size_t llen = prchunk_getline(pctx, &line);
  341                 char *ep = NULL;
  342 
  343                 if (UNLIKELY(!llen)) {
  344                     goto empty;
  345                 }
  346                 /* try and parse the line */
  347                 d = dt_io_strpdt_ep(line, fmt, nfmt, &ep, fromz);
  348                 if (UNLIKELY(dt_unk_p(d))) {
  349                     goto empty;
  350                 } else if (ep && (unsigned)*ep >= ' ') {
  351                     goto empty;
  352                 }
  353                 /* do the adding */
  354                 d = dadd_add(d, st.durs, st.ndurs);
  355                 if (UNLIKELY(dt_unk_p(d))) {
  356                     goto empty;
  357                 }
  358 
  359                 if (hackz == NULL && fromz != NULL) {
  360                     /* fixup zone */
  361                     d = dtz_forgetz(d, fromz);
  362                 }
  363                 dt_io_write(d, ofmt, z, '\n');
  364                 continue;
  365             empty:
  366                 __io_write("\n", 1U, stdout);
  367             }
  368         }
  369     } else if (st.ndurs) {
  370         /* read dates from stdin */
  371         struct grep_atom_s __nstk[16], *needle = __nstk;
  372         size_t nneedle = countof(__nstk);
  373         struct grep_atom_soa_s ndlsoa;
  374         struct mass_add_clo_s clo[1];
  375         void *pctx;
  376 
  377         /* no threads reading this stream */
  378         __io_setlocking_bycaller(stdout);
  379 
  380         /* lest we overflow the stack */
  381         if (nfmt >= nneedle) {
  382             /* round to the nearest 8-multiple */
  383             nneedle = (nfmt | 7) + 1;
  384             needle = calloc(nneedle, sizeof(*needle));
  385         }
  386         /* and now build the needle */
  387         ndlsoa = build_needle(needle, nneedle, fmt, nfmt);
  388 
  389         /* using the prchunk reader now */
  390         if ((pctx = init_prchunk(STDIN_FILENO)) == NULL) {
  391             serror("could not open stdin");
  392             goto ndl_free;
  393         }
  394 
  395         /* build the clo and then loop */
  396         clo->pctx = pctx;
  397         clo->gra = &ndlsoa;
  398         clo->st = st;
  399         clo->fromz = fromz;
  400         clo->hackz = hackz;
  401         clo->z = z;
  402         clo->ofmt = ofmt;
  403         clo->sed_mode_p = argi->sed_mode_flag;
  404         clo->quietp = argi->quiet_flag;
  405         while (prchunk_fill(pctx) >= 0) {
  406             rc |= mass_add_dur(clo);
  407         }
  408         /* get rid of resources */
  409         free_prchunk(pctx);
  410     ndl_free:
  411         if (needle != __nstk) {
  412             free(needle);
  413         }
  414 
  415     } else {
  416         /* mass-adding durations to reference date */
  417         struct mass_add_clo_s clo[1];
  418         void *pctx;
  419 
  420         /* no threads reading this stream */
  421         __io_setlocking_bycaller(stdout);
  422 
  423         /* using the prchunk reader now */
  424         if ((pctx = init_prchunk(STDIN_FILENO)) == NULL) {
  425             serror("could not open stdin");
  426             goto clear;
  427         }
  428 
  429         /* build the clo and then loop */
  430         clo->pctx = pctx;
  431         clo->rd = d;
  432         clo->fromz = fromz;
  433         clo->hackz = hackz;
  434         clo->z = z;
  435         clo->ofmt = ofmt;
  436         clo->sed_mode_p = argi->sed_mode_flag;
  437         clo->quietp = argi->quiet_flag;
  438         while (prchunk_fill(pctx) >= 0) {
  439             rc |= mass_add_d(clo);
  440         }
  441         /* get rid of resources */
  442         free_prchunk(pctx);
  443     }
  444 clear:
  445     /* free the strpdur status */
  446     __strpdtdur_free(&st);
  447 
  448     dt_io_clear_zones();
  449     if (argi->from_locale_arg) {
  450         setilocale(NULL);
  451     }
  452     if (argi->locale_arg) {
  453         setflocale(NULL);
  454     }
  455 
  456 out:
  457     yuck_free(argi);
  458     return rc;
  459 }
  460 
  461 /* dadd.c ends here */