pax_global_header00006660000000000000000000000064124147775340014530gustar00rootroot0000000000000052 comment=974dc7ffff93c68e4662b6f79cceaa4bca60d0dc dateutils-0.3.1/000077500000000000000000000000001241477753400135275ustar00rootroot00000000000000dateutils-0.3.1/.drone.yml000066400000000000000000000005431241477753400154410ustar00rootroot00000000000000image: gcc4.8 script: - sudo apt-get install gperf - sudo apt-get install help2man - sudo apt-get install flex - sudo apt-get install bison - sudo apt-get install texinfo - sudo apt-get install texlive - autoreconf -vfi - ./configure - make clean all check - make distcheck notify: email: recipients: - devel@fresse.org dateutils-0.3.1/.gitignore000066400000000000000000000005431241477753400155210ustar00rootroot00000000000000aclocal.m4 autom4te.cache configure ltmain.sh m4/libtool.m4 m4/lt*.m4 Makefile.in config.guess config.sub install-sh missing src/config.h.in *~ =build* build/ depcomp ++* Makefile .version config.log config.status libtool *.o config.h stamp-h1 .deps .libs texinfo.tex *.info test/*.log *.pc src/*-clo.[ch] info/*.h2m info/*.man ylwrap test-driver compile dateutils-0.3.1/.travis.yml000066400000000000000000000021741241477753400156440ustar00rootroot00000000000000language: c compiler: - gcc - clang env: global: - secure: "GFjrqOUyqNLrPGtxNW4r9JxJBudjddBJFzEEcpPkfEbMHJ+kk4zOYsSLV1f1cAK+X8TWLsCq5Yjt/2Rzhu7Csjiy34RReZ9KwsmcwX78T8MkQQz4yv8by9J9a5mbHQ3S6mtF7PH1t38PKVcJi51icEqUjvi4FnfME5+VrdueE+c=" before_install: - sudo apt-get -qq update install: - sudo apt-get install -qq pkg-config - sudo apt-get install -qq gperf - sudo apt-get install -qq texinfo - sudo apt-get install -qq bison - sudo apt-get install -qq flex - sudo apt-get install -qq texlive - sudo apt-get install -qq octave3.2-headers before_script: - autoreconf -vfi script: - ./configure --enable-contrib || { cat config.log; false; } - make clean all check || { cat test/test-suite.log; false; } - make distcheck ## whitelist branches: only: - master - next - coverity-scan notifications: email: - devel@fresse.org addons: coverity_scan: project: name: "hroptatyr/dateutils" description: "dateutils coverity scan" notification_email: devel@fresse.org build_command_prepend: "./configure" build_command: "make all check" branch_pattern: coverity-scan dateutils-0.3.1/GNUmakefile000066400000000000000000000017511241477753400156050ustar00rootroot00000000000000# This GNUmakefile is used only if you run GNU Make. # If the user runs GNU make but has not yet run ./configure, # give them a diagnostic. _gl-Makefile := $(wildcard [M]akefile) ifneq ($(_gl-Makefile),) _dist-target_p ?= $(filter-out %clean, $(filter dist%,$(MAKECMDGOALS))) include Makefile # update the included makefile snippet which sets VERSION variables version.mk: .version version.mk.in FORCE -$(AM_V_GEN) \ if test -w $< -a "$(MAKECMDGOALS)" != "am--refresh"; then \ $(MAKE) -C "$(top_builddir)/build-aux"; \ PATH="$(top_builddir)/build-aux:$${PATH}" \ yuck scmver --ignore-noscm -o $@ --reference $^; \ if test $$? -eq 3 -a -n "$(_dist-target_p)"; then \ exec $(MAKE) $(MAKECMDGOALS); \ fi; \ fi else .DEFAULT_GOAL := abort-due-to-no-makefile $(MAKECMDGOALS): abort-due-to-no-makefile abort-due-to-no-makefile: @echo There seems to be no Makefile in this directory. 1>&2 @echo "You must run ./configure before running 'make'." 1>&2 exit 1 endif .PHONY: FORCE dateutils-0.3.1/INSTALL000066400000000000000000000013231241477753400145570ustar00rootroot00000000000000Installing dateutils from git tree ================================== Requisites: ----------- - compiler gcc >= 4.6.0 or compatible (icc, clang, ...) - autotools - texinfo Build and install: ------------------ - autoreconf -i - ./configure - make - [sudo] make install Installing dateutils from tarball ================================= Requisites: ----------- - compiler gcc >= 4.6.0 or compatible (icc, clang, ...) Build and install: ------------------ - ./configure - make - [sudo] make install Notes ===== To run the test suite in either case invoke - make check after building the binaries To kick off adoption, currently old/buggy gcc compilers are supported as well, however this might change in the future. dateutils-0.3.1/Makefile.am000066400000000000000000000011661241477753400155670ustar00rootroot00000000000000include $(top_builddir)/version.mk LANG = C LC_ALL = C ACLOCAL_AMFLAGS = -I m4 SUBDIRS = EXTRA_DIST = $(BUILT_SOURCES) BUILT_SOURCES = SUBDIRS += build-aux SUBDIRS += lib SUBDIRS += src SUBDIRS += info SUBDIRS += test if BUILD_MEXCLI SUBDIRS += contrib endif BUILD_MEXCLI if BUILD_OCTCLI SUBDIRS += contrib endif BUILD_OCTCLI DISTCLEANFILES = version.mk EXTRA_DIST += version.mk.in doc_DATA = README.md EXTRA_DIST += $(doc_DATA) BUILT_SOURCES += .version .version: $(AM_V_GEN) echo "v$(VERSION)" > $@ ## make sure .version is read-only in the dist dist-hook: chmod ugo-w $(distdir)/.version ## Makefile.am ends here dateutils-0.3.1/README.md000066400000000000000000000257441241477753400150220ustar00rootroot00000000000000Dateutils ========= [![Build Status](https://secure.travis-ci.org/hroptatyr/dateutils.png?branch=master)](http://travis-ci.org/hroptatyr/dateutils) [![Build Status](https://drone.io/github.com/hroptatyr/dateutils/status.png)](https://drone.io/github.com/hroptatyr/dateutils/latest) [![Coverity Scan Build Status](https://scan.coverity.com/projects/2197/badge.svg)](https://scan.coverity.com/projects/2197) Dateutils are a bunch of tools that revolve around fiddling with dates and times on the command line with a strong focus on use cases that arise when dealing with large amounts of financial data. Dateutils are hosted primarily on github: + github page: + project homepage: + downloads: Below is a short list of examples that demonstrate what dateutils can do, for full specs refer to the info and man pages. For installation instructions refer to the INSTALL file. Dateutils commands are prefixed with a `d` but otherwise resemble known unix commands for reasons of intuition. The only exception being `strptime` which is analogous to the libc function of the same name. + `strptime` Command line version of the C function + `dadd` Add durations to dates or times + `dconv` Convert dates or times between calendars + `ddiff` Compute durations between dates or times + `dgrep` Grep dates or times in input streams + `dround` Round dates or times to "fuller" values + `dseq` Generate sequences of dates or times + `dtest` Compare dates or times + `dzone` Convert date/times to timezones in bulk Examples ======== I love everything to be explained by example to get a first impression. So here it comes. dseq ---- A tool mimicking seq(1) but whose inputs are from the domain of dates rather than integers. Typically scripts use something like $ for i in $(seq 0 9); do date -d "2010-01-01 +${i} days" "+%F" done which now can be shortened to $ dseq 2010-01-01 2010-01-10 with the additional benefit that the end date can be given directly instead of being computed from the start date and an interval in days. Also, it provides date specific features that would be a PITA to implement using the above seq(1)/date(1) approach, like skipping certain weekdays: $ dseq 2010-01-01 2010-01-10 --skip sat,sun => 2010-01-01 2010-01-04 2010-01-05 2010-01-06 2010-01-07 2010-01-08 dseq also works on times: $ dseq 12:00:00 5m 12:17:00 => 12:00:00 12:05:00 12:10:00 12:15:00 and also date-times: $ dseq --compute-from-last 2012-01-02T12:00:00 5m 2012-01-02T12:17:00 => 2012-01-02T12:02:00 2012-01-02T12:07:00 2012-01-02T12:12:00 2012-01-02T12:17:00 dconv ----- A tool to convert dates between different calendric systems. While other such tools usually focus on converting Gregorian dates to, say, the Chinese calendar, dconv aims at supporting calendric systems which are essential in financial contexts. To convert a (Gregorian) date into the so called ymcw representation: $ dconv 2012-03-04 -f "%Y-%m-%c-%w" => 2012-03-01-00 and vice versa: $ dconv 2012-03-01-Sun -i "%Y-%m-%c-%a" -f '%F' => 2012-03-04 where the ymcw representation means, the %c-th %w of the month in a given year. This is useful if dates are specified like, the third Thursday in May for instance. dconv can also be used to convert occurrences of dates, times or date-times in an input stream on the fly $ dconv -S -i '%b/%d %Y at %I:%M %P' < Remember we meet on 2012-03-03T14:30:00 and most prominently to convert between time zones: $ dconv --from-zone "America/Chicago" --zone "Asia/Tokyo" 2012-01-04T09:33:00 => 2012-01-05T00:33:00 $ dconv --zone "America/Chicago" now -f "%d %b %Y %T" => 05 Apr 2012 11:11:57 dtest ----- A tool to perform date comparison in the shell, it's modelled after test(1) but with proper command line options. $ if dtest today --gt 2010-01-01; then echo "yes" fi => yes dadd ---- A tool to perform date arithmetic (date maths) in the shell. Given a date and a list of durations this will compute new dates. Given a duration and a list of dates this will compute new dates. $ dadd 2010-02-02 +4d => 2010-02-06 $ dadd 2010-02-02 +1w => 2010-02-09 $ dadd -1d < 2001-01-04 2000-12-31 Adding durations to times: $ dadd 12:05:00 +10m => 12:15:00 and even date-times: $ dadd 2012-03-12T12:05:00 -1d4h => 2012-03-11T08:05:00 As of version v0.2.2 leap-second adjusted calculations are built-in. Use the unit `rs` to denote "real" seconds: $ dadd '2012-06-30 23:59:30' +30rs => 2012-06-30T23:59:60 as opposed to: $ dadd '2012-06-30 23:59:30' +30s => 2012-07-01T00:00:00 ddiff ----- A tool to calculate the difference between two (or more) dates. This is somewhat the converse of dadd. Outputs will be durations that, when added to the first date, give the second date. Get the number of days between two dates: $ ddiff 2001-02-08 2001-03-02 => 22 The duration format can be controlled through the `-f` switch: $ ddiff 2001-02-08 2001-03-09 -f "%m month and %d day" => 1 month and 1 day ddiff also accepts time stamps as input: $ ddiff 2012-03-01T12:17:00 2012-03-02T14:00:00 => 92580s The `-f` switch does the right thing: $ ddiff 2012-03-01T12:17:00 2012-03-02T14:00:00 -f '%dd %Ss' => 1d 6180s compare to: $ ddiff 2012-03-01T12:17:00 2012-03-02T14:00:00 -f '%dd %Hh %Ss' => 1d 1h 2580s As of version v0.2.2 leap-second adjusted calculations can be made. Use the format specifier `%rS` to get the elapsed time in "real" seconds: ddiff '2012-06-30 23:59:30' '2012-07-01 00:00:30' -f '%rS' => 61 dgrep ----- A tool to extract lines from an input stream that match certain criteria, showing either the line or the match: $ dgrep '<2012-03-01' < Feb 2012-02-28 Feb 2012-02-29 leap day dround ------ A tool to "round" dates or time stamps to a recurring point in time, like the next/previous January or the next/previous Thursday. Round (backwards) to the first of the current month: $ dround '2011-08-22' -1 => 2011-08-01 Round a stream of dates strictly to the next month's first: $ dround -S -n 1 < pay cable 2012-03-01 pay gas 2012-03-01 pay rent 2012-04-01 redeem loan 2012-04-01 Round a timeseries to the next full or half hour (and convert to ISO): $ dround -S 30m -i '%d/%m/%Y %T' -f '%F %T' < 2012-03-06 14:30:00 eventA 2012-03-06 14:30:00 eventA 2012-03-06 14:30:00 eventB 2012-03-06 15:00:00 eventB dsort ----- New in dateutils 0.3.0. A tool to bring the lines of a file into chronological order. $ dsort < 2009-06-03 caev="DVCA" secu="VOD" exch="XLON" xdte="2009-06-03" nett/GBX="5.2" 2010-11-17 caev="DVCA" secu="VOD" exch="XLON" xdte="2010-11-17" nett/GBX="2.85" 2011-11-16 caev="DVCA" secu="VOD" exch="XLON" xdte="2011-11-16" nett/GBX="3.05" 2012-06-06 caev="DVCA" secu="VOD" exch="XLON" xdte="2012-06-06" nett/GBX="6.47" 2013-06-12 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-06-12" nett/GBX="6.92" 2013-11-20 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-11-20" nett/GBX="3.53" At the moment the `dsort` tool is built upon `sort(1)` and `cut(1)`. dzone ----- New in dateutils 0.3.0. A tool to quickly inspect date/time values in different timezones. The result will be a matrix that shows every date-time value in every timezone: $ dzone Europe/Berlin Australia/Sydney now 2014-06-30T05:00:00 => 2014-01-30T17:37:13+01:00 Europe/Berlin 2014-01-31T03:37:13+11:00 Australia/Sydney 2014-06-30T07:00:00+02:00 Europe/Berlin 2014-06-30T15:00:00+10:00 Australia/Sydney The `dzone` tool can also be used to obtain the next or previous DST transition relative to a given date/time: $ dzone --next Europe/Berlin Australia/Sydney 2013-02-19 => 2013-03-31T02:00:00+01:00 -> 2013-03-31T03:00:00+02:00 Europe/Berlin 2013-04-07T03:00:00+11:00 -> 2013-04-07T02:00:00+10:00 Australia/Sydney where the left time stamp denotes the current zone offset and the right side is the zone offset after the transition. The date/time indicates the exact moment when the transition is about to take place. In essence `dzone` is a better `zdump(1)`. strptime -------- A tool that brings the flexibility of strptime(3) to the command line. While date(1) has support for output formats, it lacks any kind of support to read arbitrary input from the domain of dates, in particular when the input format is specifically known beforehand and only matching dates/times shall be considered. Usually, to print something like `Mon, May-01/2000` in ISO 8601, people come up with the most prolific recommendations like using perl or sed or awk or any two of them, or they come up with a pageful of shell code full of bashisms, and when sufficiently pestered they "improve" their variant to a dozen pages of portable shell code. The strptime tool does the job just fine strptime -i "%a, %b-%d/%Y" "Mon, May-01/2000" => 2000-05-01 just like you would have done in C. Similar projects ================ In no particular order and without any claim to completeness: + dateexpr: + allanfalloon's dateutils: + yest Use the one that best fits your purpose. And in case you happen to like mine, vote: [dateutils' Ohloh page](https://www.ohloh.net/p/dateutils) dateutils-0.3.1/build-aux/000077500000000000000000000000001241477753400154215ustar00rootroot00000000000000dateutils-0.3.1/build-aux/Makefile.am000066400000000000000000000002751241477753400174610ustar00rootroot00000000000000LANG = C LC_ALL = C AM_CFLAGS = $(EXTRA_CFLAGS) noinst_PROGRAMS = BUILT_SOURCES = EXTRA_DIST = DISTCLEANFILES = if !HAVE_YUCK include yuck.am endif !HAVE_YUCK ## Makefile.am ends here dateutils-0.3.1/build-aux/yuck-coru.c.m4000066400000000000000000000273451241477753400200400ustar00rootroot00000000000000/* -*- c -*- */ changequote`'changequote([,])dnl changecom([#])dnl #if defined HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #if defined HAVE_VERSION_H # include "version.h" #endif /* HAVE_VERSION_H */ #include #include #include #include #include changecom([])dnl ifdef([YUCK_HEADER], [dnl #include "YUCK_HEADER" ])dnl changecom([#])dnl #if defined __INTEL_COMPILER # pragma warning (disable:177) # pragma warning (disable:111) #elif defined __GNUC__ # if __GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6 # pragma GCC diagnostic push # endif /* GCC version */ # pragma GCC diagnostic ignored "-Wunused-label" # pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wunused-function" #endif /* __INTEL_COMPILER */ pushdef([DEFUN], ifdef([YUCK_HEADER], [], [static]))[]dnl static inline bool yuck_streqp(const char *s1, const char *s2) { return !strcmp(s1, s2); } /* for multi-args */ static inline char** yuck_append(char **array, size_t n, char *val) { if (!(n % 16U)) { /* resize */ array = realloc(array, (n + 16U) * sizeof(*array)); } array[[n]] = val; return array; } static enum yuck_cmds_e yuck_parse_cmd(const char *cmd) { if (0) { ; }foreachq([__CMD], yuck_cmds(), [ else if (yuck_streqp(cmd, "yuck_cmd_string(defn([__CMD]))")) { return yuck_cmd(defn([__CMD])); }]) else { /* error here? */ fprintf(stderr, "YUCK_UMB_STR: invalid command `%s'\n\ Try `--help' for a list of commands.\n", cmd); } return (enum yuck_cmds_e)-1; } DEFUN int yuck_parse(yuck_t tgt[[static 1U]], int argc, char *argv[[]]) { char *op; char **args; int i; /* we'll have at most this many args */ memset(tgt, 0, sizeof(*tgt)); tgt->args = args = calloc(argc, sizeof(*tgt->args)); tgt->nargs = 0U; ifdef([YUCK_MAX_POSARGS], [], [define([YUCK_MAX_POSARGS], [(size_t)-1])])dnl for (i = 1; i < argc && tgt->nargs < YUCK_MAX_POSARGS; i++) { op = argv[[i]]; switch (*op) { case '-': /* could be an option */ switch (*++op) { default: /* could be glued into one */ for (; *op; op++) { yield(shortopt, *op); } break; case '-': if (*++op == '\0') { i++; yield(dashdash); break; } yield(longopt, op); break; case '\0': goto plain_dash; } break; default: plain_dash: yield(arg, op); break; } } if (i < argc) { op = argv[[i]]; if (*op++ == '-' && *op++ == '-' && !*op) { /* another dashdash, filter out */ i++; } } /* has to be here as the max_pargs condition might drive us here */ coroutine(dashdash) { /* dashdash loop, pile everything on tgt->args * don't check for subcommands either, this is in accordance to * the git tool which won't accept commands after -- */ for (; i < argc; i++) { args[[tgt->nargs++]] = argv[[i]]; } } return 0; coroutine(longopt) { /* split into option and arg part */ char *arg; if ((arg = strchr(op, '=')) != NULL) { /* \nul this one out */ *arg++ = '\0'; } switch (tgt->cmd) { default: yield(yuck_cmd()[_longopt]); break; foreachq([__CMD], yuck_cmds(), [case yuck_cmd(defn([__CMD])): yield(yuck_cmd(defn([__CMD]))[_longopt]); break; ])} resume; dnl TYPE actions pushdef([yuck_flag_action], [tgt->yuck_slot([$1], [$2])++])dnl pushdef([yuck_arg_action], [tgt->yuck_slot([$1], [$2]) = arg ?: argv[[++i]]])dnl pushdef([yuck_arg_opt_action], [tgt->yuck_slot([$1], [$2]) = arg ?: YUCK_OPTARG_NONE])dnl pushdef([yuck_arg_mul_action], [tgt->yuck_slot([$1], [$2]) = yuck_append( tgt->yuck_slot([$1], [$2]), tgt->yuck_cnt_slot([$1], [$2])++, arg ?: argv[[++i]])])dnl pushdef([yuck_arg_mul_opt_action], [tgt->yuck_slot([$1], [$2]) = yuck_append( tgt->yuck_slot([$1], [$2]), tgt->yuck_cnt_slot([$1], [$2])++, arg ?: YUCK_OPTARG_NONE)])dnl pushdef([yuck_auto_action], [/* invoke auto action and exit */ yuck_auto_[]yuck_canon([$1], [$2])(tgt); resume_at(success)])dnl foreachq([__CMD], yuck_umbcmds(), [coroutine(yuck_cmd(defn([__CMD]))[_longopt]) { if (0) { ; }dnl foreachq([__IDN], yuck_idents(defn([__CMD])), [ dnl pushdef([long], yuck_long(defn([__IDN]), defn([__CMD])))[]dnl ifelse(defn([long]), [], [divert(-1)])dnl else if (yuck_streqp(op, "defn([long])")) { popdef([long])[]dnl dnl now simply expand yuck_foo_action: yuck_option_action(defn([__IDN]), defn([__CMD])); }dnl divert[]dnl ]) else { ifelse(defn([__CMD]), [], [dnl ifdef([YOPT_ALLOW_UNKNOWN_DASHDASH], [dnl /* just treat it as argument then */ resume_at(arg); ], [dnl /* grml */ fprintf(stderr, "YUCK_UMB_STR: unrecognized option `--%s'\n", op); resume_at(failure); ])dnl ], [dnl resume_at(yuck_cmd()[_longopt]); ])dnl } resume; } ]) popdef([yuck_flag_action])dnl popdef([yuck_arg_action])dnl popdef([yuck_arg_mul_action])dnl popdef([yuck_arg_opt_action])dnl popdef([yuck_arg_mul_opt_action])dnl popdef([yuck_auto_action])dnl } coroutine(shortopt) { char *arg = op + 1U; switch (tgt->cmd) { default: yield(yuck_cmd()[_shortopt]); break; foreachq([__CMD], yuck_cmds(), [case yuck_cmd(defn([__CMD])): yield(yuck_cmd(defn([__CMD]))[_shortopt]); break; ])} resume; dnl TYPE actions pushdef([yuck_flag_action], [tgt->yuck_slot([$1], [$2])++])dnl pushdef([yuck_arg_action], [tgt->yuck_slot([$1], [$2]) = *arg ? (op += strlen(arg), arg) : argv[[++i]]])dnl pushdef([yuck_arg_opt_action], [tgt->yuck_slot([$1], [$2]) = *arg ? (op += strlen(arg), arg) : YUCK_OPTARG_NONE])dnl pushdef([yuck_arg_mul_action], [tgt->yuck_slot([$1], [$2]) = yuck_append( tgt->yuck_slot([$1], [$2]), tgt->yuck_cnt_slot([$1], [$2])++, *arg ? (op += strlen(arg), arg) : argv[[++i]])])dnl pushdef([yuck_arg_mul_opt_action], [tgt->yuck_slot([$1], [$2]) = yuck_append( tgt->yuck_slot([$1], [$2]), tgt->yuck_cnt_slot([$1], [$2])++, *arg ? (op += strlen(arg), arg) : YUCK_OPTARG_NONE)])dnl pushdef([yuck_auto_action], [/* invoke auto action and exit */ yuck_auto_[]yuck_canon([$1], [$2])(tgt); resume_at(success)])dnl foreachq([__CMD], yuck_umbcmds(), [coroutine(yuck_cmd(defn([__CMD]))[_shortopt]) { switch (*op) { default: divert(1); ifdef([YOPT_ALLOW_UNKNOWN_DASH], [dnl resume_at(arg); ], [dnl fprintf(stderr, "YUCK_UMB_STR: invalid option -%c\n", *op); resume_at(failure); ])dnl ifdef([YUCK_SHORTS_HAVE_NUMERALS], [ /* [yuck_shorts()] (= yuck_shorts()) * has numerals as shortopts * don't allow literal treatment of numerals */divert(-1)]) case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* literal treatment of numeral */ resume_at(arg); divert(2); resume_at(yuck_cmd()[_shortopt]); divert(0); ifelse(defn([__CMD]), [], [select_divert(1)], [select_divert(2)])dnl divert[]dnl foreachq([__IDN], yuck_idents(defn([__CMD])), [dnl pushdef([short], yuck_short(defn([__IDN]), defn([__CMD])))dnl ifelse(defn([short]), [], [divert(-1)])dnl case 'defn([short])': popdef([short])dnl dnl dnl now simply expand yuck_foo_action: yuck_option_action(defn([__IDN]), defn([__CMD])); break; divert[]dnl ])dnl } resume; } ]) popdef([yuck_flag_action])dnl popdef([yuck_arg_action])dnl popdef([yuck_arg_opt_action])dnl popdef([yuck_arg_mul_action])dnl popdef([yuck_arg_mul_opt_action])dnl popdef([yuck_auto_action])dnl } coroutine(arg) { if (tgt->cmd || !YUCK_NCMDS) { args[[tgt->nargs++]] = argv[[i]]; } else { /* ah, might be an arg then */ if ((tgt->cmd = yuck_parse_cmd(op)) > YUCK_NCMDS) { return -1; } } resume; } coroutine(failure) { exit(EXIT_FAILURE); } coroutine(success) { exit(EXIT_SUCCESS); } } DEFUN void yuck_free(yuck_t tgt[[static 1U]]) { if (tgt->args != NULL) { /* free despite const qualifier */ free(tgt->args); } /* free mulargs */ switch (tgt->cmd) { void *ptr; default: break; pushdef([action], [dnl ptr = tgt->yuck_slot([$1], [$2]); if (ptr != NULL) { free(ptr); } ])dnl dnl TYPE actions pushdef([yuck_flag_action], [])dnl pushdef([yuck_arg_action], [])dnl pushdef([yuck_arg_opt_action], [])dnl pushdef([yuck_arg_mul_action], defn([action]))dnl pushdef([yuck_arg_mul_opt_action], defn([action]))dnl pushdef([yuck_auto_action], [])dnl foreachq([__CMD], yuck_umbcmds(), [dnl case yuck_cmd(defn([__CMD])): foreachq([__IDN], yuck_idents(defn([__CMD])), [dnl yuck_option_action(defn([__IDN]), defn([__CMD])); break; ])[]dnl ])[]dnl popdef([action])dnl popdef([yuck_flag_action])dnl popdef([yuck_arg_action])dnl popdef([yuck_arg_opt_action])dnl popdef([yuck_arg_mul_action])dnl popdef([yuck_arg_mul_opt_action])dnl popdef([yuck_auto_opt_action])dnl break; } return; } DEFUN void yuck_auto_usage(const yuck_t src[[static 1U]]) { switch (src->cmd) { default: YUCK_NOCMD: puts("Usage: YUCK_UMB_STR [[OPTION]]...dnl ifelse(yuck_cmds(), [], [], [ COMMAND])[]dnl ifelse(defn([YUCK_UMB_POSARG]), [], [], [ defn([YUCK_UMB_POSARG])])\n\ ifelse(yuck_umb_desc(), [], [], [dnl \n\ yuck_C_literal(yuck_umb_desc())\n\ ])dnl "); break; foreachq([__CMD], yuck_cmds(), [ case yuck_cmd(defn([__CMD])): puts("Usage: YUCK_UMB_STR dnl yuck_cmd_string(defn([__CMD]))[]dnl ifelse(yuck_idents(defn([__CMD])), [], [], [ [[OPTION]]...])[]dnl ifelse(yuck_cmd_posarg(defn([__CMD])), [], [], [ yuck_cmd_posarg(defn([__CMD]))])\n\ ifelse(yuck_cmd_desc(defn([__CMD])), [], [], [dnl \n\ yuck_C_literal(yuck_cmd_desc(defn([__CMD])))\n\ ])dnl "); break; ]) } #if defined yuck_post_usage yuck_post_usage(src); #endif /* yuck_post_usage */ return; } DEFUN void yuck_auto_help(const yuck_t src[[static 1U]]) { yuck_auto_usage(src); ifelse(yuck_cmds(), [], [], [dnl if (src->cmd == YUCK_NOCMD) { /* also output a list of commands */ puts("COMMAND may be one of:\n\ foreachq([__CMD], yuck_cmds(), [yuck_C_literal(yuck_cmd_line(defn([__CMD])))\n\ ])"); } ])dnl /* leave a not about common options */ if (src->cmd == YUCK_NOCMD) { ifelse(yuck_cmds(), [], [dnl ; ], [dnl puts("\ Options accepted by all commands:"); ])dnl ifelse(yuck_cmds(), [], [], [dnl } else { puts("\ Common options:\n\ foreachq([__IDN], yuck_idents([]), [dnl yuck_C_literal(backquote([yuck_option_help_line(defn([__IDN]), [])]))[]dnl ])dnl "); ])dnl } switch (src->cmd) { default:foreachq([__CMD], yuck_umbcmds(), [ case yuck_cmd(defn([__CMD])): puts("\ ifelse(defn([__CMD]), [], [], [dnl ifelse(yuck_idents(defn([__CMD])), [], [], [dnl Command-specific options:\n\ ])dnl ])dnl foreachq([__IDN], yuck_idents(defn([__CMD])), [dnl yuck_C_literal(backquote([yuck_option_help_line(defn([__IDN]), defn([__CMD]))]))[]dnl ])dnl "); break; ]) } #if defined yuck_post_help yuck_post_help(src); #endif /* yuck_post_help */ #if defined PACKAGE_BUGREPORT puts("\n\ Report bugs to " PACKAGE_BUGREPORT); #endif /* PACKAGE_BUGREPORT */ return; } DEFUN void yuck_auto_version(const yuck_t src[[static 1U]]) { switch (src->cmd) { default: ifdef([YUCK_VERSION], [dnl puts("YUCK_UMB_STR YUCK_VERSION"); ], [dnl #if 0 #elif defined package_string puts(package_string); #elif defined package_version printf("YUCK_UMB_STR %s\n", package_version); #elif defined PACKAGE_STRING puts(PACKAGE_STRING); #elif defined PACKAGE_VERSION puts("YUCK_UMB_STR " PACKAGE_VERSION); #elif defined VERSION puts("YUCK_UMB_STR " VERSION); #else /* !PACKAGE_VERSION, !VERSION */ puts("YUCK_UMB_STR unknown version"); #endif /* PACKAGE_VERSION */ ])dnl break; } #if defined yuck_post_version yuck_post_version(src); #endif /* yuck_post_version */ return; } popdef([DEFUN])dnl #if defined __INTEL_COMPILER # pragma warning (default:177) # pragma warning (default:111) #elif defined __GNUC__ # if __GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6 # pragma GCC diagnostic pop # endif /* GCC version */ #endif /* __INTEL_COMPILER */ changequote`'dnl dateutils-0.3.1/build-aux/yuck-coru.h.m4000066400000000000000000000064731241477753400200440ustar00rootroot00000000000000/* -*- c -*- */ changequote`'changequote([,])dnl changecom([#])dnl #if !defined INCLUDED_yuck_h_ #define INCLUDED_yuck_h_ #include #define YUCK_OPTARG_NONE ((void*)0x1U) enum yuck_cmds_e { pushdef([last], yuck_cmd())pushdef([first], defn([last]))[]dnl /* value used when no command was specified */ first = 0U, /* actual commands */ foreachq([cmd], yuck_cmds(), [define([last], yuck_cmd(defn([cmd])))[]last, ]) /* convenience identifiers */ YUCK_NOCMD = first, YUCK_NCMDS = last popdef([last])popdef([first])[]dnl }; define([yuck_slot_predecl], [dnl yuck_iftype([$1], [$2], [arg,mul], [size_t ]yuck_canon([$1], [$2])[_nargs], [arg,mul,opt], [size_t ]yuck_canon([$1], [$2])[_nargs], )dnl ])dnl define([yuck_slot_decl], [dnl pushdef([pre], [yuck_slot_predecl([$1], [$2])])dnl pushdef([ident], [yuck_slot_identifier([$1], [$2])])dnl yuck_iftype([$1], [$2], [flag], [unsigned int ident;], [arg], [char *ident;], [arg,opt], [char *ident;], [arg,mul], [pre; char **ident;], [arg,mul,opt], [pre; char **ident;], [auto], [/* $1 is handled automatically */])dnl popdef([pre])dnl popdef([ident])dnl ])dnl ifelse(yuck_cmds(), [], [dnl typedef struct yuck_s yuck_t; ], [dnl typedef union yuck_u yuck_t; ])dnl foreachq([cmd], yuck_cmds(), [ /* convenience structure for `cmd' */ struct yuck_cmd_[]defn([cmd])[]_s { enum yuck_cmds_e [cmd]; /* left-over arguments, the command string is never a part of this */ size_t nargs; char **args; foreachq([slot], yuck_idents(), [ yuck_slot_decl(defn([slot]))[]dnl ]) foreachq([slot], yuck_idents(defn([cmd])), [ yuck_slot_decl(defn([slot]), defn([cmd]))[]dnl ]) }; ]) ifelse(yuck_cmds(), [], [dnl /* generic struct */ struct yuck_s { enum yuck_cmds_e cmd; /* left-over arguments, * the command string is never a part of this */ size_t nargs; char **args; /* slots common to all commands */ foreachq([slot], yuck_idents(), [ yuck_slot_decl(defn([slot]))[]dnl ]) }; ], [dnl else union yuck_u { /* generic struct */ struct { enum yuck_cmds_e cmd; /* left-over arguments, * the command string is never a part of this */ size_t nargs; char **args; /* slots common to all commands */ foreachq([slot], yuck_idents(), [dnl yuck_slot_decl(defn([slot])) ])dnl }; /* depending on CMD at most one of the following structs is filled in * if CMD is YUCK_NONE no slots of this union must be accessed */ foreachq([cmd], yuck_cmds(), [dnl struct yuck_cmd_[]defn([cmd])[]_s defn([cmd]); ])dnl }; ]) pushdef([DECLF], ifdef([YUCK_HEADER], [extern], [static]))[]dnl DECLF __attribute__((nonnull(1))) int yuck_parse(yuck_t*, int argc, char *argv[[]]); DECLF __attribute__((nonnull(1))) void yuck_free(yuck_t*); DECLF __attribute__((nonnull(1))) void yuck_auto_help(const yuck_t*); DECLF __attribute__((nonnull(1))) void yuck_auto_usage(const yuck_t*); DECLF __attribute__((nonnull(1))) void yuck_auto_version(const yuck_t*); /* some hooks */ #if defined yuck_post_help DECLF __attribute__((nonnull(1))) void yuck_post_help(const yuck_t*); #endif /* yuck_post_help */ #if defined yuck_post_usage DECLF __attribute__((nonnull(1))) void yuck_post_usage(const yuck_t*); #endif /* yuck_post_usage */ #if defined yuck_post_version DECLF __attribute__((nonnull(1))) void yuck_post_version(const yuck_t*); #endif /* yuck_post_version */ popdef([DECLF])[]dnl #endif /* INCLUDED_yuck_h_ */ changequote`'dnl dateutils-0.3.1/build-aux/yuck-scmver.c000066400000000000000000000501541241477753400200420ustar00rootroot00000000000000/*** yuck-scmver.c -- snarf versions off project cwds * * Copyright (C) 2013-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of yuck. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***/ #if defined HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include #include #include #include #if !defined LIKELY # define LIKELY(_x) __builtin_expect((_x), 1) #endif /* !LIKELY */ #if !defined UNLIKELY # define UNLIKELY(_x) __builtin_expect((_x), 0) #endif /* UNLIKELY */ #if !defined UNUSED # define UNUSED(_x) _x __attribute__((unused)) #endif /* !UNUSED */ #if !defined countof # define countof(x) (sizeof(x) / sizeof(*x)) #endif /* !countof */ #define _paste(x, y) x ## y #define paste(x, y) _paste(x, y) #if !defined with # define with(args...) \ for (args, *paste(__ep, __LINE__) = (void*)1; \ paste(__ep, __LINE__); paste(__ep, __LINE__) = 0) #endif /* !with */ #define DEBUG(args...) static __attribute__((format(printf, 1, 2))) void error(const char *fmt, ...) { va_list vap; va_start(vap, fmt); vfprintf(stderr, fmt, vap); va_end(vap); if (errno) { fputc(':', stderr); fputc(' ', stderr); fputs(strerror(errno), stderr); } fputc('\n', stderr); return; } static inline __attribute__((const, pure, always_inline)) char* deconst(const char *s) { union { const char *c; char *p; } x = {s}; return x.p; } static __attribute__((unused)) size_t xstrlcpy(char *restrict dst, const char *src, size_t dsz) { size_t ssz; if (UNLIKELY(dsz == 0U)) { return 0U; } if ((ssz = strlen(src)) > dsz) { ssz = dsz - 1U; } memcpy(dst, src, ssz); dst[ssz] = '\0'; return ssz; } static __attribute__((unused)) size_t xstrlncpy(char *restrict dst, size_t dsz, const char *src, size_t ssz) { if (UNLIKELY(dsz == 0U)) { return 0U; } if (ssz > dsz) { ssz = dsz - 1U; } memcpy(dst, src, ssz); dst[ssz] = '\0'; return ssz; } static char* xdirname(char *restrict fn, const char *fp) { /* find next dir in FN from FP backwards */ if (fp == NULL) { fp = fn + strlen(fn); } while (--fp >= fn && *fp != '/'); while (fp >= fn && *--fp == '/'); if (fp >= fn) { /* replace / by \nul and return pointer */ char *dp = fn + (++fp - fn); *dp = '\0'; return dp; } /* return \nul */ return NULL; } static char* xmemmem(const char *hay, const size_t hayz, const char *ndl, const size_t ndlz) { const char *const eoh = hay + hayz; const char *const eon = ndl + ndlz; const char *hp; const char *np; const char *cand; unsigned int hsum; unsigned int nsum; unsigned int eqp; /* trivial checks first * a 0-sized needle is defined to be found anywhere in haystack * then run strchr() to find a candidate in HAYSTACK (i.e. a portion * that happens to begin with *NEEDLE) */ if (ndlz == 0UL) { return deconst(hay); } else if ((hay = memchr(hay, *ndl, hayz)) == NULL) { /* trivial */ return NULL; } /* First characters of haystack and needle are the same now. Both are * guaranteed to be at least one character long. Now computes the sum * of characters values of needle together with the sum of the first * needle_len characters of haystack. */ for (hp = hay + 1U, np = ndl + 1U, hsum = *hay, nsum = *hay, eqp = 1U; hp < eoh && np < eon; hsum ^= *hp, nsum ^= *np, eqp &= *hp == *np, hp++, np++); /* HP now references the (NZ + 1)-th character. */ if (np < eon) { /* haystack is smaller than needle, :O */ return NULL; } else if (eqp) { /* found a match */ return deconst(hay); } /* now loop through the rest of haystack, * updating the sum iteratively */ for (cand = hay; hp < eoh; hp++) { hsum ^= *cand++; hsum ^= *hp; /* Since the sum of the characters is already known to be * equal at that point, it is enough to check just NZ - 1 * characters for equality, * also CAND is by design < HP, so no need for range checks */ if (hsum == nsum && memcmp(cand, ndl, ndlz - 1U) == 0) { return deconst(cand); } } return NULL; } static unsigned int hextou(const char *sp, char **ep) { register unsigned int res = 0U; size_t i; if (UNLIKELY(sp == NULL)) { goto out; } else if (*sp == '\0') { goto out; } for (i = 0U; i < sizeof(res) * 8U / 4U - 1U; sp++, i++) { register unsigned int this; switch (*sp) { case '0' ... '9': this = *sp - '0'; break; case 'a' ... 'f': this = *sp - 'a' + 10U; break; case 'A' ... 'F': this = *sp - 'A' + 10U; break; default: goto fucked; } res <<= 4U; res |= this; } fucked: res <<= 4U; res |= i; /* keep reading the hexstring as long as it lasts */ for (;; sp++) { switch (*sp) { case '0' ... '9': case 'a' ... 'f': case 'A' ... 'F': continue; default: goto out; } } out: if (ep != NULL) { *ep = (char*)1U + (sp - (char*)1U); } return res; } /* version snarfers */ static __attribute__((noinline)) pid_t run(int *fd, ...) { static char *cmdline[16U]; va_list vap; pid_t p; /* to snarf off traffic from the child */ int intfd[2]; va_start(vap, fd); for (size_t i = 0U; i < countof(cmdline) && (cmdline[i] = va_arg(vap, char*)) != NULL; i++); va_end(vap); if (pipe(intfd) < 0) { error("pipe setup to/from %s failed", cmdline[0U]); return -1; } switch ((p = vfork())) { case -1: /* i am an error */ error("vfork for %s failed", cmdline[0U]); return -1; default: /* i am the parent */ close(intfd[1]); if (fd != NULL) { *fd = intfd[0]; } else { close(intfd[0]); } return p; case 0: /* i am the child */ break; } /* child code here */ close(intfd[0]); dup2(intfd[1], STDOUT_FILENO); execvp(cmdline[0U], cmdline); error("execvp(%s) failed", cmdline[0U]); _exit(EXIT_FAILURE); } static int fin(pid_t p) { int rc = 2; int st; while (waitpid(p, &st, 0) != p); if (WIFEXITED(st)) { rc = WEXITSTATUS(st); } return rc; } static yuck_scm_t find_scm(char *restrict fn, size_t fz, const char *path) { struct stat st[1U]; char *restrict dp = fn; /* make a copy so we can fiddle with it */ if (UNLIKELY(path == NULL)) { cwd: /* just use "." then */ *dp++ = '.'; *dp = '\0'; } else if ((dp += xstrlcpy(fn, path, fz)) == fn) { goto cwd; } again: if (stat(fn, st) < 0) { return YUCK_SCM_ERROR; } else if (UNLIKELY((size_t)(dp - fn) + 5U >= fz)) { /* not enough space */ return YUCK_SCM_ERROR; } else if (!S_ISDIR(st->st_mode)) { /* not a directory, get the dir bit and start over */ if ((dp = xdirname(fn, dp)) == NULL) { dp = fn; goto cwd; } goto again; } scm_chk: /* now check for .git, .bzr, .hg */ xstrlcpy(dp, "/.git", fz - (dp - fn)); DEBUG("trying %s ...\n", fn); if (stat(fn, st) == 0 && S_ISDIR(st->st_mode)) { /* yay it's a .git */ *dp = '\0'; return YUCK_SCM_GIT; } xstrlcpy(dp, "/.bzr", fz - (dp - fn)); DEBUG("trying %s ...\n", fn); if (stat(fn, st) == 0 && S_ISDIR(st->st_mode)) { /* yay it's a .git */ *dp = '\0'; return YUCK_SCM_BZR; } xstrlcpy(dp, "/.hg", fz - (dp - fn)); DEBUG("trying %s ...\n", fn); if (stat(fn, st) == 0 && S_ISDIR(st->st_mode)) { /* yay it's a .git */ *dp = '\0'; return YUCK_SCM_HG; } /* nothing then, traverse upwards */ if (*fn != '/') { /* make sure we don't go up indefinitely * comparing the current inode to ./.. */ with (ino_t curino) { *dp = '\0'; if (stat(fn, st) < 0) { return YUCK_SCM_ERROR; } /* memorise inode */ curino = st->st_ino; /* go upwards by appending /.. */ dp += xstrlcpy(dp, "/..", fz - (dp - fn)); /* check inode again */ if (stat(fn, st) < 0) { return YUCK_SCM_ERROR; } else if (st->st_ino == curino) { break; } goto scm_chk; } } else if ((dp = xdirname(fn, dp)) != NULL) { goto scm_chk; } return YUCK_SCM_TARBALL; } static int rd_version(struct yuck_version_s *restrict v, const char *buf, size_t bsz) { /* reads a normalised version string vX.Y.Z-DIST-SCM RVSN[-dirty] */ static const char dflag[] = "dirty"; const char *vtag = NULL; const char *eov; const char *dist = NULL; const char *eod; const char *bp = buf; const char *const ep = buf + bsz; /* parse buf */ switch (*bp) { case 'v': case 'V': bp++; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; default: /* weird, we req'd v-tags */ return -1; } if ((eov = memchr(vtag = bp, '-', ep - bp)) == NULL) { /* last field */ eov = ep; } else { dist = eov + 1U; } /* just for the fun of it, look for .git, .hg and .bzr as well */ with (const char *altp) { if ((altp = xmemmem(vtag, ep - vtag, ".git", 4U))) { v->scm = YUCK_SCM_GIT; eov = altp; dist = altp + 4U; } else if ((altp = xmemmem(vtag, ep - vtag, ".bzr", 4U))) { /* oooh looks like the alternative version * vX.Y.Z.gitDD.HASH */ v->scm = YUCK_SCM_BZR; eov = altp; dist = altp + 4U; } else if ((altp = xmemmem(vtag, ep - vtag, ".hg", 3U))) { /* oooh looks like the alternative version * vX.Y.Z.hgDD.HASH */ v->scm = YUCK_SCM_HG; eov = altp; dist = altp + 3U; } } /* bang vtag */ xstrlncpy(v->vtag, sizeof(v->vtag), vtag, eov - vtag); /* snarf distance */ if (dist == NULL) { return 0; } /* read distance */ with (char *on) { v->dist = strtoul(dist, &on, 10); eod = on; } switch (*eod) { default: case '\0': return 0; case '.': case '-': /* the show is going on, like it must */ bp = eod + 1U; break; } switch (*bp++) { case 'g': /* git repo */ v->scm = YUCK_SCM_GIT; break; case 'h': /* hg repo */ v->scm = YUCK_SCM_HG; break; case 'b': /* bzr repo */ v->scm = YUCK_SCM_BZR; break; default: /* could have been set already then */ if (v->scm > YUCK_SCM_TARBALL) { /* rewind bp and continue */ bp--; break; } /* otherwise we simply don't know */ return 0; } /* read scm revision */ with (char *on) { v->rvsn = hextou(bp, &on); bp = on; } if (bp >= ep) { ; } else if (*bp != '-' && *bp != '.') { ; } else if (bp + sizeof(dflag) > ep) { /* too short to fit `dirty' */ ; } else if (!memcmp(++bp, dflag, sizeof(dflag) - 1U)) { v->dirty = 1U; } return 0; } static ssize_t wr_version(char *restrict buf, size_t bsz, const struct yuck_version_s *v) { static const char yscm_abbr[] = "tgbh"; const char *const ep = buf + bsz; char *bp = buf; if (UNLIKELY(buf == NULL || bsz == 0U)) { return -1; } *bp++ = 'v'; bp += xstrlcpy(bp, v->vtag, ep - bp); if (!v->dist) { goto out; } else if (bp + 1U >= ep) { /* not enough space */ return -1; } /* get the dist bit on the wire */ *bp++ = '-'; bp += snprintf(bp, ep - bp, "%u", v->dist); if (!v->rvsn || v->scm <= YUCK_SCM_TARBALL) { goto out; } else if (bp + 2U + 8U >= ep) { /* not enough space */ return -1; } *bp++ = '-'; *bp++ = yscm_abbr[v->scm]; bp += snprintf(bp, ep - bp, "%0*x", (int)(v->rvsn & 0x07U), v->rvsn >> 4U); if (!v->dirty) { goto out; } else if (bp + 1U + 5U >= ep) { /* not enough space */ return -1; } bp += xstrlcpy(bp, "-dirty", ep - bp); out: return bp - buf; } static int git_version(struct yuck_version_s v[static 1U]) { pid_t chld; int fd[1U]; int rc = 0; if ((chld = run(fd, "git", "describe", "--match=v[0-9]*", "--abbrev=8", "--dirty", NULL)) < 0) { return -1; } /* shouldn't be heaps, so just use a single read */ with (char buf[256U]) { const char *vtag; const char *dist; char *bp; ssize_t nrd; if ((nrd = read(*fd, buf, sizeof(buf))) <= 0) { /* no version then aye */ rc = -1; break; } buf[nrd - 1U/* for \n*/] = '\0'; /* parse buf */ bp = buf; if (*bp++ != 'v') { /* weird, we req'd v-tags though */ rc = -1; break; } else if ((bp = strchr(vtag = bp, '-')) != NULL) { /* tokenise sting */ *bp++ = '\0'; } /* bang vtag */ xstrlcpy(v->vtag, vtag, sizeof(v->vtag)); /* snarf distance */ if (bp == NULL) { break; } else if ((bp = strchr(dist = bp, '-')) != NULL) { /* tokenize */ *bp++ = '\0'; } /* read distance */ v->dist = strtoul(dist, &bp, 10); if (*++bp == 'g') { bp++; /* read scm revision */ v->rvsn = hextou(bp, &bp); } if (*bp == '\0') { break; } else if (*bp == '-') { bp++; } if (!strcmp(bp, "dirty")) { v->dirty = 1U; } } close(*fd); if (fin(chld) != 0) { rc = -1; } return rc; } static int hg_version(struct yuck_version_s v[static 1U]) { pid_t chld; int fd[1U]; int rc = 0; if ((chld = run(fd, "hg", "log", "--rev", ".", "--template", "{latesttag}\t{latesttagdistance}\t{node|short}\n", NULL)) < 0) { return -1; } /* shouldn't be heaps, so just use a single read */ with (char buf[256U]) { const char *vtag; const char *dist; char *bp; ssize_t nrd; if ((nrd = read(*fd, buf, sizeof(buf))) <= 0) { /* no version then aye */ break; } buf[nrd - 1U/* for \n*/] = '\0'; /* parse buf */ bp = buf; if (*bp++ != 'v') { /* technically we could request the latest v-tag * but i'm no hg buff so fuck it */ rc = -1; break; } else if ((bp = strchr(vtag = bp, '\t')) != NULL) { /* tokenise */ *bp++ = '\0'; } /* bang vtag */ xstrlcpy(v->vtag, vtag, sizeof(v->vtag)); if (UNLIKELY(bp == NULL)) { /* huh? */ rc = -1; break; } else if ((bp = strchr(dist = bp, '\t')) != NULL) { /* tokenise */ *bp++ = '\0'; } /* bang distance */ v->dist = strtoul(dist, NULL, 10); /* bang revision */ v->rvsn = hextou(bp, NULL); } close(*fd); if (fin(chld) != 0) { rc = -1; } return rc; } static int bzr_version(struct yuck_version_s v[static 1U]) { pid_t chld; int fd[1U]; int rc = 0; /* first get current revision number */ if ((chld = run(fd, "bzr", "revno", NULL)) < 0) { return -1; } /* shouldn't be heaps, so just use a single read */ with (char buf[256U]) { ssize_t nrd; if ((nrd = read(*fd, buf, sizeof(buf))) <= 0) { /* no version then aye */ break; } with (char *on) { v->rvsn = strtoul(buf, &on, 10); if (LIKELY(on != NULL)) { v->rvsn <<= 4U; v->rvsn |= on - buf; } } } close(*fd); if (fin(chld) != 0) { return -1; } if ((chld = run(fd, "bzr", "tags", "--sort=time", NULL)) < 0) { return -1; } /* could be a lot, we only need the last line though */ with (char buf[4096U]) { const char *vtag; size_t bz; char *bp; ssize_t nrd; bp = buf; bz = sizeof(buf); while ((nrd = read(*fd, bp, bz)) == (ssize_t)bz) { /* find last line */ while (bz-- > 0 && buf[bz] != '\n'); /* reassess bz */ bz++; /* reassess bp */ bp = buf + (sizeof(buf) - bz); if (LIKELY(bz < sizeof(buf))) { memmove(buf, buf + bz, sizeof(buf) - bz); } } if (nrd <= 0) { /* no version then aye */ break; } bp[nrd - 1U/* for \n*/] = '\0'; /* find last line */ bp += nrd; while (--bp >= buf && *bp != '\n'); /* parse buf */ if (*++bp != 'v') { /* we want v tags, we could go back and see if * there are any */ rc = -1; break; } else if ((bp = strchr(vtag = ++bp, ' ')) != NULL) { /* tokenise */ *bp++ = '\0'; } /* bang vtag */ xstrlcpy(v->vtag, vtag, sizeof(v->vtag)); if (bp == NULL) { break; } /* read over all the whitespace to find the tag's revno */ while (*++bp == ' '); with (unsigned int rno = strtoul(bp, NULL, 10)) { v->dist = v->rvsn - rno; } } close(*fd); if (fin(chld) != 0) { rc = -1; } return rc; } /* public api */ #if !defined PATH_MAX # define PATH_MAX (256U) #endif /* !PATH_MAX */ int yuck_version(struct yuck_version_s *restrict v, const char *path) { char cwd[PATH_MAX]; char fn[PATH_MAX]; int rc = -1; /* initialise result structure */ memset(v, 0, sizeof(*v)); if (getcwd(cwd, sizeof(cwd)) == NULL) { return -1; } switch ((v->scm = find_scm(fn, sizeof(fn), path))) { case YUCK_SCM_ERROR: case YUCK_SCM_TARBALL: default: /* can't determine version numbers in tarball, can we? */ return -1; case YUCK_SCM_GIT: case YUCK_SCM_BZR: case YUCK_SCM_HG: if (chdir(fn) < 0) { break; } switch (v->scm) { case YUCK_SCM_GIT: rc = git_version(v); break; case YUCK_SCM_BZR: rc = bzr_version(v); break; case YUCK_SCM_HG: rc = hg_version(v); break; default: break; } if (chdir(cwd) < 0) { /* oh big cluster fuck */ rc = -1; } break; } return rc; } int yuck_version_read(struct yuck_version_s *restrict ref, const char *fn) { int rc = 0; int fd; /* initialise result structure */ memset(ref, 0, sizeof(*ref)); if ((fd = open(fn, O_RDONLY)) < 0) { return -1; } /* otherwise read and parse the string */ with (char buf[256U]) { ssize_t nrd; char *bp; if ((nrd = read(fd, buf, sizeof(buf))) <= 0) { /* no version then aye */ rc = -1; break; } else if ((bp = memchr(buf, '\n', nrd)) != NULL) { /* just go with the first line */ *bp = '\0'; nrd = bp - buf; } else { /* finalise with \nul */ buf[--nrd] = '\0'; } /* otherwise just read him */ rc = rd_version(ref, buf, nrd); } close(fd); return rc; } ssize_t yuck_version_write_fd(int fd, const struct yuck_version_s *ref) { char buf[256U]; ssize_t nwr; if ((nwr = wr_version(buf, sizeof(buf), ref)) <= 0) { return -1; } /* otherwise write */ buf[nwr++] = '\n'; return write(fd, buf, nwr); } int yuck_version_write(const char *fn, const struct yuck_version_s *ref) { int rc = 0; int fd; if ((fd = open(fn, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0) { return -1; } if (yuck_version_write_fd(fd, ref) < 0) { rc = -1; } close(fd); return rc; } int yuck_version_cmp(yuck_version_t v1, yuck_version_t v2) { if (v1->dist == 0U && v2->dist == 0U) { /* must be a tag then, innit? */ return memcmp(v1->vtag, v2->vtag, sizeof(v1->vtag)); } /* just brute force the comparison, consider -dirty > -clean */ return memcmp(v1, v2, sizeof(*v1)); } #if defined BOOTSTRAP static const char *yscm_strs[] = { [YUCK_SCM_TARBALL] = "tarball", [YUCK_SCM_GIT] = "git", [YUCK_SCM_BZR] = "bzr", [YUCK_SCM_HG] = "hg", }; int main(int argc, char *argv[]) { /* usage would be yuck-scmver SCMDIR [REFERENCE] */ static struct yuck_version_s v[1U]; int rc = 0; switch ((rc = yuck_version(v, argv[1U]))) { default: /* one more chance there is */ if (argc <= 2) { /* no reference file given */ break; } else if ((rc = yuck_version_read(v, argv[2U])) < 0) { /* ok, can't help it then */ break; } /* yay, fallthrough to success */ case 0: fputs("define(YUCK_SCMVER_VERSION, ", stdout); fputs(v->vtag, stdout); if (v->scm > YUCK_SCM_TARBALL && v->dist) { fputc('.', stdout); fputs(yscm_strs[v->scm], stdout); fprintf(stdout, "%u.%0*x", v->dist, (int)(v->rvsn & 0x07U), v->rvsn >> 4U); } if (v->dirty) { fputs(".dirty", stdout); } fputs(")\n", stdout); break; } return -rc; } #endif /* BOOTSTRAP */ /* yuck-scmver.c ends here */ dateutils-0.3.1/build-aux/yuck-scmver.h000066400000000000000000000055531241477753400200520ustar00rootroot00000000000000/*** yuck-version.h -- snarf versions off project cwds * * Copyright (C) 2013-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of yuck. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***/ #if !defined INCLUDED_yuck_version_h_ #define INCLUDED_yuck_version_h_ typedef const struct yuck_version_s *yuck_version_t; typedef enum { YUCK_SCM_ERROR = -1, YUCK_SCM_TARBALL, YUCK_SCM_GIT, YUCK_SCM_BZR, YUCK_SCM_HG, } yuck_scm_t; struct yuck_version_s { yuck_scm_t scm; unsigned int dirty:1U; char vtag[16U]; unsigned int dist; /* up to 28bits of revision id (hash for git), * the lower 4bits denote the length */ unsigned int rvsn; }; /* public api */ /** * Determine SCM version of file(s) in PATH. */ extern int yuck_version(struct yuck_version_s *restrict v, const char *path); /** * Read a reference file FN and return scm version information. */ extern int yuck_version_read(struct yuck_version_s *restrict, const char *fn); /** * Write scm version information in V to reference file FN. */ extern int yuck_version_write(const char *fn, const struct yuck_version_s *v); /** * Write scm version into buffer. */ extern ssize_t yuck_version_write_fd(int fd, const struct yuck_version_s *v); /** * Compare two version objects, return <0 if V1 < V2, >0 if V1 > V2 and * 0 if V1 and V2 are considered equal. */ extern int yuck_version_cmp(yuck_version_t v1, yuck_version_t v2); #endif /* INCLUDED_yuck_version_h_ */ dateutils-0.3.1/build-aux/yuck-scmver.m4000066400000000000000000000004241241477753400201330ustar00rootroot00000000000000changequote`'changequote([,])dnl divert([-1]) changecom([##]) ## we used to define YUCK_SCMVER_VERSION in m4 terms here ## however in C it's so much easier to come by with the same thing ## so we reserve this file for future (m4-based) goodness divert[]dnl changequote()dnl dateutils-0.3.1/build-aux/yuck.am000066400000000000000000000020471241477753400167160ustar00rootroot00000000000000## automake rules for yuck ## set the following variables in the including Makefile.am beforehand ## noinst_PROGRAMS ## BUILT_SOURCES ## EXTRA_DIST ## DISTCLEANFILES yuck_CPPFLAGS = -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -D_BSD_SOURCE yuck_CPPFLAGS += -D_ALL_SOURCE yuck_CPPFLAGS += -D_DARWIN_C_SOURCE yuck_CPPFLAGS += -D_NETBSD_SOURCE noinst_PROGRAMS += yuck-bootstrap yuck_bootstrap_SOURCES = yuck.c yuck_bootstrap_CPPFLAGS = $(yuck_CPPFLAGS) yuck_bootstrap_CPPFLAGS += -DBOOTSTRAP yuck_bootstrap_CPPFLAGS += -DWITH_SCMVER noinst_PROGRAMS += yuck yuck_SOURCES = yuck.c yuck.yuck yuck_SOURCES += yuck-scmver.c yuck-scmver.h yuck-scmver.m4 yuck_SOURCES += yuck.m4 yuck_SOURCES += yuck-coru.c.m4 yuck-coru.h.m4 yuck_SOURCES += yuck.man.m4 yuck_CPPFLAGS += -DYUCK_TEMPLATE_PATH='"$(abs_srcdir)"' yuck_CPPFLAGS += -DWITH_SCMVER BUILT_SOURCES += yuck.yucc ## aix make wants all prereq's to exist EXTRA_DIST += yuck.m4i EXTRA_DIST += yuck.yucc DISTCLEANFILES += yuck.m4i yuck.yucc ## also include custom Makefile recipes include $(srcdir)/yuck.mk dateutils-0.3.1/build-aux/yuck.c000066400000000000000000001243351241477753400165500ustar00rootroot00000000000000/*** yuck.c -- generate umbrella commands * * Copyright (C) 2013-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of yuck. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***/ #if defined HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ /* for fgetln() */ #if !defined _NETBSD_SOURCE # define _NETBSD_SOURCE #endif /* !_NETBSD_SOURCE */ #if !defined _DARWIN_SOURCE # define _DARWIN_SOURCE #endif /* !_DARWIN_SOURCE */ #if !defined _ALL_SOURCE # define _ALL_SOURCE #endif /* !_ALL_SOURCE */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined WITH_SCMVER # include #endif /* WITH_SCMVER */ #if !defined LIKELY # define LIKELY(_x) __builtin_expect((_x), 1) #endif /* !LIKELY */ #if !defined UNLIKELY # define UNLIKELY(_x) __builtin_expect((_x), 0) #endif /* UNLIKELY */ #if !defined UNUSED # define UNUSED(_x) _x __attribute__((unused)) #endif /* !UNUSED */ #if !defined countof # define countof(x) (sizeof(x) / sizeof(*x)) #endif /* !countof */ #define _paste(x, y) x ## y #define paste(x, y) _paste(x, y) #if !defined with # define with(args...) \ for (args, *paste(__ep, __LINE__) = (void*)1; \ paste(__ep, __LINE__); paste(__ep, __LINE__) = 0) #endif /* !with */ #if !defined HAVE_GETLINE && !defined HAVE_FGETLN /* as a service to people including this file in their project * but who might not necessarily run the corresponding AC_CHECK_FUNS * we assume that a getline() is available. */ # define HAVE_GETLINE 1 #endif /* !HAVE_GETLINE && !HAVE_FGETLN */ typedef enum { YOPT_NONE, YOPT_ALLOW_UNKNOWN_DASH, YOPT_ALLOW_UNKNOWN_DASHDASH, } yopt_t; struct usg_s { char *umb; char *cmd; char *parg; char *desc; }; struct opt_s { char sopt; char *lopt; char *larg; char *desc; unsigned int oarg:1U; unsigned int marg:1U; }; #if !defined BOOTSTRAP && defined WITH_SCMVER static const char *yscm_strs[] = { [YUCK_SCM_TARBALL] = "tarball", [YUCK_SCM_GIT] = "git", [YUCK_SCM_BZR] = "bzr", [YUCK_SCM_HG] = "hg", }; #elif !defined BOOTSTRAP /* just forward declare this type so function signatures will work */ struct yuck_version_s; #endif /* WITH_SCMVER */ static __attribute__((format(printf, 1, 2))) void error(const char *fmt, ...) { va_list vap; va_start(vap, fmt); vfprintf(stderr, fmt, vap); va_end(vap); if (errno) { fputs(": ", stderr); fputs(strerror(errno), stderr); } fputc('\n', stderr); return; } static inline __attribute__((unused)) void* deconst(const void *cp) { union { const void *c; void *p; } tmp = {cp}; return tmp.p; } static inline __attribute__((always_inline)) unsigned int yfls(unsigned int x) { return x ? sizeof(x) * 8U - __builtin_clz(x) : 0U; } static inline __attribute__((always_inline)) size_t max_zu(size_t x, size_t y) { return x > y ? x : y; } static size_t xstrncpy(char *restrict dst, const char *src, size_t ssz) { memcpy(dst, src, ssz); dst[ssz] = '\0'; return ssz; } static __attribute__((unused)) size_t xstrlcpy(char *restrict dst, const char *src, size_t dsz) { size_t ssz = strlen(src); if (ssz > dsz) { ssz = dsz - 1U; } memcpy(dst, src, ssz); dst[ssz] = '\0'; return ssz; } static __attribute__((unused)) size_t xstrlncpy(char *restrict dst, size_t dsz, const char *src, size_t ssz) { if (ssz > dsz) { ssz = dsz - 1U; } memcpy(dst, src, ssz); dst[ssz] = '\0'; return ssz; } static __attribute__((unused)) bool xstreqp(const char *s1, const char *s2) { if (s1 == NULL && s2 == NULL) { return true; } else if (s1 == NULL || s2 == NULL) { /* one of them isn't NULL */ return false; } /* resort to normal strcmp */ return !strcasecmp(s1, s2); } static bool only_whitespace_p(const char *line, size_t llen) { for (const char *lp = line, *const ep = line + llen; lp < ep; lp++) { if (!isspace(*lp)) { return false; } } return true; } static bool isdashdash(const char c) { switch (c) { default: return true; case '=': case '[': case ']': case '.': case '\0' ... ' ': return false; } } static void massage_desc(char *str) { /* kick final newline and escape m4 quoting characters */ char *sp; for (sp = str; *sp; sp++) { switch (*sp) { default: break; case '[': /* map to STX (start of text) */ *sp = '\002'; break; case ']': /* map to ETX (end of text) */ *sp = '\003'; break; case '(': /* map to SO (shift out) */ *sp = '\016'; break; case ')': /* map to SI (shift in) */ *sp = '\017'; break; } } if (sp > str && sp[-1] == '\n') { *--sp = '\0'; } return; } #if !defined BOOTSTRAP static void unmassage_buf(char *restrict buf, size_t bsz) { /* turn m4 quoting character substitutes into brackets again */ for (char *restrict sp = buf, *const ep = buf + bsz; sp < ep; sp++) { switch (*sp) { default: break; case '\002': /* unmap STX (start of text) */ *sp = '['; break; case '\003': /* unmap ETX (end of text) */ *sp = ']'; break; case '\016': /* unmap SO (shift out) */ *sp = '('; break; case '\017': /* unmap SI (shift in) */ *sp = ')'; break; } } return; } static int mktempp(char *restrict tmpl[static 1U], int prefixlen) { static mode_t umsk; char *bp = *tmpl + prefixlen; char *const ep = *tmpl + strlen(*tmpl); mode_t m; int fd; if (UNLIKELY(!umsk)) { umsk = umask(0022); } if (ep[-6] != 'X' || ep[-5] != 'X' || ep[-4] != 'X' || ep[-3] != 'X' || ep[-2] != 'X' || ep[-1] != 'X') { if ((fd = open(bp, O_RDWR | O_CREAT | O_EXCL, 0666)) < 0 && (bp -= prefixlen, fd = open(bp, O_RDWR | O_CREAT | O_EXCL, 0666)) < 0) { /* fuck that then */ return -1; } } else if (m = umask(S_IXUSR | S_IRWXG | S_IRWXO), UNLIKELY((fd = mkstemp(bp), umask(m), fd < 0)) && UNLIKELY((bp -= prefixlen, /* reset to XXXXXX */ memset(ep - 6, 'X', 6U), fd = mkstemp(bp)) < 0)) { /* at least we tried */ return -1; } /* store result */ *tmpl = bp; return fd; } static FILE* mkftempp(char *restrict tmpl[static 1U], int prefixlen) { int fd; if (UNLIKELY((fd = mktempp(tmpl, prefixlen)) < 0)) { return NULL; } return fdopen(fd, "w"); } # if defined WITH_SCMVER static bool regfilep(const char *fn) { struct stat st[1U]; return stat(fn, st) == 0 && S_ISREG(st->st_mode); } # endif /* WITH_SCMVER */ #endif /* !BOOTSTRAP */ /* bang buffers */ typedef struct { /* the actual buffer (resizable) */ char *s; /* current size */ size_t z; } bbuf_t; static char* bbuf_cpy(bbuf_t b[static 1U], const char *str, size_t ssz) { size_t nu = max_zu(yfls(ssz + 1U) + 1U, 6U); size_t ol = b->z ? max_zu(yfls(b->z) + 1U, 6U) : 0U; if (UNLIKELY(nu > ol)) { b->s = realloc(b->s, (1U << nu) * sizeof(*b->s)); } xstrncpy(b->s, str, ssz); b->z += ssz; return b->s; } static char* bbuf_cat(bbuf_t b[static 1U], const char *str, size_t ssz) { size_t nu = max_zu(yfls(b->z + ssz + 1U) + 1U, 6U); size_t ol = b->z ? max_zu(yfls(b->z) + 1U, 6U) : 0U; if (UNLIKELY(nu > ol)) { b->s = realloc(b->s, (1U << nu) * sizeof(*b->s)); } xstrncpy(b->s + b->z, str, ssz); b->z += ssz; return b->s; } static void yield_usg(const struct usg_s *arg); static void yield_opt(const struct opt_s *arg); static void yield_inter(const bbuf_t x[static 1U]); static void yield_setopt(yopt_t); #define DEBUG(args...) static int usagep(const char *line, size_t llen) { #define STREQLITP(x, lit) (!strncasecmp((x), lit, sizeof(lit) - 1)) static struct usg_s cur_usg; static bbuf_t umb[1U]; static bbuf_t cmd[1U]; static bbuf_t parg[1U]; static bbuf_t desc[1U]; static bool cur_usg_yldd_p; static bool umb_yldd_p; const char *sp; const char *up; const char *cp; const char *const ep = line + llen; if (UNLIKELY(line == NULL)) { goto yield; } DEBUG("USAGEP CALLED with %s", line); if (STREQLITP(line, "setopt")) { /* it's a setopt */ return 0; } else if (!STREQLITP(line, "usage:")) { if (only_whitespace_p(line, llen) && !desc->z) { return 1; } else if (!isspace(*line) && !cur_usg_yldd_p) { /* append to description */ cur_usg.desc = bbuf_cat(desc, line, llen); return 1; } yield: #define RESET cur_usg.cmd = cur_usg.parg = cur_usg.desc = NULL, desc->z = 0U if (!cur_usg_yldd_p) { yield_usg(&cur_usg); /* reset */ RESET; cur_usg_yldd_p = true; umb_yldd_p = true; } return 0; } else if (!cur_usg_yldd_p) { /* can't just goto yield because they wander off */ yield_usg(&cur_usg); /* reset */ RESET; cur_usg_yldd_p = true; umb_yldd_p = true; } /* overread whitespace then */ for (sp = line + sizeof("usage:") - 1; sp < ep && isspace(*sp); sp++); /* first thing should name the umbrella, find its end */ for (up = sp; sp < ep && !isspace(*sp); sp++); if (cur_usg.umb && !strncasecmp(cur_usg.umb, up, sp - up)) { /* nothing new and fresh */ ; } else { cur_usg.umb = bbuf_cpy(umb, up, sp - up); umb_yldd_p = false; } /* overread more whitespace and [--BLA] decls then */ overread: for (; sp < ep && isspace(*sp); sp++); /* we might be strafed with option decls here */ switch (*sp) { case '[': if (sp[1U] == '-') { /* might be option spec [-x], read on */ ; } else if (STREQLITP(sp + 1U, "OPTION")) { /* definitely an option marker innit? */ ; } else { /* could be posarg, better exit here */ break; } /* otherwise read till closing bracket */ for (sp++; sp < ep && *sp++ != ']';); /* and also read over `...' */ for (sp++; sp < ep && *sp == '.'; sp++); goto overread; default: /* best leave the loop */ break; } /* now it's time for the command innit */ for (cp = sp; sp < ep && !isspace(*sp); sp++); if (cur_usg.cmd && !strncasecmp(cur_usg.cmd, cp, sp - cp)) { /* nothing new and fresh */ ; } else if ((*cp != '<' || (cp++, *--sp == '>')) && !strncasecmp(cp, "command", sp - cp)) { /* special command COMMAND or */ cur_usg.cmd = NULL; } else if (*cp >= 'a' && *cp <= 'z' && umb_yldd_p) { /* we mandate commands start with a lower case alpha char */ cur_usg.cmd = bbuf_cpy(cmd, cp, sp - cp); } else { /* not a command, could be posarg innit, so rewind */ sp = cp; } /* now there might be positional args, snarf them */ for (; sp < ep && isspace(*sp); sp++); if (sp < ep) { cur_usg.parg = bbuf_cpy(parg, sp, ep - sp - 1U); } cur_usg_yldd_p = false; return 1; } static int optionp(const char *line, size_t llen) { static struct opt_s cur_opt; static bbuf_t desc[1U]; static bbuf_t lopt[1U]; static bbuf_t larg[1U]; const char *sp = line; const char *const ep = line + llen; if (UNLIKELY(line == NULL)) { goto yield; } DEBUG("OPTIONP CALLED with %s", line); /* overread whitespace */ for (; sp < ep && isspace(*sp); sp++) { if (*sp == '\t') { /* make a tab character count 8 in total */ sp += 7U; } } if ((sp - line >= 8 || (sp - line >= 1 && *sp != '-')) && (cur_opt.sopt || cur_opt.lopt)) { /* should be description */ goto desc; } yield: /* must yield the old current option before it's too late */ if (cur_opt.sopt || cur_opt.lopt) { yield_opt(&cur_opt); } /* complete reset */ memset(&cur_opt, 0, sizeof(cur_opt)); if (sp - line < 2) { /* can't be an option, can it? */ return 0; } else if (!*sp) { /* not an option either */ return 0; } /* no yield pressure anymore, try parsing the line */ sp++; if (*sp >= '0') { char sopt = *sp++; /* eat a comma as well */ if (*sp == ',') { sp++; } if (!isspace(*sp)) { /* dont know -x.SOMETHING? */ return 0; } /* start over with the new option */ sp++; cur_opt.sopt = sopt; if (*sp == '\0') { /* just the short option then innit? */ return 1; } else if (isspace(*sp)) { /* no arg name, no longopt */ ; } else if (*sp == '-') { /* must be a --long now, maybe */ sp++; } else { /* just an arg name */ const char *ap; if (*sp == '[') { cur_opt.oarg = 1U; sp++; } if (*sp == '=') { sp++; } for (ap = sp; sp < ep && isdashdash(*sp); sp++); cur_opt.larg = bbuf_cpy(larg, ap, sp - ap); if (cur_opt.oarg && *sp++ != ']') { /* maybe not an optarg? */ ; } if (*sp == '.') { /* could be mularg */ if (sp[1U] == '.' && sp[2U] == '.') { /* yay, 3 dots, read over dots */ for (sp += 3U; *sp == '.'; sp++); cur_opt.marg = 1U; } } } } else if (*sp == '-') { /* --option */ ; } else { /* dont know what this is */ return 0; } /* --option */ if (*sp++ == '-') { const char *op; for (op = sp; sp < ep && isdashdash(*sp); sp++); cur_opt.lopt = bbuf_cpy(lopt, op, sp - op); switch (*sp++) { case '[': if (*sp++ != '=') { /* just bullshit then innit? */ break; } /* otherwise optarg, fall through */ cur_opt.oarg = 1U; case '=':; /* has got an arg */ const char *ap; for (ap = sp; sp < ep && isdashdash(*sp); sp++); cur_opt.larg = bbuf_cpy(larg, ap, sp - ap); if (cur_opt.oarg && *sp++ != ']') { /* maybe not an optarg? */ ; } if (*sp == '.') { /* could be mularg */ if (sp[1U] == '.' && sp[2U] == '.') { /* yay, 3 dots, read over dots */ for (sp += 3U; *sp == '.'; sp++); cur_opt.marg = 1U; } } default: break; } } /* require at least one more space? */ ; /* space eater */ for (; sp < ep && isspace(*sp); sp++); /* dont free but reset the old guy */ desc->z = 0U; desc: with (size_t sz = llen - (sp - line)) { if (LIKELY(sz > 0U)) { cur_opt.desc = bbuf_cat(desc, sp, sz); } } return 1; } static int interp(const char *line, size_t llen) { static bbuf_t desc[1U]; bool only_ws_p = only_whitespace_p(line, llen); if (UNLIKELY(line == NULL)) { goto yield; } DEBUG("INTERP CALLED with %s", line); if (only_ws_p && desc->z) { yield: yield_inter(desc); /* reset */ desc->z = 0U; } else if (!only_ws_p) { if (STREQLITP(line, "setopt")) { /* not an inter */ return 0; } /* snarf the line */ bbuf_cat(desc, line, llen); return 1; } return 0; } static int setoptp(const char *line, size_t UNUSED(llen)) { if (UNLIKELY(line == NULL)) { return 0; } DEBUG("SETOPTP CALLED with %s", line); if (STREQLITP(line, "setopt")) { /* 'nother option */ const char *lp = line + sizeof("setopt"); if (0) { ; } else if (STREQLITP(lp, "allow-unknown-dash-options")) { yield_setopt(YOPT_ALLOW_UNKNOWN_DASH); } else if (STREQLITP(lp, "allow-unknown-dashdash-options")) { yield_setopt(YOPT_ALLOW_UNKNOWN_DASHDASH); } else { /* unknown setopt option */ } } return 0; } static const char nul_str[] = ""; static const char *const auto_types[] = {"auto", "flag"}; static FILE *outf; static struct { unsigned int no_auto_flags:1U; unsigned int no_auto_action:1U; } global_tweaks; static void __identify(char *restrict idn) { for (char *restrict ip = idn; *ip; ip++) { switch (*ip) { case '0' ... '9': case 'A' ... 'Z': case 'a' ... 'z': break; default: *ip = '_'; } } return; } static size_t count_pargs(const char *parg) { /* return max posargs as helper for auto-dashdash commands */ const char *pp; size_t res; for (res = 0U, pp = parg; *pp;) { /* allow [--] or -- as auto-dashdash declarators */ if (*pp == '[') { pp++; } if (*pp++ == '-') { if (*pp++ == '-') { if (*pp == ']' || isspace(*pp)) { /* found him! */ return res; } } /* otherwise not the declarator we were looking for * fast forward to the end */ for (; *pp && !isspace(*pp); pp++); } else { /* we know it's a bog-standard posarg for sure */ res++; /* check for ellipsis */ for (; *pp && *pp != '.' && !isspace(*pp); pp++); if (!*pp) { /* end of parg string anyway */ break; } if (*pp++ == '.' && *pp++ == '.' && *pp++ == '.') { /* ellipsis, set res to infinity and bog off */ break; } } /* fast forward over all the whitespace */ for (; *pp && isspace(*pp); pp++); } return 0U; } static char* make_opt_ident(const struct opt_s *arg) { static bbuf_t i[1U]; if (arg->lopt != NULL) { bbuf_cpy(i, arg->lopt, strlen(arg->lopt)); } else if (arg->sopt) { bbuf_cpy(i, "dash.", 5U); i->s[4U] = arg->sopt; } else { static unsigned int cnt; bbuf_cpy(i, "idnXXXX", 7U); snprintf(i->s + 3U, 5U, "%u", cnt++); } __identify(i->s); return i->s; } static char* make_ident(const char *str) { static bbuf_t buf[1U]; bbuf_cpy(buf, str, strlen(str)); __identify(buf->s); return buf->s; } static void yield_help(void) { const char *type = auto_types[global_tweaks.no_auto_action]; fprintf(outf, "yuck_add_option([help], [h], [help], [%s])\n", type); fprintf(outf, "yuck_set_option_desc([help], [\ display this help and exit])\n"); return; } static void yield_version(void) { const char *type = auto_types[global_tweaks.no_auto_action]; fprintf(outf, "yuck_add_option([version], [V], [version], [%s])\n", type); fprintf(outf, "yuck_set_option_desc([version], [\ output version information and exit])\n"); return; } static void yield_usg(const struct usg_s *arg) { const char *parg = arg->parg ?: nul_str; size_t nparg = count_pargs(parg); if (arg->desc != NULL) { /* kick last newline */ massage_desc(arg->desc); } if (arg->cmd != NULL) { const char *idn = make_ident(arg->cmd); fprintf(outf, "\nyuck_add_command([%s], [%s], [%s])\n", idn, arg->cmd, parg); if (nparg) { fprintf(outf, "yuck_set_command_max_posargs([%s], [%zu])\n", idn, nparg); } if (arg->desc != NULL) { fprintf(outf, "yuck_set_command_desc([%s], [%s])\n", idn, arg->desc); } } else if (arg->umb != NULL) { const char *idn = make_ident(arg->umb); fprintf(outf, "\nyuck_set_umbrella([%s], [%s], [%s])\n", idn, arg->umb, parg); if (nparg) { fprintf(outf, "yuck_set_umbrella_max_posargs([%s], [%zu])\n", idn, nparg); } if (arg->desc != NULL) { fprintf(outf, "yuck_set_umbrella_desc([%s], [%s])\n", idn, arg->desc); } /* insert auto-help and auto-version */ if (!global_tweaks.no_auto_flags) { yield_help(); yield_version(); } } return; } static void yield_opt(const struct opt_s *arg) { char sopt[2U] = {arg->sopt, '\0'}; const char *opt = arg->lopt ?: nul_str; const char *idn = make_opt_ident(arg); if (arg->larg == NULL) { fprintf(outf, "yuck_add_option([%s], [%s], [%s], " "[flag]);\n", idn, sopt, opt); } else { const char *asufs[] = { nul_str, ", opt", ", mul", ", mul, opt" }; const char *asuf = asufs[arg->oarg | arg->marg << 1U]; fprintf(outf, "yuck_add_option([%s], [%s], [%s], " "[arg, %s%s]);\n", idn, sopt, opt, arg->larg, asuf); } if (arg->desc != NULL) { massage_desc(arg->desc); fprintf(outf, "yuck_set_option_desc([%s], [%s])\n", idn, arg->desc); } return; } static void yield_inter(const bbuf_t x[static 1U]) { if (x->z) { if (x->s[x->z - 1U] == '\n') { x->s[x->z - 1U] = '\0'; } massage_desc(x->s); fprintf(outf, "yuck_add_inter([%s])\n", x->s); } return; } static void yield_setopt(yopt_t yo) { switch (yo) { default: case YOPT_NONE: break; case YOPT_ALLOW_UNKNOWN_DASH: fputs("yuck_setopt_allow_unknown_dash\n", outf); break; case YOPT_ALLOW_UNKNOWN_DASHDASH: fputs("yuck_setopt_allow_unknown_dashdash\n", outf); break; } return; } static enum { UNKNOWN, SET_INTER, SET_UMBCMD, SET_OPTION, SET_SETOPT, } snarf_ln(char *line, size_t llen) { static unsigned int st; switch (st) { case UNKNOWN: case SET_UMBCMD: usage: /* first keep looking for Usage: lines */ if (usagep(line, llen)) { st = SET_UMBCMD; break; } else if (st == SET_UMBCMD) { /* reset state, go on with option parsing */ st = UNKNOWN; goto option; } case SET_OPTION: option: /* check them option things */ if (optionp(line, llen)) { st = SET_OPTION; break; } else if (st == SET_OPTION) { /* reset state, go on with usage parsing */ st = UNKNOWN; goto usage; } case SET_INTER: /* check for some intro texts */ if (interp(line, llen)) { st = SET_INTER; break; } else { /* reset state, go on with setopt parsing */ st = UNKNOWN; } case SET_SETOPT: /* check for setopt BLA lines */ if (setoptp(line, llen)) { st = SET_SETOPT; break; } else { /* reset state, go on with option parsing */ st = UNKNOWN; } default: break; } return UNKNOWN; } static int snarf_f(FILE *f) { char *line = NULL; size_t llen = 0U; #if defined HAVE_GETLINE for (ssize_t nrd; (nrd = getline(&line, &llen, f)) > 0;) { if (*line == '#') { continue; } snarf_ln(line, nrd); } #elif defined HAVE_FGETLN while ((line = fgetln(f, &llen)) != NULL) { if (*line == '#') { continue; } snarf_ln(line, llen); } #else # error neither getline() nor fgetln() available, cannot read file line by line #endif /* GETLINE/FGETLN */ /* drain */ snarf_ln(NULL, 0U); #if defined HAVE_GETLINE free(line); #endif /* HAVE_GETLINE */ return 0; } #if defined BOOTSTRAP static FILE* get_fn(int argc, char *argv[]) { FILE *res; if (argc > 1) { const char *fn = argv[1]; if (UNLIKELY((res = fopen(fn, "r")) == NULL)) { error("cannot open file `%s'", fn); } } else { res = stdin; } return res; } int main(int argc, char *argv[]) { int rc = 0; FILE *yf; if (UNLIKELY((yf = get_fn(argc, argv)) == NULL)) { rc = -1; } else { /* always use stdout */ outf = stdout; fputs("\ changequote([,])dnl\n\ divert([-1])\n", outf); /* let the snarfing begin */ rc = snarf_f(yf); fputs("\n\ changecom([//])\n\ divert[]dnl\n", outf); /* clean up */ fclose(yf); } return -rc; } #endif /* BOOTSTRAP */ #if !defined BOOTSTRAP #if !defined PATH_MAX # define PATH_MAX (256U) #endif /* !PATH_MAX */ static char dslfn[PATH_MAX]; static bool aux_in_path_p(const char *aux, const char *path, size_t pathz) { char fn[PATH_MAX]; char *restrict fp = fn; struct stat st[1U]; fp += xstrlncpy(fn, sizeof(fn), path, pathz); *fp++ = '/'; xstrlcpy(fp, aux, sizeof(fn) - (fp - fn)); if (stat(fn, st) < 0) { return false; } return S_ISREG(st->st_mode); } static ssize_t get_myself(char *restrict buf, size_t bsz) { ssize_t off; char *mp; if ((off = readlink("/proc/self/exe", buf, bsz)) < 0) { return -1; } /* go back to the dir bit */ for (mp = buf + off - 1U; mp > buf && *mp != '/'; mp--); /* should be bin/, go up one level */ *mp = '\0'; for (; mp > buf && *mp != '/'; mp--); /* check if we're right */ if (UNLIKELY(strcmp(++mp, "bin"))) { /* oh, it's somewhere but not bin/? */ return -1; } /* now just use share/yuck/ */ xstrlcpy(mp, "share/yuck/", bsz - (mp - buf)); mp += sizeof("share/yuck"); return mp - buf; } static int find_aux(char *restrict buf, size_t bsz, const char *aux) { /* look up path relative to binary position */ static char pkgdatadir[PATH_MAX]; static ssize_t pkgdatalen; static const char *tmplpath; static ssize_t tmplplen; const char *path; size_t plen; /* start off by snarfing the environment */ if (tmplplen == 0U) { if ((tmplpath = getenv("YUCK_TEMPLATE_PATH")) != NULL) { tmplplen = strlen(tmplpath); } else { /* just set it to something non-0 to indicate initting * and that also works with the loop below */ tmplplen = -1; tmplpath = (void*)0x1U; } } /* snarf pkgdatadir */ if (pkgdatalen == 0U) { pkgdatalen = get_myself(pkgdatadir, sizeof(pkgdatadir)); } /* go through the path first */ for (const char *pp = tmplpath, *ep, *const end = tmplpath + tmplplen; pp < end; pp = ep + 1U) { ep = strchr(pp, ':') ?: end; if (aux_in_path_p(aux, pp, ep - pp)) { path = pp; plen = ep - pp; goto bang; } } /* no luck with the env path then aye */ if (pkgdatalen > 0 && aux_in_path_p(aux, pkgdatadir, pkgdatalen)) { path = pkgdatadir; plen = pkgdatalen; goto bang; } #if defined YUCK_TEMPLATE_PATH path = YUCK_TEMPLATE_PATH; plen = sizeof(YUCK_TEMPLATE_PATH); if (plen-- > 0U && aux_in_path_p(aux, path, plen)) { goto bang; } #endif /* YUCK_TEMPLATE_PATH */ /* not what we wanted at all, must be christmas */ return -1; bang: with (size_t z) { z = xstrlncpy(buf, bsz, path, plen); buf[z++] = '/'; xstrlcpy(buf + z, aux, bsz - z); } return 0; } static int find_dsl(void) { return find_aux(dslfn, sizeof(dslfn), "yuck.m4"); } static void unmassage_fd(int tgtfd, int srcfd) { static char buf[4096U]; for (ssize_t nrd; (nrd = read(srcfd, buf, sizeof(buf))) > 0;) { const char *bp = buf; const char *const ep = buf + nrd; unmassage_buf(buf, nrd); for (ssize_t nwr; bp < ep && (nwr = write(tgtfd, bp, ep - bp)) > 0; bp += nwr); } return; } static char *m4_cmdline[16U] = { "m4", }; static size_t cmdln_idx; static int prep_m4(void) { char *p; /* checkout the environment, look for M4 */ if ((p = getenv("M4")) == NULL) { cmdln_idx = 1U; return 0; } /* otherwise it's big string massaging business */ do { m4_cmdline[cmdln_idx++] = p; /* mimic a shell's IFS */ for (; *p && !isspace(*p); p++) { const char this = *p; switch (this) { default: break; case '"': case '\'': /* fast forward then */ while (*++p != this) { if (*p == '\\') { p++; } } break; } } if (!*p) { break; } /* otherwise it's an IFS */ for (*p++ = '\0'; isspace(*p); p++); } while (1); return 0; } static __attribute__((noinline)) int run_m4(const char *outfn, ...) { pid_t m4p; /* to snarf off traffic from the child */ int intfd[2]; if (pipe(intfd) < 0) { error("pipe setup to/from m4 failed"); return -1; } else if (!cmdln_idx && prep_m4() < 0) { error("m4 preparations failed"); return -1; } switch ((m4p = vfork())) { case -1: /* i am an error */ error("vfork for m4 failed"); return -1; default:; /* i am the parent */ int rc; int st; if (outfn != NULL) { /* --output given */ const int outfl = O_RDWR | O_CREAT | O_TRUNC; int outfd; if ((outfd = open(outfn, outfl, 0666)) < 0) { /* bollocks */ error("cannot open outfile `%s'", outfn); goto bollocks; } /* really redir now */ dup2(outfd, STDOUT_FILENO); close(outfd); } close(intfd[1]); unmassage_fd(STDOUT_FILENO, intfd[0]); rc = 2; while (waitpid(m4p, &st, 0) != m4p); if (WIFEXITED(st)) { rc = WEXITSTATUS(st); } /* clean up the rest of the pipe */ close(intfd[0]); return rc; case 0:; /* i am the child */ break; } /* child code here */ with (va_list vap) { va_start(vap, outfn); for (size_t i = cmdln_idx; i < countof(m4_cmdline) && (m4_cmdline[i] = va_arg(vap, char*)) != NULL; i++); va_end(vap); } dup2(intfd[1], STDOUT_FILENO); close(intfd[0]); execvp(m4_cmdline[0U], m4_cmdline); error("execvp(m4) failed"); bollocks: _exit(EXIT_FAILURE); } static int wr_pre(void) { fputs("\ changequote`'changequote([,])dnl\n\ divert([-1])\n", outf); return 0; } static int wr_suf(void) { fputs("\n\ changequote`'dnl\n\ divert`'dnl\n", outf); return 0; } static int wr_intermediary(char *const args[], size_t nargs) { int rc = 0; wr_pre(); if (nargs == 0U) { if (snarf_f(stdin) < 0) { errno = 0; error("cannot interpret directives on stdin"); rc = 1; } } for (unsigned int i = 0U; i < nargs && rc == 0; i++) { const char *fn = args[i]; FILE *yf; if (UNLIKELY((yf = fopen(fn, "r")) == NULL)) { error("cannot open file `%s'", fn); rc = 1; break; } else if (snarf_f(yf) < 0) { errno = 0; error("cannot interpret directives from `%s'", fn); rc = 1; } /* clean up */ fclose(yf); } /* reset to sane values */ wr_suf(); return rc; } static int wr_header(const char hdr[static 1U]) { /* massage the hdr bit a bit */ if (strcmp(hdr, "/dev/null")) { /* /dev/null just means ignore the header aye? */ const char *hp; if ((hp = strrchr(hdr, '/')) == NULL) { hp = hdr; } else { hp++; }; wr_pre(); fprintf(outf, "define([YUCK_HEADER], [%s])dnl\n", hp); wr_suf(); } return 0; } static int wr_man_date(void) { time_t now; const struct tm *tp; char buf[32U]; int rc = 0; if ((now = time(NULL)) == (time_t)-1) { rc = -1; } else if ((tp = gmtime(&now)) == NULL) { rc = -1; } else if (!strftime(buf, sizeof(buf), "%B %Y", tp)) { rc = -1; } else { fprintf(outf, "define([YUCK_MAN_DATE], [%s])dnl\n", buf); } return rc; } static int wr_man_pkg(const char *pkg) { fprintf(outf, "define([YUCK_PKG_STR], [%s])dnl\n", pkg); return 0; } static int wr_man_nfo(const char *nfo) { fprintf(outf, "define([YUCK_NFO_STR], [%s])dnl\n", nfo); return 0; } static int wr_man_incln(FILE *fp, char *restrict ln, size_t lz) { static int verbp; static int parap; if (UNLIKELY(ln == NULL)) { /* drain mode */ if (verbp) { fputs(".fi\n", fp); } } else if (lz <= 1U/*has at least a newline?*/) { if (verbp) { /* close verbatim mode */ fputs(".fi\n", fp); verbp = 0; } if (!parap) { fputs(".PP\n", fp); parap = 1; } } else if (*ln == '[' && ln[lz - 2U] == ']') { /* section */ char *restrict lp = ln + 1U; for (const char *const eol = ln + lz - 2U; lp < eol; lp++) { *lp = (char)toupper(*lp); } *lp = '\0'; fputs(".SH ", fp); fputs(ln + 1U, fp); fputs("\n", fp); /* reset state */ parap = 0; verbp = 0; } else if (ln[0U] == ' ' && ln[1U] == ' ' && !verbp) { fputs(".nf\n", fp); verbp = 1; goto cp; } else { cp: /* otherwise copy */ fwrite(ln, lz, sizeof(*ln), fp); parap = 0; } return 0; } static int wr_man_include(char **const inc) { char _ofn[] = P_tmpdir "/" "yuck_XXXXXX"; char *ofn = _ofn; FILE *ofp; char *line = NULL; size_t llen = 0U; FILE *fp; if (UNLIKELY((fp = fopen(*inc, "r")) == NULL)) { error("Cannot open include file `%s', ignoring", *inc); *inc = NULL; return -1; } else if (UNLIKELY((ofp = mkftempp(&ofn, sizeof(P_tmpdir))) == NULL)) { error("Cannot open output file `%s', ignoring", ofn); *inc = NULL; return -1; } /* make sure we pass on ofn */ *inc = strdup(ofn); #if defined HAVE_GETLINE for (ssize_t nrd; (nrd = getline(&line, &llen, fp)) > 0;) { wr_man_incln(ofp, line, nrd); } #elif defined HAVE_FGETLN while ((line = fgetln(fp, &llen)) != NULL) { wr_man_incln(ofp, line, llen); } #else # error neither getline() nor fgetln() available, cannot read file line by line #endif /* GETLINE/FGETLN */ /* drain */ wr_man_incln(ofp, NULL, 0U); #if defined HAVE_GETLINE free(line); #endif /* HAVE_GETLINE */ /* close files properly */ fclose(fp); fclose(ofp); return 0; } static int wr_man_includes(char *incs[], size_t nincs) { for (size_t i = 0U; i < nincs; i++) { /* massage file */ if (wr_man_include(incs + i) < 0) { continue; } else if (incs[i] == NULL) { /* something else is wrong */ continue; } /* otherwise make a note to include this file */ fprintf(outf, "\ append([YUCK_INCLUDES], [%s], [,])dnl\n", incs[i]); } return 0; } static int wr_version(const struct yuck_version_s *v, const char *vlit) { wr_pre(); if (v != NULL) { #if defined WITH_SCMVER const char *yscm = yscm_strs[v->scm]; fprintf(outf, "define([YUCK_SCMVER_VTAG], [%s])\n", v->vtag); fprintf(outf, "define([YUCK_SCMVER_SCM], [%s])\n", yscm); fprintf(outf, "define([YUCK_SCMVER_DIST], [%u])\n", v->dist); fprintf(outf, "define([YUCK_SCMVER_RVSN], [%0*x])\n", (int)(v->rvsn & 0x07U), v->rvsn >> 4U); if (!v->dirty) { fputs("define([YUCK_SCMVER_FLAG_CLEAN])\n", outf); } else { fputs("define([YUCK_SCMVER_FLAG_DIRTY])\n", outf); } /* for convenience */ fputs("define([YUCK_SCMVER_VERSION], [", outf); fputs(v->vtag, outf); if (v->scm > YUCK_SCM_TARBALL && v->dist) { fputc('.', outf); fputs(yscm_strs[v->scm], outf); fprintf(outf, "%u.%0*x", v->dist, (int)(v->rvsn & 0x07U), v->rvsn >> 4U); } if (v->dirty) { fputs(".dirty", outf); } fputs("])\n", outf); #else /* !WITH_SCMVER */ errno = 0, error("\ scmver support not built in but ptr %p given to wr_version()", v); #endif /* WITH_SCMVER */ } if (vlit != NULL) { fputs("define([YUCK_VERSION], [", outf); fputs(vlit, outf); fputs("])\n", outf); } wr_suf(); return 0; } static int rm_intermediary(const char *fn, int keepp) { if (!keepp) { if (unlink(fn) < 0) { error("cannot remove intermediary `%s'", fn); return -1; } } else { /* otherwise print a nice message so users know * the file we created */ errno = 0, error("intermediary `%s' kept", fn); } return 0; } static int rm_includes(char *const incs[], size_t nincs, int keepp) { int rc = 0; errno = 0; for (size_t i = 0U; i < nincs; i++) { char *restrict fn; if ((fn = incs[i]) != NULL) { if (!keepp && unlink(fn) < 0) { error("cannot remove intermediary `%s'", fn); rc = -1; } else if (keepp) { /* otherwise print a nice message so users know * the file we created */ errno = 0, error("intermediary `%s' kept", fn); } free(fn); } } return rc; } #endif /* !BOOTSTRAP */ #if !defined BOOTSTRAP #include "yuck.yucc" static int cmd_gen(const struct yuck_cmd_gen_s argi[static 1U]) { static char _deffn[] = P_tmpdir "/" "yuck_XXXXXX"; static char gencfn[PATH_MAX]; static char genhfn[PATH_MAX]; char *deffn = _deffn; int rc = 0; if (argi->no_auto_flags_flag) { global_tweaks.no_auto_flags = 1U; } if (argi->no_auto_actions_flag) { global_tweaks.no_auto_action = 1U; } /* deal with the output first */ if (UNLIKELY((outf = mkftempp(&deffn, sizeof(P_tmpdir))) == NULL)) { error("cannot open intermediate file `%s'", deffn); return -1; } /* write up our findings in DSL language */ rc = wr_intermediary(argi->args, argi->nargs); /* deal with hard wired version numbers */ if (argi->version_arg) { rc += wr_version(NULL, argi->version_arg); } /* special directive for the header or is it */ if (argi->header_arg != NULL) { rc += wr_header(argi->header_arg); } /* and we're finished with the intermediary */ fclose(outf); /* only proceed if there has been no error yet */ if (rc) { goto out; } else if (find_dsl() < 0) { /* error whilst finding our DSL and things */ error("cannot find yuck dsl file"); rc = 2; goto out; } else if (find_aux(gencfn, sizeof(gencfn), "yuck-coru.c.m4") < 0 || find_aux(genhfn, sizeof(genhfn), "yuck-coru.h.m4") < 0) { error("cannot find yuck template files"); rc = 2; goto out; } /* now route that stuff through m4 */ with (const char *outfn = argi->output_arg, *cusfn = argi->custom_arg ?: "/dev/null", *hdrfn) { if ((hdrfn = argi->header_arg) != NULL) { /* run a special one for the header */ if ((rc = run_m4(hdrfn, dslfn, deffn, genhfn, NULL))) { break; } /* now run the whole shebang for the beef code */ rc = run_m4(outfn, dslfn, deffn, cusfn, gencfn, NULL); break; } /* standard case: pipe directives, then header, then code */ rc = run_m4(outfn, dslfn, deffn, cusfn, genhfn, gencfn, NULL); } out: /* unlink include files */ rm_intermediary(deffn, argi->keep_flag); return rc; } static int cmd_genman(const struct yuck_cmd_genman_s argi[static 1U]) { static char _deffn[] = P_tmpdir "/" "yuck_XXXXXX"; static char genmfn[PATH_MAX]; char *deffn = _deffn; int rc = 0; /* deal with the output first */ if (UNLIKELY((outf = mkftempp(&deffn, sizeof(P_tmpdir))) == NULL)) { error("cannot open intermediate file `%s'", deffn); return -1; } /* write up our findings in DSL language */ rc = wr_intermediary(argi->args, argi->nargs); if (argi->version_string_arg) { rc += wr_version(NULL, argi->version_string_arg); } else if (argi->version_file_arg) { #if defined WITH_SCMVER struct yuck_version_s v[1U]; const char *verfn = argi->version_file_arg; if (yuck_version_read(v, verfn) < 0) { error("cannot read version number from `%s'", verfn); rc--; } else { rc += wr_version(v, NULL); } #else /* !WITH_SCMVER */ errno = 0; error("\ scmver support not built in, --version-file cannot be used"); #endif /* WITH_SCMVER */ } /* reset to sane values */ wr_pre(); /* at least give the man page template an idea for YUCK_MAN_DATE */ rc += wr_man_date(); if (argi->package_arg) { /* package != umbrella */ rc += wr_man_pkg(argi->package_arg); } if (argi->info_page_arg) { const char *nfo; if ((nfo = argi->info_page_arg) == YUCK_OPTARG_NONE) { nfo = "YUCK_PKG_STR"; } rc += wr_man_nfo(nfo); } /* go through includes */ wr_man_includes(argi->include_args, argi->include_nargs); /* reset to sane values */ wr_suf(); /* and we're finished with the intermediary */ fclose(outf); /* only proceed if there has been no error yet */ if (rc) { goto out; } else if (find_dsl() < 0) { /* error whilst finding our DSL and things */ error("cannot find yuck dsl and template files"); rc = 2; goto out; } else if (find_aux(genmfn, sizeof(genmfn), "yuck.man.m4") < 0) { error("cannot find yuck template for man pages"); rc = 2; goto out; } /* now route that stuff through m4 */ with (const char *outfn = argi->output_arg) { /* standard case: pipe directives, then header, then code */ rc = run_m4(outfn, dslfn, deffn, genmfn, NULL); } out: rm_includes(argi->include_args, argi->include_nargs, argi->keep_flag); rm_intermediary(deffn, argi->keep_flag); return rc; } static int cmd_gendsl(const struct yuck_cmd_gendsl_s argi[static 1U]) { int rc = 0; if (argi->no_auto_flags_flag) { global_tweaks.no_auto_flags = 1U; } if (argi->no_auto_actions_flag) { global_tweaks.no_auto_action = 1U; } /* bang to stdout or argi->output_arg */ with (const char *outfn = argi->output_arg) { if (outfn == NULL) { outf = stdout; } else if ((outf = fopen(outfn, "w")) == NULL) { error("cannot open outfile `%s'", outfn); return 1; } } rc += wr_intermediary(argi->args, argi->nargs); if (argi->version_arg) { rc += wr_version(NULL, argi->version_arg); } return rc; } static int cmd_scmver(const struct yuck_cmd_scmver_s argi[static 1U]) { #if defined WITH_SCMVER struct yuck_version_s v[1U]; struct yuck_version_s ref[1U]; const char *const reffn = argi->reference_arg; const char *const infn = argi->args[0U]; int rc = 0; /* read the reference file before it goes out of fashion */ if (reffn && yuck_version_read(ref, reffn) < 0 && /* only be fatal if we actually want to use the reference file */ argi->use_reference_flag) { error("cannot read reference file `%s'", reffn); return 1; } else if (reffn == NULL && argi->use_reference_flag) { errno = 0, error("\ flag -n|--use-reference requires -r|--reference parameter"); return 1; } else if (!argi->use_reference_flag && yuck_version(v, infn) < 0) { if (argi->ignore_noscm_flag) { /* allow graceful exit through --ignore-noscm */ return 0; } errno = 0, error("cannot determine SCM"); return 1; } if (reffn && argi->use_reference_flag) { /* must populate v then */ *v = *ref; } else if (reffn && yuck_version_cmp(v, ref)) { if (argi->verbose_flag) { errno = 0, error("scm version differs from reference"); } /* version stamps differ */ yuck_version_write(argi->reference_arg, v); /* reserve exit code 3 for `updated reference file' */ rc = 3; } else if (reffn && !argi->force_flag) { /* make sure the output file exists */ const char *const outfn = argi->output_arg; if (outfn == NULL || regfilep(outfn)) { /* don't worry about anything then */ return 0; } /* otherwise create at least one version of the output */ } if (infn != NULL && regfilep(infn)) { static char _scmvfn[] = P_tmpdir "/" "yscm_XXXXXX"; static char tmplfn[PATH_MAX]; char *scmvfn = _scmvfn; /* try the local dir first */ if ((outf = mkftempp(&scmvfn, sizeof(P_tmpdir))) == NULL) { error("cannot open intermediate file `%s'", scmvfn); rc = 1; } else if (find_aux(tmplfn, sizeof(tmplfn), "yuck-scmver.m4") < 0) { error("cannot find yuck template for version strings"); rc = 1; } else { const char *outfn = argi->output_arg; /* write the actual version info */ rc += wr_version(v, NULL); /* and we're finished with the intermediary */ fclose(outf); /* macro massage, vtmpfn is the template file */ rc = run_m4(outfn, scmvfn, tmplfn, infn, NULL); rm_intermediary(scmvfn, argi->keep_flag); } } else { fputs(v->vtag, stdout); if (v->scm > YUCK_SCM_TARBALL && v->dist) { fputc('.', stdout); fputs(yscm_strs[v->scm], stdout); fprintf(stdout, "%u.%0*x", v->dist, (int)(v->rvsn & 0x07U), v->rvsn >> 4U); } if (v->dirty) { fputs(".dirty", stdout); } fputc('\n', stdout); } return rc; #else /* !WITH_SCMVER */ fputs("scmver support not built in\n", stderr); return argi->cmd == YUCK_CMD_SCMVER; #endif /* WITH_SCMVER */ } int main(int argc, char *argv[]) { yuck_t argi[1U]; int rc = 0; if (yuck_parse(argi, argc, argv) < 0) { rc = 1; goto out; } switch (argi->cmd) { default: fputs("\ No valid command specified.\n\ See --help to obtain a list of available commands.\n", stderr); rc = 1; goto out; case YUCK_CMD_GEN: if ((rc = cmd_gen((const void*)argi)) < 0) { rc = 1; } break; case YUCK_CMD_GENDSL: if ((rc = cmd_gendsl((const void*)argi)) < 0) { rc = 1; } break; case YUCK_CMD_GENMAN: if ((rc = cmd_genman((const void*)argi)) < 0) { rc = 1; } break; case YUCK_CMD_SCMVER: if ((rc = cmd_scmver((const void*)argi)) < 0) { rc = 1; } break; } out: yuck_free(argi); return rc; } #endif /* !BOOTSTRAP */ /* yuck.c ends here */ dateutils-0.3.1/build-aux/yuck.m4000066400000000000000000000275571241477753400166560ustar00rootroot00000000000000changequote`'changequote([,])dnl divert([-1]) ## this is a little domain language for the yuck processor # foreachq(x, [item_1, item_2, ..., item_n], stmt) # quoted list, alternate improved version define([foreachq], [ifelse([$2], [], [], [pushdef([$1])_$0([$1], [$3], [], $2)popdef([$1])])]) define([_foreachq], [ifelse([$#], [3], [], [define([$1], [$4])$2[]$0([$1], [$2], shift(shift(shift($@))))])]) #### append $2 to $1, separated by $3. define([append], [define([$1], ifdef([$1], [defn([$1])[$3]])[$2])]) ## like append, but append only non-empty arguments define([append_ne], [ifelse([$2], [], [], [append([$1], [$2], [$3])])]) ## like append_ne, but append only non-existing arguments define([append_nene], [ifelse(index([$3]defn([$1])[$3], [$3$2$3]), [-1], [append_ne([$1], [$2], [$3])])]) define([appendq], [define([$1], ifdef([$1], [defn([$1])[$3]])dquote([$2]))]) ## like appendq, but append only non-empty arguments define([appendq_ne], [ifelse([$2], [], [], [append([$1], dquote([$2]), [$3])])]) ## like appendq_ne, but append only non-existing arguments define([appendq_nene], [ifelse(index([$3]defn([$1])[$3], [$3]dquote($2)[$3]), [-1], [appendq_ne([$1], [$2], [$3])])]) define([first_nonnil], [ifelse([$#], [0], [], [$1], [], [first_nonnil(shift($@))], [], [], [$1])]) define([first], [_first($*)]) define([_first], [$1]) define([second], [_second($*)]) define([_second], [$2]) define([thirds], [_thirds($*)]) define([_thirds], [quote(shift(shift($@)))]) define([quote], [ifelse([$#], [0], [], [[$*]])]) define([dquote], [[$@]]) define([equote], [dquote($*)]) define([backquote], [_$0([$1], [(], -=<{($1)}>=-, [}>=-])]) define([_backquote], [dnl ifelse([$4], [}>=-], [dnl changequote([-=<{$2], [)}>=-])$3changequote([, ])], [dnl else $0([$1], [($2], -=<{($2$1)}>=-, [}>=-])_ignore$2])]) define([_ignore]) define([_splice], [ifelse(eval([$#] > [3]), [0], [[$1], [$2], [$3]], [[$1], [$2], [$3], _splice([$1], shift(shift(shift($@))))])]) define([cond], [ifelse([$#], [0], [], [$#], [1], [$1], [_$0($@)])]) define([_cond], [dnl ifelse([$1], [$2], [$3], [$#], [3], [], [$#], [4], [$4], [$0([$1], shift(shift(shift($@))))])]) define([downcase], [dnl translit([$1], [ABCDEFGHIJKLMNOPQRSTUVWXYZ], [abcdefghijklmnopqrstuvwxyz])[]dnl ]) define([upcase], [dnl translit([$1], [abcdefghijklmnopqrstuvwxyz], [ABCDEFGHIJKLMNOPQRSTUVWXYZ])[]dnl ]) ## select a diversion, clearing all other diversions define([select_divert], [divert[]undivert($1)[]divert(-1)[]undivert[]divert(0)]) define([yuck_set_version], [dnl define([YUCK_VERSION], [$1]) ]) ## yuck_set_umbrella([ident], [umbrella], [[posarg]]) define([yuck_set_umbrella], [dnl define([YUCK_UMB], [$1]) define([YUCK_UMB_STR], [$2]) define([YUCK_UMB_POSARG], [$3]) ]) ## yuck_set_umbrella_desc([ident], [desc]) define([yuck_set_umbrella_desc], [dnl define([YUCK_UMB_$1_desc], [$2]) ## define yuck_add_inter here, corresponding to IDENT define([YUCK_INTER_CMD], [YUCK_UMB_$1_desc]) ]) ## yuck_set_umbrella_max_posargs([ident], [N]) define([yuck_set_umbrella_max_posargs], [dnl define([YUCK_UMB_$1_max_posargs], [$2]) define([YUCK_MAX_POSARGS], [$2]) ]) ## yuck_add_command([ident], [command], [[posarg]]) define([yuck_add_command], [dnl define([YUCK_CMD], [$1]) append_nene([YUCK_ALL_CMDS], [$1], [,]) define([YUCK_$1_STR], [$2]) define([YUCK_POSARG_$1], [$3]) ]) ## yuck_set_command_desc([ident], [desc]) define([yuck_set_command_desc], [dnl define([YUCK_CMD_$1_desc], [$2]) ## define yuck_add_inter here, corresponding to IDENT define([YUCK_INTER_CMD], [YUCK_CMD_$1_desc]) ]) ## yuck_set_umbrella_max_posargs([ident], [N]) define([yuck_set_command_max_posargs], [dnl define([YUCK_CMD_$1_max_posargs], [$2]) ]) ## yuck_add_inter([desc]) #### append interim DESC to last command desc define([yuck_add_inter], [dnl append(defn([YUCK_INTER_CMD]), [$1], [ ]) ]) ## yuck_add_option([ident], [short], [long], [type]) define([yuck_add_option], [dnl ## quote the elements of the type arg first ## before any possible expansion is in scope pushdef([type], equote([$4])) pushdef([ident], [$1]) pushdef([cmd], defn([YUCK_CMD])) ifelse([$2], [], [], index([0123456789], [$2]), [-1], [], [dnl else define([YUCK_SHORTS_HAVE_NUMERALS], [1]) ]) ifdef([YUCK_]defn([cmd])[_]defn([ident])[_canon], [], [dnl ## process only if new appendq_ne([YUCK_]defn([cmd])[_I], defn([ident]), [,]) ## forward maps define([YUCK_]defn([cmd])[_]defn([ident])[_canon], defn([ident])) define([YUCK_]defn([cmd])[_]defn([ident])[_type], defn([type])) ## reverse maps define([YUCK_]defn([cmd])[_]defn([ident])[_short], [$2]) define([YUCK_]defn([cmd])[_]defn([ident])[_long], [$3]) ]) popdef([ident]) popdef([cmd]) popdef([type]) ]) ## yuck_set_option_desc([ident], [desc]) define([yuck_set_option_desc], [dnl define([YUCK_]defn([YUCK_CMD])[_$1_desc], [$2]) ]) ## some yopts here, mostly flags define([yuck_setopt_allow_unknown_dash], [dnl define([YOPT_ALLOW_UNKNOWN_DASH]) ]) define([yuck_setopt_allow_unknown_dashdash], [dnl define([YOPT_ALLOW_UNKNOWN_DASHDASH]) ]) ## helpers for the m4c and m4h ## yuck_canon([opt], [[cmd]]) define([yuck_canon], [defn([YUCK_$2_$1_canon])]) ## yuck_option_type([opt], [[cmd]]) define([yuck_option_type], [defn([YUCK_$2_$1_type])]) ## yuck_type([type-spec]) define([yuck_type], [first([$1])]) ## yuck_type_name([type-spec]) define([yuck_type_name], [second([$1])]) ## yuck_type_sufx([type-spec]) define([yuck_type_sufx], [thirds([$1])]) ## yuck_slot_identifier([option], [[cmd]]) define([yuck_slot_identifier], [dnl pushdef([canon], yuck_canon([$1], [$2]))dnl pushdef([type], yuck_option_type([$1], [$2]))dnl dnl defn([canon])[_]yuck_type(defn([type]))[]dnl cond(yuck_type_sufx(defn([type])), [mul], [s], [mul,opt], [s])[]dnl dnl popdef([canon])dnl popdef([type])dnl ]) ## yuck_cnt_slot([option], [[cmd]]) define([yuck_cnt_slot], [dnl pushdef([type], yuck_option_type([$1], [$2]))dnl ifelse(yuck_type(defn([type])), [arg], [dnl ifelse(first(yuck_type_sufx(defn([type]))), [mul], [ pushdef([idn], [yuck_canon([$1], [$2])[_nargs]])dnl ifelse([$2], [], [idn], [$2.idn])[]dnl popdef([idn])dnl ])[]dnl ])[]dnl popdef([type])dnl ]) ## yuck_slot([option], [[cmd]]) define([yuck_slot], [dnl pushdef([idn], yuck_slot_identifier([$1], [$2]))dnl dnl ifelse([$2], [], defn([idn]), [$2.]defn([idn]))[]dnl dnl popdef([idn])dnl ]) ## yuck_iftype([opt], [cmd], [type], [body], [[type], [body]]...) define([yuck_iftype], [dnl pushdef([type], yuck_option_type([$1], [$2]))dnl pushdef([tsuf], yuck_type_sufx(defn([type])))dnl pushdef([res], yuck_type(defn([type])))dnl append_ne([res], defn([tsuf]), [,])[]dnl []ifelse(_splice(defn([res]), shift(shift($@))))[]dnl popdef([tsuf])dnl popdef([type])dnl popdef([res])dnl ]) ## yuck_umbcmds(), umbrella + commands define([yuck_umbcmds], [ifdef([YUCK_ALL_CMDS], [[,]defn([YUCK_ALL_CMDS])], dquote([[]]))]) ## yuck_cmds(), just the commands define([yuck_cmds], [defn([YUCK_ALL_CMDS])]) ## yuck_cmd([command]) define([yuck_cmd], [upcase(defn([YUCK_UMB]))[_CMD_]ifelse([$1], [], [NONE], [upcase([$1])])]) ## yuck_cmd_string define([yuck_cmd_string], [defn([YUCK_]$1[_STR])]) ## yuck_cmd_posarg define([yuck_cmd_posarg], [defn([YUCK_POSARG_]$1)]) ## yuck_umb_desc([[umb]]) getter for the umbrella description define([yuck_umb_desc], [defn([YUCK_UMB_]ifelse([$1], [], defn([YUCK_UMB]), [$1])[_desc])]) ## yuck_cmd_desc([cmd]) getter for the command description define([yuck_cmd_desc], [defn([YUCK_CMD_$1_desc])]) ## yuck_idents([cmd]) define([yuck_idents], [defn([YUCK_$1_I])]) ## yuck_short([ident], [[cmd]]) define([yuck_short], [defn([YUCK_$2_$1_short])]) ## yuck_long([ident], [[cmd]]) define([yuck_long], [defn([YUCK_$2_$1_long])]) ## yuck_option_desc([ident], [[cmd]]) define([yuck_option_desc], [defn([YUCK_$2_$1_desc])]) ## type actions define([_yuck_option_action], [dnl pushdef([type], yuck_option_type([$1], [$2]))dnl pushdef([prim], yuck_type(defn([type])))dnl pushdef([sufx], yuck_type_sufx(defn([type])))dnl quote([yuck_]defn([prim])ifelse(defn([sufx]), [], [], [_]translit(defn([sufx]), [,], [_]))[_action][(quote([$1]), quote([$2]))])dnl popdef([type])dnl popdef([prim])dnl popdef([sufx])dnl ])dnl define([yuck_expand], [$1]) define([yuck_option_action], [yuck_expand(_$0([$1], [$2]))]) ## yuck_option_help_lhs([ident], [[cmd]]) define([yuck_option_help_lhs], [dnl pushdef([s], [backquote([yuck_short([$1], [$2])])])dnl pushdef([l], [backquote([yuck_long([$1], [$2])])])dnl pushdef([type], yuck_option_type([$1], [$2]))dnl pushdef([prel], ifelse(l, [], [], [=]))dnl pushdef([yuck_arg_action], [defn([prel])[]yuck_type_name(yuck_option_type([$1], [$2]))])dnl pushdef([yuck_arg_opt_action], [defn([prel])[]yuck_type_name(yuck_option_type([$1], [$2]))])dnl pushdef([yuck_arg_mul_action], [defn([prel])[]yuck_type_name(yuck_option_type([$1], [$2]))...])dnl pushdef([yuck_arg_mul_opt_action], [defn([prel])[]yuck_type_name(yuck_option_type([$1], [$2]))...])dnl [ ]ifelse(s, [], [ ], [-s[]ifelse(l, [], [], [[, ]])])[]dnl ifelse(l, [], [], [--l])[]dnl ifelse(yuck_type(defn([type])), [arg], [dnl ifelse(l, [], [ ], [])backquote([yuck_option_action([$1], [$2])])[]dnl ])[]dnl popdef([type])dnl popdef([prel])dnl popdef([s])dnl popdef([l])dnl popdef([yuck_arg_action])dnl popdef([yuck_arg_opt_action])dnl popdef([yuck_arg_mul_action])dnl popdef([yuck_arg_mul_opt_action])dnl ]) define([xleft], [_$0([$1], 0, [$2])]) define([_xleft], [dnl ifelse(eval(incr(incr([$2])) <= [$3]), [1], [dnl substr([$1], [$2], 2)[]$0([$1], incr(incr([$2])), [$3])[]dnl ], eval(incr([$2]) <= [$3]), [1], [dnl substr([$1], [$2], 1)[]dnl ])[]dnl ]) define([xright], [_$0([$1], [$2])]) define([_xright], [dnl ifelse(eval([$2] >= len([$1])), [0], [dnl substr([$1], [$2], 2)[]$0([$1], incr(incr([$2])))[]dnl ])[]dnl ]) define([yuck_esc], [backquote([_$0([$1], [$2], [$3], [$4])])]) define([_yuck_esc], [dnl pushdef([__next_sep], index([$1], [$2]))[]dnl ifelse([$1], [], [], defn([__next_sep]), [-1], [$4[$1]], [dnl [$4]xleft([$1], defn([__next_sep]))[$3]dnl $0(backquote([xright([$1], eval(defn([__next_sep]) + len([$2])))]), [$2], [$3], [$4])[]dnl ])[]dnl popdef([__next_sep])dnl ])dnl define([yuck_indent_line], [yuck_esc([$1], [ ], [ ], [ ])]) ## yuck_option_help_line([ident], [[cmd]]) define([yuck_option_help_line], [dnl pushdef([lhs], [backquote([yuck_option_help_lhs([$1], [$2])])])dnl pushdef([desc], [yuck_option_desc([$1], [$2])])dnl pushdef([indesc], [yuck_indent_line(backquote([desc]))])dnl pushdef([lenlhs], len(lhs))dnl ifelse(indesc, [], [lhs], eval(lenlhs >= 23), [0], [dnl lhs[]backquote([xright(indesc, lenlhs)])[]dnl ], eval(lenlhs >= 24), [0], [dnl lhs[]backquote([xright(indesc, decr(lenlhs))])[]dnl ], [dnl lhs[ ]backquote([indesc])[]dnl ]) popdef([lenlhs])dnl popdef([indesc])dnl popdef([desc])dnl popdef([lhs])dnl ]) ## yuck_first_line([string]) define([yuck_first_line], [dnl pushdef([lnlen], [index([$1], [ ])])dnl backquote([ifelse(lnlen, -1, [$1], [xleft([$1], lnlen)])])[]dnl popdef([lnlen])dnl ]) ## yuck_cmd_line([cmd]) define([yuck_cmd_line], [dnl pushdef([lhs], [backquote([yuck_cmd_string([$1])])])dnl pushdef([indesc], [dnl yuck_first_line(backquote([yuck_cmd_desc([$1])]))])dnl pushdef([lenlhs], len(lhs))dnl ifelse(indesc, [], [lhs], eval(lenlhs >= 11), [0], [dnl lhs[]backquote([xright(indesc, lenlhs)])[]dnl ], eval(lenlhs >= 12), [0], [dnl lhs[]backquote([xright(indesc, decr(lenlhs))])[]dnl ], [dnl lhs backquote([indesc])[]dnl ])dnl popdef([lenlhs])dnl popdef([indesc])dnl popdef([lhs])dnl ]) ## \n -> \\n\\ define([yuck_esc_newline], [yuck_esc([$1], [ ], [\n\ ])]) ## " -> \" define([yuck_esc_quote], [yuck_esc([$1], ["], [\"])])dnl " ## \ -> \\ define([yuck_esc_backslash], [yuck_esc([$1], [\], [\\])])dnl define([yuck_C_literal], [dnl yuck_esc_newline(yuck_esc_quote(yuck_esc_backslash([$1])))[]dnl ])dnl ## coroutine stuff define([yield], [goto $1; back_from_$1:]) define([coroutine], [define([this_coru], [$1])$1:]) define([resume], [goto back_from_[]this_coru]) define([resume_at], [goto $1]) define([quit], [goto out]) divert[]dnl changequote`'dnl dateutils-0.3.1/build-aux/yuck.man.m4000066400000000000000000000054151241477753400174150ustar00rootroot00000000000000.\" auto generated by yuck -*- nroff -*- changequote`'changequote([,])dnl ifdef([YUCK_VERSION], [], [dnl else (!YUCK_VERSION) ifdef([YUCK_SCMVER_VERSION], [dnl then define([YUCK_VERSION], [YUCK_SCMVER_VERSION])[]dnl ], [dnl else (!YUCK_SCMVER_VERSION) define([YUCK_VERSION], [unknown])dnl ])dnl ])dnl define([ucase], [translit([$1], [abcdefghijklmnopqrstuvwxyz], [ABCDEFGHIJKLMNOPQRSTUVWXYZ])])dnl ifdef([YUCK_PKG_STR], [], [define([YUCK_PKG_STR], [YUCK_UMB_STR])])dnl .TH ucase(YUCK_UMB_STR) "1" "YUCK_MAN_DATE" "YUCK_PKG_STR YUCK_VERSION" "User Commands" .SH NAME pushdef([umb_desc], [yuck_first_line(yuck_umb_desc())])dnl pushdef([alt_desc], [manual page for YUCK_PKG_STR YUCK_VERSION])dnl YUCK_UMB_STR - first_nonnil(umb_desc, alt_desc) popdef([umb_desc])dnl popdef([alt_desc])dnl .SH SYNOPSIS .B YUCK_UMB_STR [[\fIOPTION\fR]]...[ ]dnl ifelse(yuck_cmds(), [], [], [\fICOMMAND\fR])dnl []dnl yuck_esc(dnl yuck_esc(dnl yuck_esc(dnl yuck_esc(dnl yuck_esc(translit(defn([YUCK_UMB_POSARG]), [[]], []), [ -], [\fR -]), [ ], [ \fI]), [], [\fR\fI]), [], [\fR]), [...], [\fR...]) .SH DESCRIPTION yuck_umb_desc() ifelse(yuck_cmds(), [], [], [dnl .PP \fICOMMAND\fR may be one of: foreachq([__CMD__], yuck_cmds(), [dnl .TP .B yuck_cmd_string(__CMD__) . yuck_cmd_desc(__CMD__) ])dnl ])dnl .PP define([yuck_man_option], [dnl pushdef([lhs], [yuck_option_help_lhs([$1], [$2])])dnl yuck_esc(dnl yuck_esc(dnl yuck_esc(dnl yuck_esc(dnl yuck_esc(dnl yuck_esc(dnl yuck_esc(lhs, [,], [\fR,]), [ -], [ \fB-]), [], [\fR]), [=], [\fR=]), [=], [=\fI]), [], [\fR]), [...], [\fR...])dnl popdef([lhs])dnl ]) Recognized \fIOPTION\fRs: foreachq([__IDN__], yuck_idents(), [dnl .TP .B yuck_man_option(defn([__IDN__]), []) yuck_option_desc(defn([__IDN__]), []) ])dnl dnl ifelse(yuck_cmds(), [], [], [dnl .SH COMMANDS ])dnl foreachq([__CMD__], yuck_cmds(), [ .P .B YUCK_UMB_STR yuck_cmd_string(__CMD__) [[\fIOPTION\fR]]... yuck_esc(dnl yuck_esc(dnl yuck_esc(dnl yuck_esc(dnl yuck_esc(translit(yuck_cmd_posarg(__CMD__), [[]], []), [ -], [\fR -]), [ ], [ \fI]), [], [\fR\fI]), [], [\fR]), [...], [\fR...]) .br yuck_cmd_desc(C) .P \fIOPTION\fRs specific to the \fB[]yuck_cmd_string(__CMD__)\fR command: foreachq([__IDN__], yuck_idents(__CMD__), [dnl .TP .B yuck_option_help_lhs(defn([__IDN__]), defn([__CMD__])) yuck_option_desc(defn([__IDN__]), defn([__CMD__])) ])dnl ])dnl foreachq([__INC__], defn([YUCK_INCLUDES]), [dnl include(__INC__) ]) ifdef([YUCK_NFO_STR], [ .SH "SEE ALSO" The full documentation for .B YUCK_UMB_STR is maintained as a Texinfo manual. If the .B info and .B YUCK_UMB_STR programs are properly installed at your site, the command .IP .B info ifelse(YUCK_NFO_STR, YUCK_UMB_STR, [YUCK_NFO_STR], [(YUCK_NFO_STR)YUCK_UMB_STR]) .PP should give you access to the complete manual. ])dnl .\" yuck.m4man ends here changequote`'dnl dateutils-0.3.1/build-aux/yuck.mk000066400000000000000000000007141241477753400167270ustar00rootroot00000000000000## bootstrapping rules, made for inclusion in your own Makefiles yuck.m4i: yuck.yuck $(MAKE) $(AM_MAKEFLAGS) yuck-bootstrap $(AM_V_GEN) $(builddir)/yuck-bootstrap$(EXEEXT) $(srcdir)/yuck.yuck > $@ \ || { rm -f -- $@; false; } yuck.yucc: yuck.m4i yuck.m4 yuck-coru.h.m4 yuck-coru.c.m4 $(AM_V_GEN) $(M4) $(srcdir)/yuck.m4 yuck.m4i \ $(srcdir)/yuck-coru.h.m4 $(srcdir)/yuck-coru.c.m4 | \ tr '\002\003\016\017' '[]()' > $@ \ || { rm -f -- $@; false; } dateutils-0.3.1/build-aux/yuck.yuck000066400000000000000000000051221241477753400172710ustar00rootroot00000000000000Usage: yuck COMMAND [ARG]... Generate command line option parsers for umbrella commands. -k, --keep Keep intermediary files. -o, --output=FILE Output goes into FILE instead of stdout. ## Usages of the single commands Usage: yuck [OPTION]... gen [FILE]... Generate a parser from definitions in FILE, or stdin if omitted. -H, --header=FILE Also generate a header file. --no-auto-flags Do not add auto flags (--help, --version). --no-auto-actions Do not automatically handle auto flags. --version=VERSION Hardwire version number. --custom=FILE Include custom macros from FILE. ## GENMAN Usage: yuck [OPTION]... genman [FILE]... Generate a man page from definitions in FILE, or stdin if omitted. --version-string=STRING Hardwire version number as STRING. --version-file=FILE Hardwire version number from FILE. --package=STRING Use package STRING instead of umbrella. -i, --include=FILE... Include sections from FILE --info-page[=NAME] Include reference to Texinfo manual. ## GENDSL Usage: yuck gendsl [FILE]... Generate the intermediary description of definitions from FILE, or stdin if omitted. --no-auto-flags Do not add auto flags (--help, --version). --no-auto-actions Do not automatically handle auto flags. --version=VERSION Hardwire version number. ## VER Usage: yuck scmver [PATH] Guess version number for SCM controlled PATH. If PATH is a file run a transformation. If PATH is a directory just output the version number. Transformations are done through the m4 processor: YUCK_SCMVER_VTAG will expand to the tag name. YUCK_SCMVER_SCM will expand to the name of the SCM used. YUCK_SCMVER_DIST will expand to the distance, that is the number of commits since the last tag. YUCK_SCMVER_RVSN will expand to the current commit number. YUCK_SCMVER_FLAG_DIRTY is set for changes in the source tree that have not yet been committed. Definitions in the template yuck-scmver.m4 are prepended, and by default this defines the YUCK_SCMVER_VERSION macro that expands to the full version number. -v, --verbose Print additional information on stderr. --reference=FILE Store version reference in FILE and don't touch the output file if nothing has changed. -f, --force Force operation even if the current scm version coincides with the reference version. -n, --use-reference Use version number provided in the reference file instead of determining it. --ignore-noscm Don't treat no scm as error. dateutils-0.3.1/configure.ac000066400000000000000000000146751241477753400160320ustar00rootroot00000000000000dnl ------------------------------------------------------------------------- dnl Autoconf startup. dnl ------------------------------------------------------------------------- AC_PREREQ([2.63]) AC_INIT([dateutils], [0.3.1], [https://github.com/hroptatyr/dateutils/issues]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADER([src/config.h]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([src/]) dnl ------------------------------------------------------------------------- dnl Local copyright notices. dnl ------------------------------------------------------------------------- AC_COPYRIGHT([dnl #### Configuration script for dateutils and friends. #### Copyright (C) 2011-2014 Sebastian Freundt ### Don't edit this script! ### This script was automatically generated by the `autoconf' program ### from the file `./configure.ac'. ### To rebuild it, execute the command ### autoreconf ]) AM_INIT_AUTOMAKE([foreign dist-xz color-tests parallel-tests subdir-objects]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AX_YUCK_SCMVER([version.mk]) AC_CONFIG_LINKS([GNUmakefile:GNUmakefile]) ## the build chain AC_PROG_CC([icc gcc tcc cc]) SXE_CHECK_CC([gnu11 c11 gnu1x c1x gnu99 c99]) AC_CHECK_TOOLS([AR], [xiar ar], [false]) AC_C_BIGENDIAN SXE_CHECK_CFLAGS ## check for byteorder utils AC_CHECK_HEADERS([endian.h sys/endian.h machine/endian.h byteorder.h]) AC_CHECK_HEADERS([byteswap.h]) ## to make lintian happy AC_SYS_LARGEFILE ## disallow warnings from here SXE_LANG_WERROR([off]) ## check for mmap and friends SXE_CHECK_MMAP ## for getline()/fgetln() code (e.g. tzmap.c) AC_CHECK_FUNCS([getline]) AC_CHECK_FUNCS([fgetln]) ## AIX' take on stdint AC_CHECK_HEADERS([sys/stdint.h]) ## check for tzfile.h AX_ZONEINFO([right]) AM_CONDITIONAL([ZONEINFO_UTC_RIGHT], [test -n "${ax_cv_zoneinfo_utc_right}"]) ## check for strptime AC_CHECK_FUNCS([strptime]) have_strptime="${ac_cv_func_strptime}" AM_CONDITIONAL([HAVE_STRPTIME], [test "${have_strptime}" = "yes"]) ## check for working c1x features SXE_CHECK_ANON_STRUCTS_DECL SXE_CHECK_ANON_STRUCTS_INIT SXE_CHECK_SLOPPY_STRUCTS_INIT if test "${sxe_cv_have_anon_structs_decl}" != "yes"; then AC_MSG_ERROR([C compiler unusable dateutils make extensive use of c11 anonymous structs/unions but your compiler does not fully support them. Change either the CFLAGS or the compiler. Good day. ]) fi AM_PROG_LEX AC_PROG_YACC AC_PATH_PROG([GPERF], [gperf]) if test -z "${GPERF}"; then GPERF="gperf" fi AC_ARG_VAR([GPERF], [full path to the gperf tool]) ## check if we've got curl, necessary to d/l the tzmaps AC_PATH_PROG([CURL], [curl]) AC_ARG_VAR([CURL], [full path to the curl tool]) AM_CONDITIONAL([HAVE_CURL], [test -n "${CURL}"]) AC_ARG_ENABLE([tzmap-fetch], [ AS_HELP_STRING([--enable-tzmap-fetch], [Fetch tzmaps from github, default: no.])], [dnl enable_tzmap_fetch="${enableval}" if test -z "${CURL}"; then enable_tzmap_fetch="no" fi ], [enable_tzmap_fetch="no"]) AM_CONDITIONAL([FETCH_TZMAPS], [test "${enable_tzmap_fetch}" = "yes"]) AM_CONDITIONAL([HAVE_TZMAPS], [test `find "${srcdir}/lib" -name '*.tzmap' -print | wc -l` -gt 0]) AC_PATH_PROG([GDATE], [date]) AC_ARG_VAR([GDATE], [full path to the date tool]) if test -n "${GDATE}"; then ## try and use -d AC_MSG_CHECKING([if date is of GNU flavour]) if "${GDATE}" -d "2012-01-01" >/dev/null 2>/dev/null; then have_gdate="yes" else have_gdate="no" fi AC_MSG_RESULT([${have_gdate}]) fi if test -n "${GDATE}" -a "${have_gdate}" = "yes"; then ## try and use -d with a big year AC_MSG_CHECKING([if date is immune to year 2038 problem]) if "${GDATE}" -d "4095-01-01" >/dev/null 2>/dev/null; then have_gdate_2039="yes" else have_gdate_2039="no" fi AC_MSG_RESULT([${have_gdate_2039}]) fi AC_ARG_VAR([have_gdate], [yes if GDATE is of GNU flavour]) AC_ARG_VAR([have_gdate_2039], [yes if GDATE can handle years beyond 2038]) AM_CONDITIONAL([HAVE_GDATE], [test "${have_gdate}" = "yes"]) AM_CONDITIONAL([HAVE_GDATE_2039], [test "${have_gdate_2039}" = "yes"]) AC_ARG_ENABLE([fast-arith], [AS_HELP_STRING([--enable-fast-arith], [ Whether to enable fast date handling and arithmetic routines at the cost of strictness. For instance the leap year rule used is incorrect for years before 1901 and after 2100, or every month can have a 31st to denote the last day of the month.]) AS_HELP_STRING([], [Default: disabled])], [enable_fast_arith="${enableval}"], [enable_fast_arith="no"]) AC_ARG_ENABLE([contrib], [ AS_HELP_STRING([--enable-contrib], [Build contribs, default: no.])], [enable_contrib="${enableval}"], [enable_contrib="no"]) AM_CONDITIONAL([WITH_CONTRIB], [test "${enable_contrib}" != "no"]) ## checks if test "${enable_fast_arith}" = "yes"; then AC_DEFINE([WITH_FAST_ARITH], [1], [whether to use fast but incorrect date routines]) fi ## always define this one for now AC_DEFINE([WITH_LEAP_SECONDS], [1], [Whether to use leap-second aware routines]) AM_CONDITIONAL([WITH_LEAP_SECONDS], [test "1" = "1"]) ## trivial conditional so that the dexpr scanner and parser are built AM_CONDITIONAL([BUILD_DEXPR], [test "0" = "1"]) AM_CONDITIONAL([BUILD_LTRCC], [test ! -f "${srcdir}/lib/leapseconds.def"]) ## check for contrib stuff if test "${enable_contrib}" != "no"; then ## check for matlab, then octave SXE_CHECK_MATLAB SXE_CHECK_OCTAVE fi AM_CONDITIONAL([BUILD_MEXCLI], [test "${sxe_cv_matlab_mex_h}" = "yes" -a -n "${MATLABPATH}"]) AM_CONDITIONAL([BUILD_OCTCLI], [test "${sxe_cv_octave_mex_h}" = "yes" -a -n "${OCTAVEPATH}"]) ## prepare the summary page dut_apps="dadd dconv ddiff dgrep dround dseq dsort dtest dzone" if test "${have_strptime}" = "yes"; then misc_apps="strptime" else misc_apps="none" fi if test "${enable_contrib}" != "no"; then if test "${sxe_cv_matlab_mex_h}" = "yes"; then cntrb_apps="${cntrb_apps}${cntrb_apps:+ }tzconv.m(atlab)" fi if test "${sxe_cv_octave_mex_h}" = "yes"; then cntrb_apps="${cntrb_apps}${cntrb_apps:+ }tzconv.m(octave)" fi else cntrb_apps="none" fi AX_CHECK_YUCK dnl must come after all AC_LINK_IFELSE clauses ## check for the ldflags SXE_CHECK_LDFLAGS LT_INIT SXE_CHECK_LIBTOOL AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([build-aux/Makefile]) AC_CONFIG_FILES([lib/Makefile]) AC_CONFIG_FILES([src/Makefile]) AC_CONFIG_FILES([info/Makefile]) AC_CONFIG_FILES([test/Makefile]) AC_CONFIG_FILES([contrib/Makefile]) AC_OUTPUT cat < * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***/ #if defined HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include /* matlab stuff */ #if defined HAVE_OCTAVE_MEX_H # include #else /* !HAVE_OCTAVE_MEX_H */ # include #endif /* HAVE_OCTAVE_MEX_H */ /* our stuff */ #include "tzraw.h" /* see tzconv.m for details */ static zif_t find_zone(const mxArray *zstr) { char *zone = mxArrayToString(zstr); zif_t res; res = zif_open(zone); if (zone != NULL) { mxFree(zone); } return res; } void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { zif_t fromz; zif_t toz; if (nrhs != 3 || nlhs > 1) { mexErrMsgTxt("invalid usage, see `help tzconv'\n"); return; } /* find zones */ if ((fromz = find_zone(prhs[1])) == NULL) { mexErrMsgTxt("cannot open from zone\n"); } if ((toz = find_zone(prhs[2])) == NULL) { zif_close(fromz); mexErrMsgTxt("cannot open target zone\n"); } #define TO_UNIX(x) ((x) - 719529.0) * 86400.0 #define TO_MATL(x) ((x) / 86400.0) + 719529.0 { mwSize m = mxGetM(prhs[0]); mwSize n = mxGetN(prhs[0]); const double *src = mxGetPr(prhs[0]); double *tgt; plhs[0] = mxCreateDoubleMatrix(m, n, mxREAL); tgt = mxGetPr(plhs[0]); for (mwSize i = 0; i < m * n; i++) { double x = TO_UNIX(src[i]); if (x < 2147483647.0 && x > -2147483648.0) { double frac = modf(x, &x); int32_t utc = zif_utc_time(fromz, (int32_t)x); int32_t lcl = zif_local_time(toz, utc); tgt[i] = TO_MATL((double)lcl) + frac / 86400.0; } else { tgt[i] = NAN; } } } zif_close(fromz); zif_close(toz); return; } /* gand_get_series.c ends here */ dateutils-0.3.1/contrib/tzconv.m000066400000000000000000000006571241477753400167000ustar00rootroot00000000000000% tzconv convert between timezones % % Syntax: % d = tzconv(dates, from_zone, to_zone); % % Input Arguments: % dates - a vector of matlab dates to be converted % from_zone - interpret DATES as coming from FROM_ZONE % to_zone - convert DATEs to TO_ZONE % % Output Arguments: % d - vector of dates in the result % % Copyright (C) 2013 Sebastian Freundt % % This file is part of dateutils dateutils-0.3.1/info/000077500000000000000000000000001241477753400144625ustar00rootroot00000000000000dateutils-0.3.1/info/Makefile.am000066400000000000000000000224031241477753400165170ustar00rootroot00000000000000# Help the Developers and yourself. Just use the C locale and settings # for the compilation. They can still be overriden by make LANG= # but that is general a not very good idea LANG=C LC_ALL=C include $(top_builddir)/version.mk BUILT_SOURCES = EXTRA_DIST = $(BUILT_SOURCES) SUFFIXES = info_TEXINFOS = dateutils.texi dateutils_TEXINFOS = dateutils_TEXINFOS += $(built_texis) dateutils_TEXINFOS += format.texi dateutils_TEXINFOS += format-ddiff.texi dateutils_TEXINFOS += units.texi man1_MANS = man1_MANS += $(built_mans) man1_MANS += dateutils.man dateutils_EXAMPLES = dateutils_H2M_EX = dconv_EXAMPLES = dconv_EXAMPLES += $(top_srcdir)/test/dconv.001.clit dconv_EXAMPLES += $(top_srcdir)/test/dconv.002.clit dconv_EXAMPLES += $(top_srcdir)/test/dconv.003.clit dconv_EXAMPLES += $(top_srcdir)/test/dconv.004.clit dconv_EXAMPLES += $(top_srcdir)/test/tconv.001.clit dconv_EXAMPLES += $(top_srcdir)/test/tconv.002.clit dconv_EXAMPLES += $(top_srcdir)/test/dtconv.001.clit dconv_EXAMPLES += $(top_srcdir)/test/dtconv.002.clit dconv_EXAMPLES += $(top_srcdir)/test/dtconv.011.clit dconv_EXAMPLES += $(top_srcdir)/test/dtconv.012.clit dconv_EXAMPLES += $(top_srcdir)/test/dtconv.014.clit dateutils_EXAMPLES += $(dconv_EXAMPLES) dateutils_H2M_EX += dconv.h2m dseq_EXAMPLES = dseq_EXAMPLES += $(top_srcdir)/test/dseq.01.clit dseq_EXAMPLES += $(top_srcdir)/test/dseq.02.clit dseq_EXAMPLES += $(top_srcdir)/test/dseq.03.clit dseq_EXAMPLES += $(top_srcdir)/test/dseq.04.clit dseq_EXAMPLES += $(top_srcdir)/test/dseq.05.clit dseq_EXAMPLES += $(top_srcdir)/test/dseq.06.clit dseq_EXAMPLES += $(top_srcdir)/test/dseq.07.clit dseq_EXAMPLES += $(top_srcdir)/test/dseq.08.clit dseq_EXAMPLES += $(top_srcdir)/test/dseq.09.clit dseq_EXAMPLES += $(top_srcdir)/test/dseq.10.clit dseq_EXAMPLES += $(top_srcdir)/test/dseq.11.clit dseq_EXAMPLES += $(top_srcdir)/test/dseq.12.clit dseq_EXAMPLES += $(top_srcdir)/test/dseq.13.clit dseq_EXAMPLES += $(top_srcdir)/test/tseq.01.clit dseq_EXAMPLES += $(top_srcdir)/test/tseq.02.clit dseq_EXAMPLES += $(top_srcdir)/test/tseq.03.clit dseq_EXAMPLES += $(top_srcdir)/test/tseq.04.clit dateutils_EXAMPLES += $(dseq_EXAMPLES) dateutils_H2M_EX += dseq.h2m dadd_EXAMPLES = dadd_EXAMPLES += $(top_srcdir)/test/dadd.001.clit dadd_EXAMPLES += $(top_srcdir)/test/dadd.002.clit dadd_EXAMPLES += $(top_srcdir)/test/dadd.003.clit dadd_EXAMPLES += $(top_srcdir)/test/dadd.004.clit dadd_EXAMPLES += $(top_srcdir)/test/tadd.001.clit dadd_EXAMPLES += $(top_srcdir)/test/tadd.002.clit dadd_EXAMPLES += $(top_srcdir)/test/tadd.003.clit dateutils_EXAMPLES += $(dadd_EXAMPLES) dateutils_H2M_EX += dadd.h2m dtest_EXAMPLES = dtest_EXAMPLES += $(top_srcdir)/test/dtest.001.clit dtest_EXAMPLES += $(top_srcdir)/test/dtest.002.clit dtest_EXAMPLES += $(top_srcdir)/test/dtest.003.clit dtest_EXAMPLES += $(top_srcdir)/test/dtest.004.clit dtest_EXAMPLES += $(top_srcdir)/test/dtest.005.clit dtest_EXAMPLES += $(top_srcdir)/test/ttest.001.clit dtest_EXAMPLES += $(top_srcdir)/test/ttest.002.clit dtest_EXAMPLES += $(top_srcdir)/test/ttest.003.clit dtest_EXAMPLES += $(top_srcdir)/test/ttest.004.clit dtest_EXAMPLES += $(top_srcdir)/test/dttest.010.clit dtest_EXAMPLES += $(top_srcdir)/test/dttest.002.clit dtest_EXAMPLES += $(top_srcdir)/test/dttest.003.clit dtest_EXAMPLES += $(top_srcdir)/test/dttest.004.clit dtest_EXAMPLES += $(top_srcdir)/test/dttest.005.clit dateutils_EXAMPLES += $(dtest_EXAMPLES) dateutils_H2M_EX += dtest.h2m ddiff_EXAMPLES = ddiff_EXAMPLES += $(top_srcdir)/test/ddiff.001.clit ddiff_EXAMPLES += $(top_srcdir)/test/ddiff.002.clit ddiff_EXAMPLES += $(top_srcdir)/test/ddiff.003.clit ddiff_EXAMPLES += $(top_srcdir)/test/ddiff.004.clit ddiff_EXAMPLES += $(top_srcdir)/test/ddiff.005.clit ddiff_EXAMPLES += $(top_srcdir)/test/ddiff.006.clit ddiff_EXAMPLES += $(top_srcdir)/test/ddiff.008.clit ddiff_EXAMPLES += $(top_srcdir)/test/tdiff.001.clit ddiff_EXAMPLES += $(top_srcdir)/test/tdiff.002.clit ddiff_EXAMPLES += $(top_srcdir)/test/tdiff.003.clit ddiff_EXAMPLES += $(top_srcdir)/test/tdiff.008.clit ddiff_EXAMPLES += $(top_srcdir)/test/tdiff.006.clit ddiff_EXAMPLES += $(top_srcdir)/test/tdiff.007.clit ddiff_EXAMPLES += $(top_srcdir)/test/dtdiff.001.clit ddiff_EXAMPLES += $(top_srcdir)/test/dtdiff.003.clit ddiff_EXAMPLES += $(top_srcdir)/test/dtdiff.011.clit ddiff_EXAMPLES += $(top_srcdir)/test/dtdiff.012.clit dateutils_EXAMPLES += $(ddiff_EXAMPLES) dateutils_H2M_EX += ddiff.h2m dgrep_EXAMPLES = dgrep_EXAMPLES += $(top_srcdir)/test/dgrep.001.clit dgrep_EXAMPLES += $(top_srcdir)/test/dgrep.002.clit dgrep_EXAMPLES += $(top_srcdir)/test/dgrep.006.clit dgrep_EXAMPLES += $(top_srcdir)/test/dgrep.007.clit dgrep_EXAMPLES += $(top_srcdir)/test/dgrep.008.clit dgrep_EXAMPLES += $(top_srcdir)/test/tgrep.001.clit dgrep_EXAMPLES += $(top_srcdir)/test/tgrep.002.clit dgrep_EXAMPLES += $(top_srcdir)/test/dtgrep.001.clit dgrep_EXAMPLES += $(top_srcdir)/test/dtgrep.002.clit dgrep_EXAMPLES += $(top_srcdir)/test/dtgrep.005.clit dgrep_EXAMPLES += $(top_srcdir)/test/dtgrep.006.clit dateutils_EXAMPLES += $(dgrep_EXAMPLES) dateutils_H2M_EX += dgrep.h2m dround_EXAMPLES = dround_EXAMPLES += $(top_srcdir)/test/dround.002.clit dround_EXAMPLES += $(top_srcdir)/test/dround.003.clit dround_EXAMPLES += $(top_srcdir)/test/tround.003.clit dround_EXAMPLES += $(top_srcdir)/test/tround.002.clit dateutils_EXAMPLES += $(dround_EXAMPLES) dateutils_H2M_EX += dround.h2m dzone_EXAMPLES = dzone_EXAMPLES += $(top_srcdir)/test/dzone.001.clit dzone_EXAMPLES += $(top_srcdir)/test/dzone.002.clit dzone_EXAMPLES += $(top_srcdir)/test/dzone.003.clit dzone_EXAMPLES += $(top_srcdir)/test/dzone.004.clit dateutils_EXAMPLES += $(dzone_EXAMPLES) dateutils_H2M_EX += dzone.h2m dsort_EXAMPLES = dsort_EXAMPLES += $(top_srcdir)/test/dsort.001.clit dsort_EXAMPLES += $(top_srcdir)/test/dsort.002.clit dsort_EXAMPLES += $(top_srcdir)/test/dsort.003.clit dsort_EXAMPLES += $(top_srcdir)/test/dsort.004.clit dsort_EXAMPLES += $(top_srcdir)/test/dsort.005.clit dsort_EXAMPLES += $(top_srcdir)/test/dsort.006.clit dateutils_EXAMPLES += $(dsort_EXAMPLES) dateutils_H2M_EX += dsort.h2m if HAVE_STRPTIME strptime_EXAMPLES = strptime_EXAMPLES += $(top_srcdir)/test/strptime.001.clit strptime_EXAMPLES += $(top_srcdir)/test/strptime.002.clit dateutils_EXAMPLES += $(strptime_EXAMPLES) dateutils_H2M_EX += strptime.h2m endif HAVE_STRPTIME EXTRA_DIST += author.h2m BUILT_SOURCES += format.th2m BUILT_SOURCES += format-ddiff.th2m BUILT_SOURCES += units.th2m BUILT_SOURCES += $(dateutils_H2M_EX) BUILT_SOURCES += $(built_texis) BUILT_SOURCES += $(built_mans) dist_noinst_SCRIPTS = gentexi.sh genh2m.sh texi2h2m.sh built_texis = built_texis += strptime.texi built_texis += dadd.texi built_texis += dconv.texi built_texis += ddiff.texi built_texis += dgrep.texi built_texis += dround.texi built_texis += dseq.texi built_texis += dsort.texi built_texis += dtest.texi built_texis += dzone.texi built_mans = if HAVE_STRPTIME built_mans += strptime.man endif HAVE_STRPTIME built_mans += dadd.manu built_mans += dconv.man built_mans += ddiff.mand built_mans += dgrep.man built_mans += dround.manu built_mans += dseq.manu built_mans += dsort.man built_mans += dtest.man built_mans += dzone.man EXTRA_DIST += $(man1_MANS) EXTRA_DIST += $(dateutils_TEXINFOS) ## just to aid the suffix rules strptime.man: strptime.h2m dadd.manu: dadd.h2m dconv.man: dconv.h2m ddiff.mand: ddiff.h2m dgrep.man: dgrep.h2m dround.manu: dround.h2m dseq.manu: dseq.h2m dsort.man: dsort.h2m dtest.man: dtest.h2m dzone.man: dzone.h2m SUFFIXES += .yuck VPATH += @top_srcdir@/src SUFFIXES += .man .yuck.man: $(AM_V_GEN) PATH="$(top_builddir)/build-aux:$${PATH}" \ yuck$(EXEEXT) genman \ --package "$(PACKAGE_NAME)" \ --info-page \ -i "$(builddir)/format.th2m" \ -i "$(builddir)/$*.h2m" \ -i "$(srcdir)/author.h2m" \ -o $@ --version-file "$(top_builddir)/.version" $< ## generic rule with format-ddiff instead of format SUFFIXES += .mand .yuck.mand: $(AM_V_GEN) PATH="$(top_builddir)/build-aux:$${PATH}" \ yuck$(EXEEXT) genman \ --package "$(PACKAGE_NAME)" \ --info-page \ -i "$(builddir)/format-ddiff.th2m" \ -i "$(builddir)/$*.h2m" \ -i "$(srcdir)/author.h2m" \ -o $@ --version-file "$(top_builddir)/.version" $< ## generic rule for man pages with units section SUFFIXES += .manu .yuck.manu: $(AM_V_GEN) PATH="$(top_builddir)/build-aux:$${PATH}" \ yuck$(EXEEXT) genman \ --package "$(PACKAGE_NAME)" \ --info-page \ -i "$(builddir)/format.th2m" \ -i "$(builddir)/units.th2m" \ -i "$(builddir)/$*.h2m" \ -i "$(srcdir)/author.h2m" \ -o $@ --version-file "$(top_builddir)/.version" $< my_bld_h2m = $(__bld_h2m_$(V)) __bld_h2m_ = $(__bld_h2m_$(AM_DEFAULT_VERBOSITY)) __bld_h2m_0 = @echo " GENH2M " $*; SUFFIXES += .h2m .yuck.h2m: $(dateutils_EXAMPLES) $(my_bld_h2m) ${SHELL} \ $(srcdir)/genh2m.sh $(top_builddir)/src/$* \ $($*_EXAMPLES) > $@ || rm -f -- $@ my_bld_texi = $(__bld_texi_$(V)) __bld_texi_ = $(__bld_texi_$(AM_DEFAULT_VERBOSITY)) __bld_texi_0 = @echo " GENTEXI " $*; SUFFIXES += .texi .yuck.texi: $(dateutils_EXAMPLES) dateutils.texi $(my_bld_texi) ${SHELL} \ $(srcdir)/gentexi.sh $(top_builddir)/src/$* \ $($*_EXAMPLES) > $@ || test "$$?" = "2" || rm -f -- $@ my_bld_th2m = $(__bld_th2m_$(V)) __bld_th2m_ = $(__bld_th2m_$(AM_DEFAULT_VERBOSITY)) __bld_th2m_0 = @echo " GENTH2M " $*; SUFFIXES += .th2m .texi.th2m: $(my_bld_th2m) ${SHELL} \ $(srcdir)/texi2h2m.sh $< > $@ || rm -f -- $@ ## Makefile.am ends here dateutils-0.3.1/info/author.h2m000066400000000000000000000002141241477753400163710ustar00rootroot00000000000000[Author] Written by Sebastian Freundt [Reporting bugs] Report bugs to: https://github.com/hroptatyr/dateutils/issues dateutils-0.3.1/info/dadd.name000066400000000000000000000000561241477753400162210ustar00rootroot00000000000000[NAME] dadd - Add durations to dates or times dateutils-0.3.1/info/dateutils.man000066400000000000000000000023751241477753400171640ustar00rootroot00000000000000.TH DATEUTILS "1" "September 2012" "dateutils" "User Commands" .SH NAME dateutils \- command line date and time utilities .SH DESCRIPTION dateutils are a bunch of tools that revolve around fiddling with dates and times in the command line with a strong focus on use cases that arise when dealing with large amounts of financial data. .PP .SH COMMANDS .PP \fBdadd\fR(1) .RS 4 Add durations to dates or times .RE .PP \fBdconv\fR(1) .RS 4 Convert dates between calendars or time zones .RE .PP \fBddiff\fR(1) .RS 4 Compute durations between dates and times .RE .PP \fBdgrep\fR(1) .RS 4 Find date or time matches in input stream .RE .PP \fBdround\fR(1) .RS 4 Round dates or times to designated values .RE .PP \fBdseq\fR(1) .RS 4 Generate sequences of dates or times .RE .PP \fBdtest\fR(1) .RS 4 Compare dates or times .RE .PP \fBstrptime\fR(1) .RS 4 Command line version of the C function .RE .SH AUTHOR Written by Sebastian Freundt .SH "REPORTING BUGS" Report bugs to: https://github.com/hroptatyr/dateutils/issues .SH "SEE ALSO" The full documentation for .B dateutils is maintained as a Texinfo manual. If the .B info program is properly installed at your site, the command .IP .B info dateutils .PP should give you access to the complete manual. dateutils-0.3.1/info/dateutils.texi000066400000000000000000000341571241477753400173650ustar00rootroot00000000000000\input texinfo @c -*-texinfo-*- @setfilename dateutils.info @comment node-name, next, previous, up @ifinfo @dircategory Miscellaneous @direntry * dateutils: (dateutils). Command line tools to fiddle with dates. @end direntry @dircategory Individual utilities @direntry * dadd: (dateutils)dadd. Add durations to dates or times. * dconv: (dateutils)dconv. Convert dates between calendars or time zones. * ddiff: (dateutils)ddiff. Compute durations between dates and times. * dgrep: (dateutils)dgrep. Find date or time matches in input stream. * dround: (dateutils)dround. Round dates or times to designated values. * dseq: (dateutils)dseq. Sequences of dates or times. * dsort: (dateutils)dsort. Sort chronologically. * dtest: (dateutils)dtest. Compare dates or times. * dzone: (dateutils)dzone. Convert date/times to different timezones in bulk. * strptime: (dateutils)strptime. Command line version of the C function. @end direntry This manual documents the dateutils package. Copyright @copyright{} 2011-2014 Sebastian Freundt. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". @end ifinfo @c @setchapternewpage odd @settitle dateutils User's Manual @c @titlepage @sp 6 @center @titlefont{dateutils User's Manual} @sp 4 @sp 1 @sp 1 @center September 2011 @sp 5 @center Sebastian Freundt @page @vskip 0pt plus 1filll Copyright @copyright{} 2011-2014 Sebastian Freundt. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". @end titlepage @page @node Top @top dateutils dateutils are a bunch of tools that revolve around fiddling with dates and times in the command line with a strong focus on use cases that arise when dealing with large amounts of financial data. @menu * Introduction:: Motivation, background, etc. * Calendars:: Calendar concepts and format specs * Format specifiers and units:: How to control input and output * Algorithms:: Some notes on the algorithms used * dadd:: Add durations to dates or times * dconv:: Convert dates between calendars or time zones * ddiff:: Compute durations between dates and times * dgrep:: Find date or time matches in input stream * dround:: Round dates or times to designated values * dseq:: Generate sequences of dates or times * dsort:: Sort the contents of files chronologically * dtest:: Compare dates or times * dzone:: Convert date/times to timezones in bulk * strptime:: Command line version of the C function @end menu @node Introduction @chapter Introduction The dateutils package is an attempt to provide a comprehensive set of command line tools that behave intuitively, support a similar variety of inputs, allow for normalised output and, most importantly, cover nearly all tasks that arise whilst dealing with huge amounts of dates and unusual calendars. In day to day business, the authors have run across a plethora of approaches to tackle seemingly simple problems. When the command line is a necessity most of these involve perl or awk, which suffer from bad maintainability simply because those tools weren't made to process dates and times in particular, and for the same reason those approaches are anything but fast. And conversely, good maintainability and fast processing is often seen in integrated systems, such as R or database solutions but they come at a price: little flexibility. It's very uncommon to import billions of dates into a database just to compare if they are greater than or equal to a given date. Besides, most of the time those billions of dates come from external sources and have to be brought into shape before or whilst importing them into an integrated system. @node Calendars @chapter Calendars All of the dateutils command line apps are built around a library, libdut. The textual representation of dates is converted to an internal one first, then the date operation is performed and the internal representation in the end is converted back to a textual one. While many of the tools that provide date arithmetic or conversions employ a single standard internal representation (mostly days since a reference date, or seconds since the epoch), the date-core library provides a variety of calendars, each suitable for one or more specific tasks. Usually it's the tool's task to find out which calendar is the best for the task at hand, but to use the library directly we give an overview of the supported calendars here along with some of their properties. @section ymd, aka gregorian This is the `ordinary' calendar, holding a year, a month and the day of the month. Years are subdivided into 12 months, months are subdivided into 28 to 31 days. The canonical input and output format is @code{%Y-%m-%d} (ISO 8601). For outputs the format string @code{ymd} can be used as well. @section ymcw This is a calendric system used at some security exchanges, and can be thought of as a mixture of the year-month-day and year-week-day calendars. It holds a year, a month, a weekday and the count of the weekday within the month. So dates like the third Thursday in March 2011 can be expressed trivially in this system. Years are subdivided into months as in the ymd calendar, months consist of at least 4 and up to 5 weeks and weeks are subdivided into weekdays, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday. The canonical input and output format is @code{%Y-%m-%c-%w}. The week is enumerated by 01 for Monday, 02 for Tuesday, @dots{}, 07 for Sunday, as mandated by ISO 8601. For outputs the format string @code{ymcw} can be used as well. @section ywd This calendar is ISO's 8601 year-week-day calendar. Every year is divided into 52 weeks. Every week is divided into 7 days, starting with Monday. To make up for ``missing days'' a leap week is introduced every now and again, i.e. years with leap weeks are 53 weeks long and called leap years (note: ISO does not use the term leap year or leap week). The canonical input and output format is @code{%rY-W%V-%u}, so e.g. 2012-W04-02. Note that ywd years don't necessarily correspond to Gregorian/ymd years, hence the @code{r} modifier in the spec (@code{%rY} is used in calendars to select the ``real'' calendar year). The format string @code{ywd} can be used as well. @section daisy This is one of the most common calendric systems, it counts the days since a given reference date (we originally went for daysi, short for days since, but after the 100th spelling mistake, because daisy is so much more natural, we decided to stick with daisy). In the Julian calendar this was the founding of Rome, in many database systems this is the 1st Jan 1, or other convenient dates like the 1st Jan 1970 or 1st Jan 1900. The (internal) dateutils reference day is the 31st Dec 1600, or equivalently the Naught-th of Jan 1601. This may look like an arbitrary date but it has some interesting properties: - it is a Sunday, so weekday computation is easy as it is a mod 7 operation only - the year is 1 mod 4, so the number of leap years between the reference year and any other year Y is simply Y div 4. In earlier versions we used 1917 for the reference year because it's the first year after 1900 that meets the conditions above. But then we relaxed leap year rules to support dates beyond 2100 (2100 isn't a leap year) so for symmetry reasons we should support years before 1917 in a similar fashion. The daisy calendar has no notion of years or months. The daisy calendar as such has no associated input or output format. This is because we reserve the freedom to change the reference date in the future (like we have done in the past). However, daisy is easily converted to and from other similar day counting systems so their input and output format may be used instead. Also noteworthy on a more informative level, dateutils globally assumes the Gregorian date switch to have taken place in October 1582. This is unlike some other well-known tools (Unix cal for instance) which assume the reformation to have occurred in September 1752. @subsection julian, jdn A close sibling to the daisy system described before is the Julian day number, with reference date 01 Jan 4713 BC in the proleptic Julian calendar. The input and output format string is @code{jdn} or @code{julian}, there is no format specifier. @subsection lilian, ldn Another close sibling to the daisy system is the Lilian day number, its reference date is the first day of the Gregorian calendar, 15 Oct 1582. The input and output format string is @code{ldn} or @code{lilian}, there is no format specifier. @section bizda This calendric system is actually a whole tribe of calendars, in its canonical form this tracks the number of business days after last month's ultimo. Where business day means any non-weekend day. Years are divided into 12 months, each of which consists of 20 to 23 business days. The canonical input and output format is @code{%Y-%m-%db}, where @code{b} is a suffix modifier meaning business days since last month's ultimo. Similarly, @code{%Y-%m-%dB} stands for the business days until this month's ultimo. @node Format specifiers and units @chapter Format specifiers and units The tools provided by dateutils would be pretty meaningless if you could not control how input is to be read or results are to be printed. Following the footsteps of proven systems (such as libc) output formatting is controlled through format specifiers (and flags), as covered by the next 2 sections. Nonetheless, some tools (@samp{dadd}, @samp{dseq}) require durations to be input. Their syntax is covered in the final section. @include format.texi @include format-ddiff.texi @include units.texi @node Algorithms @chapter Algorithms Coming from a financial background, shaving milliseconds off of code is daily core business. And that in turn is why some of the algorithms used in dateutils might look different to what other people do. In this chapter key concepts are briefly introduced. For implementation details see the @file{*-core.c} and @file{*-core.h} files. @section 32-adic year-days Months, in the Gregorian sense, are roughly 30 days long. Some are longer, one is shorter. It comes in handy though that the average month length is close to a 2-power, 32. So we can introduce a 32-adic year as follows: @verbatim year-day traditional 32-adic m/d 0 19 Jan|00 00|19 1 20 Jan|01 00|20 31 50 Jan|31 01|18 32 51 Feb|01 01|19 59 78 Feb|28 02|14 60 79 Mar|01 02|15 90 109 Mar|31 03|13 91 110 Apr|01 03|14 120 139 Apr|30 04|11 121 140 May|01 04|12 151 170 May|31 05|10 181 200 Jun|30 06|08 212 231 Jul|31 07|07 243 262 Aug|31 08|06 273 292 Sep|30 09|04 304 323 Oct|31 10|03 334 353 Nov|30 11|01 365 384 Dec|31 12|00 @end verbatim As can be seen, the year has 19 unexplained days at the beginning, and, more unintuitively, (traditional) months start in one (32-adic) month and end in another. But the ending always coincides with the traditional months. Another nice thing about this year is that all months end on a @emph{different} day; this is nice because you can deduce the month just by naming its ending (or the beginning respectively, as all months as a consequence also start on a different day). The final nice thing lies in the property, that months that end (or start) on a day <=16, are affected by the leap day introduced in Feb in the traditional Gregorian calendar. By affected we mean, that the months start (and end) one day off in a leap year. So to cut this story short, the 32-adic year makes computations easier that need a lot of mapping between the day in the year and the month+day representation, e.g. weekday computations (the 32-adic year preserves weekdays as 32 and 7 are co-prime), day differences, etc. The algorithm to get the day of the year from a 32-adic month+day is: @verbatim Input: m <- 32-adic month d <- 32-adic day of month Output: yd -> day of year yd <- m * 32 + d - 19 @end verbatim And conversely. The algorithm to get the 32-adic month+day is trivial. To convert between 32-adic month+day and Gregorian month+day: @verbatim Input: m <- 32-adic month d <- 32-adic day of month Output: m -> 32-adic month d -> 32-adic day of month /* day of month of the beginning and end of m */ bom <- get_beg_of_month(m) eom <- get_end_of_month(m) /* get yd as described above */ yd <- get_yd(m, d) if d <= eom d <- yd - (32 * (m - 1) - 19 + bom - 1) else d <- yd - (32 * m - 19 + eom) m <- m + 1 @end verbatim @include dadd.texi @include dconv.texi @include ddiff.texi @include dgrep.texi @include dround.texi @include dseq.texi @include dsort.texi @include dtest.texi @include dzone.texi @include strptime.texi @summarycontents @contents @bye @c Remember to delete these lines before creating the info file. @iftex @bindingoffset = 0.5in @parindent = 0pt @end iftex dateutils-0.3.1/info/dconv.name000066400000000000000000000000751241477753400164370ustar00rootroot00000000000000[NAME] dconv - Convert dates between calendars or time zones dateutils-0.3.1/info/ddiff.name000066400000000000000000000000711241477753400163760ustar00rootroot00000000000000[NAME] ddiff - Compute durations between dates and times dateutils-0.3.1/info/dgrep.name000066400000000000000000000000711241477753400164230ustar00rootroot00000000000000[NAME] dgrep - Find date or time matches in input stream dateutils-0.3.1/info/dround.name000066400000000000000000000000721241477753400166160ustar00rootroot00000000000000[NAME] dround - Round dates or times to designated values dateutils-0.3.1/info/dseq.name000066400000000000000000000000711241477753400162560ustar00rootroot00000000000000[NAME] ddiff - Compute durations between dates and times dateutils-0.3.1/info/dtest.name000066400000000000000000000000461241477753400164470ustar00rootroot00000000000000[NAME] dtest - Compare dates or times dateutils-0.3.1/info/dzone.name000066400000000000000000000000641241477753400164430ustar00rootroot00000000000000[NAME] dzone - Convert date/times between timezones dateutils-0.3.1/info/format-ddiff.texi000066400000000000000000000072241241477753400177240ustar00rootroot00000000000000@section Format specs for durations Unlike time or absolute instants, durations are reference-free, i.e. the reference instant is not part of the duration. As a result durations cannot be named, i.e. there is no naming scheme that applies to all durations and all references unambiguously. Consequently, none of the format specifiers for date/times makes sense for durations in the literal sense. However, to aid intuitive usage we reused format specifiers when they represent integral values and a valid unit for duration, as follows: Date specs: @verbatim %c Equivalent to %w %d Durations in days %F Equivalent to %dd with no resorting to bigger units %m Durations in months %w Durations in weeks %y Equivalent to %Y %Y Durations in years %db Duration in business days %dB Equivalent to %db @end verbatim Time specs: @verbatim %H Durations in hours %I Equivalent to %H %M Durations in minutes %S Durations in seconds %T Equivalent to %Ss without resorting to bigger units %rS Durations in real-life seconds, as in including leap seconds %rT Equivalent to %rSs without resoring to bigger units @end verbatim General specs: @verbatim %n A newline character %t A tab character %% A literal % character @end verbatim Modifiers: @verbatim %r Modifier to turn units into real units %0 Modifier to pad refined values with zeroes %SPC Modifier to pad refined values with spaces b Suffix, treat days as business days @end verbatim @section The refinement rule Durations are somewhat ambiguous when it comes to representing them through format specifiers. Unlike format specifiers in point-in-time representations duration specifiers can have an intra-line relationship. So for instance a duration of 128 seconds might be presented through @samp{%S} as @samp{128} but similarly through @samp{%M:%S} as @samp{02:08} (read two minutes and 8 seconds). There are several approaches to deal with this ambiguity. The ddiff tool will follow, what we call, the refinement rule. That is, regardless of the position of a format specifier, if it is a valid @emph{refinement} of another specifier in the format string, then it will only show the fractional value, i.e. the value in its natural range with respect to the @emph{refined} specifier. @verbatim %Y possible refinements: %m, %w, %d %m possible refinements: %w, %d %w possible refinements: %d %d possible refinements: %H, %M, %S %H possible refinements: %M, %S %M possible refinements: %S @end verbatim The refinement alternatives are listed in order of precedence and they are mutually exclusive. I.e. it is not possible to express a duration in months and hours without having a @samp{%d} specifier as well. On the other hand in a chain of refinements inner elements are optional, i.e. you can express a duration in weeks and hours because every day has 24 hours and hence there are 168 hours in a week. In case of negative durations (the minuend is in the future relative to the subtrahend) @emph{only} the largest unit will carry the minus sign. Using the refinement rule keeps the format string dead simple, there's no need for operators or a full-blown language to distinguish the range ambiguity, which then would have to be escaped because they could also in theory be part of the literal characters of the format string, resulting more often than not in command lines that are hard to craft and even harder to understand later on (e.g. if used in shell scripts). The refinement rule ingeniously covers the 99% case but, unlike other approaches, there's @emph{no} way to display two unrefined values in the same format string, e.g. @samp{'%w weeks (which is %d days)'}. dateutils-0.3.1/info/format.texi000066400000000000000000000066121241477753400166520ustar00rootroot00000000000000@section Format specs Format specs in dateutils are similar to posix' strftime(). However, due to a broader range of supported calendars dateutils must employ different rules. Date specs: @verbatim %a The abbreviated weekday name %A The full weekday name %_a The weekday name shortened to a single character (MTWRFAS) %b The abbreviated month name %B The full month name %_b The month name shortened to a single character (FGHJKMNQUVXZ) %c The count of the weekday within the month (range 00 to 05) %C The count of the weekday within the year (range 00 to 53) %d The day of the month, 2 digits (range 00 to 31) %D The day of the year, 3 digits (range 000 to 366) %F Equivalent to %Y-%m-%d (ymd's canonical format) %j Equivalent to %D %m The month in the current calendar (range 00 to 19) %Q The quarter of the year (range Q1 to Q4) %q The number of the quarter (range 01 to 04) %s The number of seconds since the Epoch. %u The weekday as number (range 01 to 07, Sunday being 07) %U The week count, first day of week is Sun (range 00 to 53) %V The ISO week count, first day of week is Mon (range 01 to 53) %w The weekday as number (range 00 to 06, Sunday being 00) %W The week count, first day of week is Mon (range 00 to 53) %y The year without a century (range 00 to 99) %Y The year including the century %Z The zone offset in hours and minutes (HH:MM) with a preceding sign (+ for offsets east of UTC, - for offsets west of UTC) %Od The day as roman numerals %Om The month as roman numerals %Oy The two digit year as roman numerals %OY The year including the century as roman numerals %rs In time systems whose Epoch is different from the unix Epoch, this selects the number of seconds since then. %rY In calendars with years that don't coincide with the Gregorian years, this selects the calendar's year. %dth The day of the month as an ordinal number, 1st, 2nd, 3rd, etc. %mth The month of the year as an ordinal number, 1st, 2nd, 3rd, etc. %db The business day of the month (since last month's ultimo) %dB Number of business days until this month's ultimo @end verbatim Time specs: @verbatim %H The hour of the day using a 24h clock, 2 digits (range 00 to 23) %I The hour of the day using a 12h clock, 2 digits (range 01 to 12) %M The minute (range 00 to 59) %N The nanoseconds (range 000000000 to 999999999) %p The string AM or PM, noon is PM and midnight is AM. %P Like %p but in lowercase %S The second (range 00 to 60, 60 is for leap seconds) %T Equivalent to %H:%M:%S @end verbatim General specs: @verbatim %n A newline character %t A tab character %% A literal % character @end verbatim Modifiers: @verbatim %O Modifier to turn decimal numbers into Roman numerals %r Modifier to turn units into real units th Suffix, read and print ordinal numbers b Suffix, treat days as business days @end verbatim By design dates before 1601-01-01 are not supported. For conformity here is a list of calendar designators and their corresponding format string: @verbatim ymd %Y-%m-%d ymcw %Y-%m-%c-%w ywd %rY-W%V-%u bizda %Y-%m-%db lilian n/a ldn n/a julian n/a jdn n/a @end verbatim These designators can be used as output format string, moreover, @code{lilian}/@code{ldn} and @code{julian}/@code{jdn} can also be used as input format string. dateutils-0.3.1/info/genh2m.sh000077500000000000000000000005241241477753400162020ustar00rootroot00000000000000#!/bin/sh ## usage gentexi BINARY if test -x "${1}"; then BINARY="${1}" BINNAME=$(basename "${BINARY}") shift else echo "${1} not a binary" >&2 exit 1 fi echo "[EXAMPLES]" if test "${#}" -eq 0; then exit 0 fi for i; do echo sed '/^#!/d; /ends here$/d; /^[ \t]*$/d; s/@/@@/g; s/{/@{/g; s/}/@}/g s/^/ /' "${i}" echo done exit 0 dateutils-0.3.1/info/gentexi.sh000077500000000000000000000013701241477753400164650ustar00rootroot00000000000000#!/bin/sh ## usage gentexi BINARY BINARY="${1}" BINNAME=$(basename "${BINARY}") shift if ! test -x "${BINARY}"; then echo "${BINARY} not found, generating dummy" >&2 cat < $@ || rm -f $@ ## version rules version.c: version.c.in $(top_builddir)/.version $(AM_V_GEN) PATH="$(top_builddir)/build-aux:$${PATH}" \ yuck$(EXEEXT) scmver --ignore-noscm --force -o $@ \ --use-reference --reference $(top_builddir)/.version $< ## yuck rule SUFFIXES += .yuck SUFFIXES += .yucc .yuck.yucc: $(AM_V_GEN) PATH="$(top_builddir)/build-aux:$${PATH}" \ yuck$(EXEEXT) gen -o $@ $< ## gperf rule SUFFIXES += .gperf .gperf.c: $(AM_V_GEN) $(GPERF) -L ANSI-C $< --output-file $@ ## tzmap rules SUFFIXES += .tzminfo SUFFIXES += .tzmap SUFFIXES += .tzmcc TZMAP_URL := https://raw.github.com/hroptatyr/dateutils/tzmaps .tzminfo.tzmap: -$(AM_V_DL) curl -qgskfLO -D "$*.hdr" "$(TZMAP_URL)/$@" \ || { echo "Cannot download latest tzmaps:" >&2; \ cat "$*.hdr" >&2; \ echo -e "\n\ You can download them from https://github.com/hroptatyr/dateutils/tree/tzmaps\n\ or if you happen to use the git repository copy them rom the tzmaps branch\n\ and put them into $(abs_builddir).\n\ \n" >&2; } -@$(RM) -- "$*.hdr" .tzmap.tzmcc: -$(AM_V_GEN) $(builddir)/tzmap cc -e -o $@ $< ## make sure installing the tzmaps isn't fatal either .IGNORE: install-pkgdataDATA ## for dist or distcheck we need libdut.a dist-hook: $(noinst_LIBRARIES) # # Help the developers get nice post-processed source files ## Create preprocessor output (debugging purposes only) .c.i: $(COMPILE) -E -o $@ $< ## Create assembler output (debugging purposes only) .c.s: $(COMPILE) -S -c $(AM_CFLAGS) $< dateutils-0.3.1/lib/bizda.c000066400000000000000000000374241241477753400155440ustar00rootroot00000000000000/*** bizda.c -- guts for bizda dates * * Copyright (C) 2010-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ /* set aspect temporarily */ #define ASPECT_BIZDA /* permanent aspect, to be read as have we ever seen aspect_bizda */ #if !defined ASPECT_BIZDA_ #define ASPECT_BIZDA_ #endif /* !ASPECT_BIZDA_ */ #if !defined DEFUN # define DEFUN #endif /* !DEFUN */ #if !defined BIZDA_ASPECT_HELPERS_ #define BIZDA_ASPECT_HELPERS_ #if defined ASPECT_YMD static int __get_d_equiv(dt_dow_t dow, int b) { /* return the number of gregorian days B business days away from now, * where the first day is on a DOW. */ int res = 0; switch (dow) { case DT_MONDAY: case DT_TUESDAY: case DT_WEDNESDAY: case DT_THURSDAY: case DT_FRIDAY: res += GREG_DAYS_P_WEEK * (b / (signed int)DUWW_BDAYS_P_WEEK); b %= (signed int)DUWW_BDAYS_P_WEEK; break; case DT_SATURDAY: res++; case DT_SUNDAY: res++; b--; res += GREG_DAYS_P_WEEK * (b / (signed int)DUWW_BDAYS_P_WEEK); if ((b %= (signed int)DUWW_BDAYS_P_WEEK) < 0) { /* act as if we're on the monday after */ res++; } dow = DT_MONDAY; break; case DT_MIRACLEDAY: default: break; } /* fixup b */ if (b < 0) { res -= GREG_DAYS_P_WEEK; b += DUWW_BDAYS_P_WEEK; } /* b >= 0 && b < 5 */ switch (dow) { case DT_MONDAY: case DT_TUESDAY: case DT_WEDNESDAY: case DT_THURSDAY: case DT_FRIDAY: if ((int)dow + b <= (int)DT_FRIDAY) { res += b; } else { res += b + 2; } break; case DT_MIRACLEDAY: default: res = 0; break; } return res; } #endif /* ASPECT_YMD */ static int __get_b_equiv(dt_dow_t dow, int d) { /* return the number of business days D gregorian days away from now, * where the first day is on a DOW. */ int res = 0; switch (dow) { case DT_MONDAY: case DT_TUESDAY: case DT_WEDNESDAY: case DT_THURSDAY: case DT_FRIDAY: res += DUWW_BDAYS_P_WEEK * (d / (signed int)GREG_DAYS_P_WEEK); d %= (signed int)GREG_DAYS_P_WEEK; break; case DT_SATURDAY: res--; case DT_SUNDAY: res--; d--; res += DUWW_BDAYS_P_WEEK * (d / (signed int)GREG_DAYS_P_WEEK); if ((d %= (signed int)GREG_DAYS_P_WEEK) < 0) { /* act as if we're on the friday before */ res++; } dow = DT_MONDAY; break; case DT_MIRACLEDAY: default: break; } /* invariant dow + d \in [-6,13] */ switch ((int)dow + d) { case -6: case -5: case -4: case -3: case -2: res += d + 2; break; case -1: res += d + 2; break; case 0: res += d + 1; break; case 1: case 2: case 3: case 4: case 5: res += d; break; case 6: res += d - 1; break; case 7: res += d - 2; break; case 8: case 9: case 10: case 11: case 12: res += d - 2; break; case 13: res += d - 2 - 1; default: break; } return res; } static __attribute__((pure)) dt_bizda_t __bizda_fixup(dt_bizda_t d) { /* given dates like 2013-08-23b this returns 2013-08-22b */ int bdays; if (LIKELY(d.bd <= 20)) { /* every month has 20 business days */ ; } else if (UNLIKELY(d.m == 0 || d.m > GREG_MONTHS_P_YEAR)) { ; } else if (d.bd > (bdays = __get_bdays(d.y, d.m))) { d.bd = bdays; } return d; } static int __get_nwedays(int dur, dt_dow_t wd) { /* get the number of weekend days in a sequence of DUR days ending on WD * The minimum number of weekend days is simply 2 for every 7 days * to get the exact number observe the following: * * The number of remaining weekend days depends on the remaining number * of days and the DOW of the end point. * * here's the matrix, mod7 down, WD right: * S M T W R F A * 0 0 0 0 0 0 0 0 * 1 1 0 0 0 0 0 1 * 2 2 1 0 0 0 0 1 * 3 2 2 1 0 0 0 1 * 4 2 2 2 1 0 0 1 * 5 2 2 2 2 1 0 1 * 6 2 2 2 2 2 1 1 * * That means * (mod7 == 0) -> 0 * (WD == SAT) -> 1 * (mod7 > WD + 1) -> 2 * (mod7 > WD) -> 1 * * and that's all the magic behind the following code * * Note: If the number of weekend days in a sequence of DUR days starting on WD * (or, equivalently, -DUR days ending on WD before the start day) is sought * after, just use -DUR as input. * * Here's the table for the converse: * S M T W R F A * 0 0 0 0 0 0 0 0 * 1 1 0 0 0 0 1 2 * 2 1 0 0 0 1 2 2 * 3 1 0 0 1 2 2 2 * 4 1 0 1 2 2 2 2 * 5 1 1 2 2 2 2 2 * 6 1 2 2 2 2 2 2 * * mod7 == 0 -> 0 * wd == SUN -> 1 * (mod7 + wd >= 7) -> 2 * (mod7 + wd >= 6) -> 1 */ int nss = (dur / (signed)GREG_DAYS_P_WEEK) * 2; int mod = (dur % (signed)GREG_DAYS_P_WEEK); /* this algo still works with SUNDAY == 0 */ int xwd = wd < DT_SUNDAY ? wd : 0; if (mod == 0) { return nss; } else if (UNLIKELY(wd == DT_SATURDAY && dur > 0)) { return nss + 1; } else if (UNLIKELY(wd == DT_SATURDAY && dur < 0)) { return nss - 1; } else if (mod > xwd + 1) { return nss + 2; } else if (mod > xwd) { return nss + 1; } else if (mod + 7 <= xwd) { return nss - 2; } else if (mod + 6 <= xwd) { return nss - 1; } return nss; } static int __get_nbdays(int dur, dt_dow_t wd) { /* get the number of business days in a sequence of DUR days ending on WD * which is simply the number of days minus the number of weekend-days */ if (dur) { return dur - __get_nwedays(dur, wd); } return 0; } DEFUN unsigned int __get_bdays(unsigned int y, unsigned int m) { /* the 28th exists in every month, and it's exactly 20 bdays * away from the first, oh and it's -1 mod 7 * then to get the number of bdays remaining in the month * from the number of days remaining in the month R * we use a multiplication table, downwards the weekday of the * 28th, rightwards the days in excess of the 28th * Miracleday is only there to make the left hand side of the * multiplication 3 bits wide: * * r-> 0 1 2 3 * Sun 0 1 2 3 * Mon 0 1 2 3 * Tue 0 1 2 3 * Wed 0 1 2 2 * Thu 0 1 1 1 * Fri 0 0 0 1 * Sat 0 0 1 2 * Mir 0 0 0 0 */ unsigned int md = __get_mdays(y, m); unsigned int rd = (unsigned int)(md - 28U); dt_dow_t m01wd; dt_dow_t m28wd; /* rd should not overflow */ assert((signed int)md - 28 >= 0); /* wday of the 1st and 28th */ m01wd = __get_m01_wday(y, m); m28wd = (dt_dow_t)(m01wd - 1 ?: DT_SUNDAY); if (LIKELY(rd > 0)) { switch (m28wd) { case DT_SUNDAY: case DT_MONDAY: case DT_TUESDAY: return 20 + rd; case DT_WEDNESDAY: return 20 + rd - (rd == 3); case DT_THURSDAY: return 21; case DT_FRIDAY: return 20 + (rd == 3); case DT_SATURDAY: return 20 + rd - 1; case DT_MIRACLEDAY: default: abort(); } } return 20U; } #endif /* BIZDA_ASPECT_HELPERS_ */ #if defined ASPECT_GETTERS && !defined BIZDA_ASPECT_GETTERS_ #define BIZDA_ASPECT_GETTERS_ static unsigned int __bizda_get_mday(dt_bizda_t that) { dt_dow_t wd01; unsigned int res; /* find first of the month first */ wd01 = __get_m01_wday(that.y, that.m); switch (wd01) { case DT_MONDAY: case DT_TUESDAY: case DT_WEDNESDAY: case DT_THURSDAY: case DT_FRIDAY: res = 1; break; case DT_SATURDAY: wd01 = DT_MONDAY; res = 3; break; case DT_SUNDAY: wd01 = DT_MONDAY; res = 2; break; case DT_MIRACLEDAY: default: res = 0; break; } /* now just add up bdays */ { unsigned int wk; unsigned int nd; unsigned int b = that.bd; unsigned int magic = (b - 1 + wd01 - 1); assert(b + wd01 >= 2); wk = magic / DUWW_BDAYS_P_WEEK; nd = magic % DUWW_BDAYS_P_WEEK; res += wk * GREG_DAYS_P_WEEK + nd - wd01 + 1; } /* fixup mdays */ if (res > __get_mdays(that.y, that.m)) { res = 0; } return res; } static dt_dow_t __bizda_get_wday(dt_bizda_t that) { dt_dow_t wd01; unsigned int b; unsigned int magic; /* find first of the month first */ wd01 = __get_m01_wday(that.y, that.m); b = that.bd; magic = (b - 1 + (wd01 < DT_SUNDAY ? wd01 : 6) - 1); /* now just add up bdays */ return (dt_dow_t)((magic % DUWW_BDAYS_P_WEEK) + DT_MONDAY); } static unsigned int __bizda_get_count(dt_bizda_t that) { /* get N where N is the N-th occurrence of wday in the month of that year */ unsigned int bd = __get_bdays(that.y, that.m); if (UNLIKELY(that.bd + DUWW_BDAYS_P_WEEK > bd)) { return DUWW_BDAYS_P_WEEK; } return (that.bd - 1U) / DUWW_BDAYS_P_WEEK + 1U; } static unsigned int __bizda_get_yday(dt_bizda_t that, dt_bizda_param_t param) { /* return the N-th business day in Y, * the meaning of ultimo will be stretched to Y-ultimo, either last year's * or this year's, other reference points are not yet supported * * we use the following table (days beyond 20 bdays per month (across)): * Mon 3 0 2 1 3 1 2 3 0 3 2 1 * Mon 3 1 1 rest like Tue * Tue 3 0 1 2 3 0 3 2 1 3 1 2 * Tue 3 1 1 rest like Wed * Wed 3 0 1 2 2 1 3 1 2 3 0 3 * Wed 3 0 2 rest like Thu * Thu 2 0 2 2 1 2 3 1 2 2 1 3 * Thu 2 0 3 rest like Fri * Fri 1 0 3 2 1 2 2 2 2 1 2 3 * Fri 1 1 3 rest like Sat * Sat 1 0 3 1 2 2 1 3 2 1 2 2 * Sat 1 1 3 rest like Sun * Sun 2 0 3 0 3 2 1 3 1 2 2 1 * Sun 2 1 2 rest like Mon * */ struct __bdays_by_wday_s { unsigned int jan:2; unsigned int feb:2; unsigned int mar:2; unsigned int apr:2; unsigned int may:2; unsigned int jun:2; unsigned int jul:2; unsigned int aug:2; unsigned int sep:2; unsigned int oct:2; unsigned int nov:2; unsigned int dec:2; unsigned int feb_leap:2; unsigned int mar_leap:2; /* 4 bits left */ unsigned int flags:4; }; static struct __bdays_by_wday_s tbl[8U] = { { /* DT_MIRACLEDAY */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* DT_MONDAY */ 3, 0, 2, 1, 3, 1, 2, 3, 0, 3, 2, 1, 1, 1, 0 }, { /* DT_TUESDAY */ 3, 0, 1, 2, 3, 0, 3, 2, 1, 3, 1, 2, 1, 1, 0 }, { /* DT_WEDNESDAY */ 3, 0, 1, 2, 2, 1, 3, 1, 2, 3, 0, 3, 0, 2, 0 }, { /* DT_THURSDAY */ 2, 0, 2, 2, 1, 2, 3, 1, 2, 2, 1, 3, 0, 3, 0 }, { /* DT_FRIDAY */ 1, 0, 3, 2, 1, 2, 2, 2, 2, 1, 2, 3, 1, 3, 0 }, { /* DT_SATURDAY */ 1, 0, 3, 1, 2, 2, 1, 3, 2, 1, 2, 2, 1, 3, 0 }, { /* DT_SUNDAY */ 2, 0, 3, 0, 3, 2, 1, 3, 1, 2, 2, 1, 1, 2, 0 }, }; dt_dow_t j01wd; unsigned int y = that.y; unsigned int m = that.m; unsigned int accum = 0; if (UNLIKELY(param.ref != BIZDA_ULTIMO)) { return 0; } j01wd = __get_jan01_wday(that.y); if (LIKELY(!__leapp(y))) { union { uint32_t u; uint32_t lu:2; struct __bdays_by_wday_s s; } page = { .s = tbl[j01wd], }; for (unsigned int i = 0; i < m - 1; i++) { accum += page.lu; #if defined WORDS_BIGENDIAN page.u <<= 2; #else /* !WORDS_BIGENDIAN */ page.u >>= 2; #endif /* WORDS_BIGENDIAN */ } } else if (m > 1) { union { uint32_t u; uint32_t lu:2; struct __bdays_by_wday_s s; } page = { .s = tbl[j01wd], }; accum += page.lu; if (m > 2) { accum += page.s.feb_leap; } if (m > 3) { accum += page.s.mar_leap; } /* load a different page now, shift to the right month */ page.s = tbl[(j01wd < DT_SUNDAY ? j01wd : 0U) + DT_MONDAY]; #if defined WORDS_BIGENDIAN page.u <<= 6; #else /* !WORDS_BIGENDIAN */ page.u >>= 6; #endif /* WORDS_BIGENDIAN */ for (unsigned int i = 4; i < m; i++) { accum += page.lu; #if defined WORDS_BIGENDIAN page.u <<= 2; #else /* !WORDS_BIGENDIAN */ page.u >>= 2; #endif /* WORDS_BIGENDIAN */ } } return 20 * (m - 1) + accum + that.bd; } #endif /* BIZDA_ASPECT_GETTERS_ */ #if defined ASPECT_CONV && !defined BIZDA_ASPECT_CONV_ #define BIZDA_ASPECT_CONV_ static dt_ymd_t __bizda_to_ymd(dt_bizda_t d) { unsigned int tgtd = __bizda_get_mday(d); #if defined HAVE_ANON_STRUCTS_INIT return (dt_ymd_t){.y = d.y, .m = d.m, .d = tgtd}; #else /* !HAVE_ANON_STRUCTS_INIT */ dt_ymd_t res; res.y = d.y; res.m = d.m; res.d = tgtd; return res; #endif /* HAVE_ANON_STRUCTS_INIT */ } static dt_ywd_t __bizda_to_ywd(dt_bizda_t d, dt_bizda_param_t p) { unsigned int yd = __bizda_get_yday(d, p); return __make_ywd_ybd(d.y, yd); } static dt_ymcw_t __bizda_to_ymcw(dt_bizda_t d, dt_bizda_param_t UNUSED(p)) { unsigned int c = __bizda_get_count(d); dt_dow_t w = __bizda_get_wday(d); #if defined HAVE_ANON_STRUCTS_INIT return (dt_ymcw_t){.y = d.y, .m = d.m, .c = c, .w = w}; #else dt_ymcw_t res; res.y = d.y; res.m = d.m; res.c = c; res.w = w; return res; #endif } static dt_daisy_t __bizda_to_daisy(dt_bizda_t d, dt_bizda_param_t p) { dt_daisy_t res; unsigned int ybd; unsigned int wd; res = __jan00_daisy(d.y); wd = __daisy_get_wday(res); ybd = __bizda_get_yday(d, p); res += __get_d_equiv((dt_dow_t)wd, ybd); return res; } #endif /* ASPECT_CONV */ #if defined ASPECT_ADD && !defined BIZDA_ASPECT_ADD_ #define BIZDA_ASPECT_ADD_ static dt_bizda_t __bizda_fixup_b(unsigned int y, signed int m, signed int b) { dt_bizda_t res = {0}; if (LIKELY(b >= 1 && b <= 20)) { /* all months in our design range have at least 20 bdays */ ; } else if (b < 1) { int bdays; do { if (UNLIKELY(--m < 1)) { --y; m = GREG_MONTHS_P_YEAR; } bdays = __get_bdays(y, m); b += bdays; } while (b < 1); } else { int bdays; while (b > (bdays = __get_bdays(y, m))) { b -= bdays; if (UNLIKELY(++m > (signed int)GREG_MONTHS_P_YEAR)) { ++y; m = 1; } } } res.y = y; res.m = m; res.bd = b; return res; } static dt_bizda_t __bizda_add_b(dt_bizda_t d, int n) { /* add N business days to D */ int tgtb = d.bd + n; return __bizda_fixup_b(d.y, d.m, tgtb); } static dt_bizda_t __bizda_add_d(dt_bizda_t d, int n) { /* add N real days to D */ dt_dow_t wd = __bizda_get_wday(d); int tgtb = d.bd + __get_b_equiv(wd, n); return __bizda_fixup_b(d.y, d.m, tgtb); } static dt_bizda_t __bizda_add_w(dt_bizda_t d, int n) { /* add N weeks to D */ return __bizda_add_d(d, GREG_DAYS_P_WEEK * n); } static dt_bizda_t __bizda_add_m(dt_bizda_t d, int n) { /* add N months to D */ signed int tgtm = d.m + n; while (tgtm > (signed int)GREG_MONTHS_P_YEAR) { tgtm -= GREG_MONTHS_P_YEAR; ++d.y; } while (tgtm < 1) { tgtm += GREG_MONTHS_P_YEAR; --d.y; } /* final assignment */ d.m = tgtm; return __bizda_fixup(d); } static dt_bizda_t __bizda_add_y(dt_bizda_t d, int n) { /* add N years to D */ d.y += n; return __bizda_fixup(d); } #endif /* ASPECT_ADD */ #if defined ASPECT_STRF && !defined BIZDA_ASPECT_STRF_ #define BIZDA_ASPECT_STRF_ DEFUN void __prep_strfd_bizda(struct strpd_s *tgt, dt_bizda_t d, dt_bizda_param_t bp) { tgt->y = d.y; tgt->m = d.m; tgt->b = d.bd; if (LIKELY(bp.ab == BIZDA_AFTER)) { tgt->flags.ab = BIZDA_AFTER; } else { tgt->flags.ab = BIZDA_BEFORE; } tgt->flags.bizda = 1; return; } #endif /* ASPECT_STRF */ #undef ASPECT_BIZDA /* bizda.c ends here */ dateutils-0.3.1/lib/boops.h000066400000000000000000000146251241477753400156000ustar00rootroot00000000000000/*** boops.h -- byte-order operations * * Copyright (C) 2012-2014 Sebastian Freundt * Copyright (C) 2012 Ruediger Meier * * Author: Sebastian Freundt * * This file is part of uterus, dateutils and atem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***/ #if !defined INCLUDED_boops_h_ #define INCLUDED_boops_h_ #if defined HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ /* *bsd except for openbsd */ #if defined HAVE_SYS_ENDIAN_H # include #elif defined HAVE_MACHINE_ENDIAN_H # include #elif defined HAVE_ENDIAN_H # include #elif defined HAVE_BYTEORDER_H # include #endif /* SYS/ENDIAN_H || MACHINE/ENDIAN_H || ENDIAN_H || BYTEORDER_H */ /* check for byteswap to do the swapping ourselves if need be */ #if defined HAVE_BYTESWAP_H # include #endif /* BYTESWAP_H */ /* start off with opposite-endianness converters */ #if defined htooe16 /* yay, nothing to do really */ #elif defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ >= 7 # define htooe16(x) __builtin_bswap16(x) #elif defined __bswap_16 # define htooe16(x) __bswap_16(x) #elif defined __swap16 # define htooe16(x) __swap16(x) #elif defined WORDS_BIGENDIAN && defined le16toh # define htooe16(x) le16toh(x) #elif !defined WORDS_BIGENDIAN && defined be16toh # define htooe16(x) be16toh(x) #else # warning htooe16() will not convert anything # define htooe16(x) (x) #endif /* htooe16 */ #if !defined be16toh # if defined betoh16 # define be16toh betoh16 # elif defined WORDS_BIGENDIAN # define be16toh(x) (x) # else /* means we need swapping */ # define be16toh(x) htooe16(x) # endif /* betoh16 */ #endif /* !be16toh */ #if !defined le16toh # if defined letoh16 # define le16toh letoh16 # elif defined WORDS_BIGENDIAN # define le16toh(x) htooe16(x) # else /* no swapping needed */ # define le16toh(x) (x) # endif /* letoh16 */ #endif /* !le16toh */ #if !defined htobe16 # if defined WORDS_BIGENDIAN # define htobe16(x) (x) # else /* need swabbing */ # define htobe16(x) htooe16(x) # endif #endif /* !htobe16 */ #if !defined htole16 # if defined WORDS_BIGENDIAN # define htole16(x) htooe16(x) # else /* no byte swapping needed */ # define htole16(x) (x) # endif #endif /* !htole16 */ /* just to abstract over pure swapping */ #if defined htooe32 /* yay, nothing to do really */ #elif defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ >= 7 # define htooe32(x) __builtin_bswap32(x) #elif defined __bswap_32 # define htooe32(x) __bswap_32(x) #elif defined __swap32 # define htooe32(x) __swap32(x) #elif defined WORDS_BIGENDIAN && defined le32toh # define htooe32(x) le32toh(x) #elif !defined WORDS_BIGENDIAN && defined be32toh # define htooe32(x) be32toh(x) #else # warning htooe32() will not convert anything # define htooe32(x) (x) #endif /* and even now we may be out of luck */ #if !defined be32toh # if defined betoh32 # define be32toh betoh32 # elif defined WORDS_BIGENDIAN # define be32toh(x) (x) # else /* need some swaps */ # define be32toh(x) htooe32(x) # endif #endif /* !be32toh */ #if !defined le32toh # if defined letoh32 # define le32toh letoh32 # elif defined WORDS_BIGENDIAN # define le32toh(x) htooe32(x) # else /* no byte swapping here */ # define le32toh(x) (x) # endif /* letoh32 */ #endif /* !le32toh */ #if !defined htobe32 # if defined WORDS_BIGENDIAN # define htobe32(x) (x) # else /* yep, swap me about */ # define htobe32(x) htooe32(x) # endif #endif /* !be32toh */ #if !defined htole32 # if defined WORDS_BIGENDIAN # define htole32(x) htooe32(x) # else /* nothing to swap */ # define htole32(x) (x) # endif #endif /* !htole32 */ #if defined htooe64 /* yay, nothing to do really */ #elif defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ >= 7 # define htooe64(x) __builtin_bswap64(x) #elif defined __bswap_64 # define htooe64(x) __bswap_64(x) #elif defined __swap64 # define htooe64(x) __swap64(x) #elif defined WORDS_BIGENDIAN && defined le64toh # define htooe64(x) le64toh(x) #elif !defined WORDS_BIGENDIAN && defined be64toh # define htooe64(x) be64toh(x) #else # warning htooe64() will not convert anything # define htooe64(x) (x) #endif #if !defined be64toh # if defined betoh64 # define be64toh betoh64 # elif defined WORDS_BIGENDIAN # define be64toh(x) (x) # else /* swapping */ # define be64toh(x) htooe64(x) # endif #endif /* !be64toh */ #if !defined le64toh # if defined letoh64 # define le64toh letoh64 # elif defined WORDS_BIGENDIAN # define le64toh(x) htooe64(x) # else /* nothing to swap */ # define le64toh(x) (x) # endif #endif /* !le64toh */ #if !defined htobe64 # if defined WORDS_BIGENDIAN # define htobe64(x) (x) # else # define htobe64(x) htooe64(x) # endif #endif /* !htobe64 */ #if !defined htole64 # if defined WORDS_BIGENDIAN # define htole64(x) htooe64(x) # else /* no need swapping */ # define htole64(x) (x) # endif #endif /* !htole64 */ /* we could technically include byteswap.h and to the swap ourselves * in the missing cases. Instead we'll just leave it as is and wait * for bug reports. */ #endif /* INCLUDED_boops_h_ */ dateutils-0.3.1/lib/daisy.c000066400000000000000000000172441241477753400155620ustar00rootroot00000000000000/*** daisy.c -- guts for daisy dates * * Copyright (C) 2010-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ #define ASPECT_DAISY #include "nifty.h" #if !defined DEFUN # define DEFUN #endif /* !DEFUN */ #if !defined DAISY_ASPECT_HELPERS_ #define DAISY_ASPECT_HELPERS_ #define TO_BASE(x) ((x) - DT_DAISY_BASE_YEAR) #define TO_YEAR(x) ((x) + DT_DAISY_BASE_YEAR) static inline __attribute__((const, pure)) dt_daisy_t __jan00_daisy(unsigned int year) { /* daisy's base year is both 1 mod 4 and starts on a monday, so ... */ unsigned int by = TO_BASE(year); #if defined WITH_FAST_ARITH return by * 365U + by / 4U; #else /* !WITH_FAST_ARITH */ by = by * 365U + by / 4U; #if DT_DAISY_BASE_YEAR == 1917 if (UNLIKELY(year > 2100U)) { by -= (year - 2001U) / 100U; by += (year - 2001U) / 400U; } #elif DT_DAISY_BASE_YEAR == 1753 if (LIKELY(year > 1800U)) { by -= (year - 1701U) / 100U; by += (year - 1601U) / 400U; } #elif DT_DAISY_BASE_YEAR == 1601 by -= (year - 1601U) / 100U; by += (year - 1601U) / 400U; #endif return by; #endif /* WITH_FAST_ARITH */ } #endif /* DAISY_ASPECT_HELPERS_ */ #if defined ASPECT_GETTERS && !defined DAISY_ASPECT_GETTERS_ #define DAISY_ASPECT_GETTERS_ static __attribute__((const, pure)) dt_dow_t __daisy_get_wday(dt_daisy_t d) { /* daisy wdays are simple because the base year is chosen so that day 0 * in the daisy calendar is a sunday */ return (dt_dow_t)((d % GREG_DAYS_P_WEEK) ?: DT_SUNDAY); } static __attribute__((const, pure)) unsigned int __daisy_get_year(dt_daisy_t d) { /* given days since 1917-01-01 (Mon), compute a year */ unsigned int by; if (UNLIKELY(d == 0)) { return 0; } /* get an estimate for the year and readjust */ by = d / 365U; if (UNLIKELY(__jan00_daisy(TO_YEAR(by)) >= d)) { by--; #if !defined WITH_FAST_ARITH if (UNLIKELY(__jan00_daisy(TO_YEAR(by)) >= d)) { by--; } #endif /* WITH_FAST_ARITH */ } return TO_YEAR(by); } static __attribute__((const, pure)) unsigned int __daisy_get_yday(dt_daisy_t d) { dt_daisy_t j00; unsigned int y; if (UNLIKELY(d == 0)) { return 0U; } y = __daisy_get_year(d); j00 = __jan00_daisy(y); return d - j00; } #endif /* DAISY_ASPECT_GETTERS_ */ #if defined ASPECT_CONV && !defined DAISY_ASPECT_CONV_ #define DAISY_ASPECT_CONV_ #if DT_DAISY_BASE_YEAR == 1917 # define DT_LDN_BASE (122068U/*lilian's 1917-01-00*/) # define DT_JDN_BASE (2421228.5f/*julian's 1917-01-00*/) #elif DT_DAISY_BASE_YEAR == 1753 # define DT_LDN_BASE (62169U/*lilian's 1753-01-00*/) # define DT_JDN_BASE (2361329.5f/*julian's 1753-01-00*/) #elif DT_DAISY_BASE_YEAR == 1601 # define DT_LDN_BASE (6652U/*lilian's 1601-01-00*/) # define DT_JDN_BASE (2305812.5f/*julian's 1601-01-00*/) #else # error cannot convert to ldn, unknown base year #endif static __attribute__((const, pure)) dt_ldn_t __daisy_to_ldn(dt_daisy_t d) { return d + DT_LDN_BASE; } static __attribute__((const, pure)) dt_jdn_t __daisy_to_jdn(dt_daisy_t d) { return (dt_jdn_t)d + DT_JDN_BASE; } static __attribute__((const, pure)) dt_daisy_t __ldn_to_daisy(dt_ldn_t d) { dt_sdaisy_t tmp; if ((tmp = d - DT_LDN_BASE) > 0) { return (dt_daisy_t)tmp; } return 0U; } static __attribute__((const, pure)) dt_daisy_t __jdn_to_daisy(dt_jdn_t d) { float tmp; if ((tmp = d - DT_JDN_BASE) > 0.0f) { return (dt_daisy_t)tmp; } return 0U; } DEFUN __attribute__((const, pure)) dt_ymd_t __daisy_to_ymd(dt_daisy_t that) { dt_daisy_t j00; unsigned int doy; unsigned int y; struct __md_s md; if (UNLIKELY(that == 0)) { return (dt_ymd_t){.u = 0}; } y = __daisy_get_year(that); j00 = __jan00_daisy(y); doy = that - j00; md = __yday_get_md(y, doy); #if defined HAVE_ANON_STRUCTS_INIT return (dt_ymd_t){.y = y, .m = md.m, .d = md.d}; #else /* !HAVE_ANON_STRUCTS_INIT */ { dt_ymd_t res; res.y = y; res.m = md.m; res.d = md.d; return res; } #endif /* HAVE_ANON_STRUCTS_INIT */ } static __attribute__((const, pure)) dt_ymcw_t __daisy_to_ymcw(dt_daisy_t that) { dt_ymd_t tmp; unsigned int c; unsigned int w; if (UNLIKELY(that == 0)) { return (dt_ymcw_t){.u = 0}; } tmp = __daisy_to_ymd(that); c = __ymd_get_count(tmp); w = __daisy_get_wday(that); #if defined HAVE_ANON_STRUCTS_INIT return (dt_ymcw_t){.y = tmp.y, .m = tmp.m, .c = c, .w = w}; #else { dt_ymcw_t res; res.y = tmp.y; res.m = tmp.m; res.c = c; res.w = w; return res; } #endif } static __attribute__((const, pure)) dt_ywd_t __daisy_to_ywd(dt_daisy_t that) { const unsigned int wd = (that + GREG_DAYS_P_WEEK - 1) % GREG_DAYS_P_WEEK; dt_dow_t dow = (dt_dow_t)(wd + 1U); unsigned int y = __daisy_get_year(that); int yd = that - __jan00_daisy(y); return __make_ywd_yd_dow(y, yd, dow); } static __attribute__((const, pure)) dt_yd_t __daisy_to_yd(dt_daisy_t d) { int yd = __daisy_get_yday(d); unsigned int y = __daisy_get_year(d); #if defined HAVE_ANON_STRUCTS_INIT return (dt_yd_t){.y = y, .d = yd}; #else dt_yd_t res; res.y = y; res.d = yd; return res; #endif } #endif /* ASPECT_CONV */ #if defined ASPECT_ADD && !defined DAISY_ASPECT_ADD_ #define DAISY_ASPECT_ADD_ #define ASPECT_GETTERS #include "daisy.c" #undef ASPECT_GETTERS static __attribute__((const, pure)) dt_daisy_t __daisy_add_d(dt_daisy_t d, int n) { /* add N days to D */ d += n; return d; } static __attribute__((const, pure)) dt_daisy_t __daisy_add_b(dt_daisy_t d, int n) { /* add N business days to D */ dt_dow_t dow = __daisy_get_wday(d); int equ = __get_d_equiv(dow, n); d += equ; return d; } static __attribute__((const, pure)) dt_daisy_t __daisy_add_w(dt_daisy_t d, int n) { /* add N weeks to D */ return __daisy_add_d(d, GREG_DAYS_P_WEEK * n); } #endif /* ASPECT_ADD */ #if defined ASPECT_DIFF && !defined DAISY_ASPECT_DIFF_ #define DAISY_ASPECT_DIFF_ static __attribute__((const, pure)) struct dt_d_s __daisy_diff(dt_daisy_t d1, dt_daisy_t d2) { /* compute d2 - d1 */ struct dt_d_s res = {.typ = DT_DAISY, .dur = 1}; int32_t diff = d2 - d1; res.daisydur = diff; return res; } #endif /* ASPECT_DIFF */ #if defined ASPECT_STRF && !defined DAISY_ASPECT_STRF_ #define DAISY_ASPECT_STRF_ DEFUN void __prep_strfd_daisy(struct strpd_s *tgt, dt_daisy_t d) { dt_ymd_t tmp = __daisy_to_ymd(d); tgt->y = tmp.y; tgt->m = tmp.m; tgt->d = tmp.d; return; } #endif /* ASPECT_STRF */ /* daisy.c ends here */ dateutils-0.3.1/lib/date-core-private.h000066400000000000000000000047151241477753400177700ustar00rootroot00000000000000/*** date-core-private.h -- our universe of dates, private bits * * Copyright (C) 2011-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ /* private portion of date-core.h */ #if !defined INCLUDED_date_core_private_h_ #define INCLUDED_date_core_private_h_ #include "date-core.h" /* formatting defaults */ extern const char ymd_dflt[]; extern const char ymcw_dflt[]; extern const char ywd_dflt[]; extern const char yd_dflt[]; extern const char daisy_dflt[]; extern const char bizsi_dflt[]; extern const char bizda_dflt[]; extern const char ymddur_dflt[]; extern const char ymcwdur_dflt[]; extern const char ywddur_dflt[]; extern const char yddur_dflt[]; extern const char daisydur_dflt[]; extern const char bizsidur_dflt[]; extern const char bizdadur_dflt[]; extern dt_dtyp_t __trans_dfmt_special(const char*); extern dt_dtyp_t __trans_dfmt(const char **fmt); extern dt_dtyp_t __trans_ddurfmt(const char**fmt); #endif /* INCLUDED_date_core_private_h_ */ dateutils-0.3.1/lib/date-core-strpf.c000066400000000000000000000413441241477753400174460ustar00rootroot00000000000000/*** date-core-strpf.c -- parser and formatter funs for date-core * * Copyright (C) 2011-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ /* implementation part of date-core-strpf.h */ #if !defined INCLUDED_date_core_strpf_c_ #define INCLUDED_date_core_strpf_c_ #if defined HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include "strops.h" #include "token.h" #include "date-core.h" #include "date-core-strpf.h" #if defined __INTEL_COMPILER /* we MUST return a char* */ # pragma warning (disable:2203) #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wcast-qual" #endif /* __INTEL_COMPILER */ #if !defined DEFUN # define DEFUN #endif /* !DEFUN */ #if !defined DEFVAR # define DEFVAR #endif /* !DEFVAR */ static const char *__long_wday[] = { "Miracleday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", }; DEFVAR const char **dut_long_wday = __long_wday; DEFVAR const ssize_t dut_nlong_wday = countof(__long_wday); static const char *__abbr_wday[] = { "Mir", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", }; DEFVAR const char **dut_abbr_wday = __abbr_wday; DEFVAR const ssize_t dut_nabbr_wday = countof(__abbr_wday); static const char __abab_wday[] = "XMTWRFAS"; DEFVAR const char *dut_abab_wday = __abab_wday; DEFVAR const ssize_t dut_nabab_wday = countof(__abab_wday); static const char *__long_mon[] = { "Miraculary", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", }; DEFVAR const char **dut_long_mon = __long_mon; DEFVAR const ssize_t dut_nlong_mon = countof(__long_mon); static const char *__abbr_mon[] = { "Mir", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; DEFVAR const char **dut_abbr_mon = __abbr_mon; DEFVAR const ssize_t dut_nabbr_mon = countof(__abbr_mon); /* futures expiry codes, how convenient */ static const char __abab_mon[] = "_FGHJKMNQUVXZ"; DEFVAR const char *dut_abab_mon = __abab_mon; DEFVAR const ssize_t dut_nabab_mon = countof(__abab_mon); DEFUN inline void __fill_strpdi(struct strpdi_s *tgt, struct dt_d_s dur) { switch (dur.typ) { case DT_YMD: tgt->y = dur.ymd.y; tgt->m = dur.ymd.m; tgt->d = dur.ymd.d; break; case DT_DAISY: tgt->d = dur.daisydur; /* we don't need the negation, so return here */ return; case DT_BIZSI: tgt->b = dur.bizsidur; /* we don't need the negation, so return here */ return; case DT_BIZDA: tgt->y = dur.bizda.y; tgt->m = dur.bizda.m; tgt->b = dur.bizda.bd; break; case DT_YMCW: tgt->y = dur.ymcw.y; tgt->m = dur.ymcw.m; tgt->w = dur.ymcw.c; tgt->d = dur.ymcw.w; break; case DT_MD: tgt->m = dur.md.m; tgt->d = dur.md.d; break; default: break; } if (UNLIKELY(dur.neg)) { tgt->y = -tgt->y; tgt->m = -tgt->m; tgt->d = -tgt->d; tgt->w = -tgt->w; tgt->b = -tgt->b; } return; } DEFUN struct dt_d_s __strpd_std(const char *str, char **ep) { /* code dupe, see __strpdt_std() */ struct dt_d_s res = dt_d_initialiser(); struct strpd_s d; const char *sp; if ((sp = str) == NULL) { goto out; } d = strpd_initialiser(); /* read the year */ if ((d.y = strtoi_lim(sp, &sp, DT_MIN_YEAR, DT_MAX_YEAR)) < 0 || *sp++ != '-') { goto fucked; } /* check for ywd dates */ if (UNLIKELY(*sp == 'W')) { /* brilliant */ if ((sp++, d.c = strtoi_lim(sp, &sp, 0, 53)) < 0 || *sp++ != '-') { goto fucked; } d.flags.c_wcnt_p = 1; d.flags.wk_cnt = YWD_ISOWK_CNT; goto dow; } /* read the month */ if ((d.m = strtoi_lim(sp, &sp, 0, GREG_MONTHS_P_YEAR)) < 0 || *sp++ != '-') { goto fucked; } /* read the day or the count */ if ((d.d = strtoi_lim(sp, &sp, 0, 31)) < 0) { /* didn't work, fuck off */ goto fucked; } /* check the date type */ switch (*sp) { case '-': /* it is a YMCW date */ if ((d.c = d.d) > 5) { /* nope, it was bollocks */ break; } d.d = 0; sp++; dow: if ((d.w = strtoi_lim(sp, &sp, 0, GREG_DAYS_P_WEEK)) < 0) { /* didn't work, fuck off */ goto fucked; } /* fix up d.w right away */ d.w = d.w ?: DT_SUNDAY; break; case 'B': /* it's a bizda/YMDU before ultimo date */ d.flags.ab = BIZDA_BEFORE; case 'b': /* it's a bizda/YMDU after ultimo date */ d.flags.bizda = 1; d.b = d.d; d.d = 0; sp++; break; default: /* we don't care */ break; } /* guess what we're doing */ res = __guess_dtyp(d); out: if (ep != NULL) { *ep = (char*)sp; } return res; fucked: if (ep != NULL) { *ep = (char*)str; } return dt_d_initialiser(); } DEFUN int __strpd_card(struct strpd_s *d, const char *sp, struct dt_spec_s s, char **ep) { /* we're really pessimistic, aren't we? */ int res = -1; switch (s.spfl) { default: case DT_SPFL_UNK: break; case DT_SPFL_N_DSTD: d->y = strtoi_lim(sp, &sp, DT_MIN_YEAR, DT_MAX_YEAR); sp++; d->m = strtoi_lim(sp, &sp, 0, GREG_MONTHS_P_YEAR); sp++; d->d = strtoi_lim(sp, &sp, 0, 31); res = 0 - (d->y < 0 || d->m < 0 || d->d < 0); break; case DT_SPFL_N_YEAR: if (s.abbr == DT_SPMOD_NORM) { d->y = strtoi_lim(sp, &sp, DT_MIN_YEAR, DT_MAX_YEAR); } else if (s.abbr == DT_SPMOD_ABBR) { d->y = strtoi_lim(sp, &sp, 0, 99); if (UNLIKELY(d->y < 0)) { ; } else if ((d->y += 2000) > 2068) { d->y -= 100; } } res = 0 - (d->y < 0); break; case DT_SPFL_N_MON: d->m = strtoi_lim(sp, &sp, 0, GREG_MONTHS_P_YEAR); res = 0 - (d->m < 0); break; case DT_SPFL_N_DCNT_MON: /* ymd mode? */ if (LIKELY(!s.bizda)) { d->d = strtoi_lim(sp, &sp, 0, 31); res = 0 - (d->d < 0); } else { d->b = strtoi_lim(sp, &sp, 0, 23); res = 0 - (d->b < 0); } break; case DT_SPFL_N_DCNT_WEEK: /* ymcw mode? */ d->w = strtoi_lim(sp, &sp, 0, GREG_DAYS_P_WEEK); /* fix up d->w right away */ d->w = d->w ?: DT_SUNDAY; res = 0 - (d->w < 0); break; case DT_SPFL_N_WCNT_MON: /* ymcw mode? */ d->c = strtoi_lim(sp, &sp, 0, 5); res = 0 - (d->c < 0); break; case DT_SPFL_S_WDAY: /* ymcw mode? */ switch (s.abbr) { case DT_SPMOD_NORM: d->w = strtoarri( sp, &sp, dut_abbr_wday, dut_nabbr_wday); break; case DT_SPMOD_LONG: d->w = strtoarri( sp, &sp, dut_long_wday, dut_nlong_wday); break; case DT_SPMOD_ABBR: { const char *pos; if ((pos = strchr(dut_abab_wday, *sp++)) != NULL) { d->w = pos - dut_abab_wday; } else { d->w = -1; } break; } case DT_SPMOD_ILL: default: break; } res = 0 - (d->w < 0); break; case DT_SPFL_S_MON: switch (s.abbr) { case DT_SPMOD_NORM: d->m = strtoarri( sp, &sp, dut_abbr_mon, dut_nabbr_mon); break; case DT_SPMOD_LONG: d->m = strtoarri( sp, &sp, dut_long_mon, dut_nlong_mon); break; case DT_SPMOD_ABBR: { const char *pos; if ((pos = strchr(dut_abab_mon, *sp++)) != NULL) { d->m = pos - dut_abab_mon; } else { d->m = -1; } break; } case DT_SPMOD_ILL: default: break; } res = 0 - (d->m < 0); break; case DT_SPFL_S_QTR: if (*sp++ != 'Q') { break; } case DT_SPFL_N_QTR: if (d->m == 0) { int q; if ((q = strtoi_lim(sp, &sp, 1, 4)) >= 0) { d->m = q * 3 - 2; res = 0; } } break; case DT_SPFL_LIT_PERCENT: if (*sp++ == '%') { res = 0; } break; case DT_SPFL_LIT_TAB: if (*sp++ == '\t') { res = 0; } break; case DT_SPFL_LIT_NL: if (*sp++ == '\n') { res = 0; } break; case DT_SPFL_N_DCNT_YEAR: /* was %D and %j, cannot be used at the moment */ if ((d->d = strtoi_lim(sp, &sp, 1, 366)) >= 0) { res = 0; d->flags.d_dcnt_p = 1; } break; case DT_SPFL_N_WCNT_YEAR: /* was %C, cannot be used at the moment */ d->c = strtoi_lim(sp, &sp, 0, 53); d->flags.wk_cnt = s.wk_cnt; /* let everyone know d->c has a week-count in there */ d->flags.c_wcnt_p = 1; res = 0; break; } /* assign end pointer */ if (ep != NULL) { *ep = (char*)sp; } return res; } DEFUN int __strpd_rom(struct strpd_s *d, const char *sp, struct dt_spec_s s, char **ep) { int res = -1; switch (s.spfl) { default: case DT_SPFL_UNK: break; case DT_SPFL_N_YEAR: if (s.abbr == DT_SPMOD_NORM) { d->y = romstrtoi_lim( sp, &sp, DT_MIN_YEAR, DT_MAX_YEAR); } else if (s.abbr == DT_SPMOD_ABBR) { d->y = romstrtoi_lim(sp, &sp, 0, 99); if (UNLIKELY(d->y < 0)) { ; } else if ((d->y += 2000) > 2068) { d->y -= 100; } } res = 0 - (d->y < 0); break; case DT_SPFL_N_MON: d->m = romstrtoi_lim(sp, &sp, 0, GREG_MONTHS_P_YEAR); res = 0 - (d->m < 0); break; case DT_SPFL_N_DCNT_MON: d->d = romstrtoi_lim(sp, &sp, 0, 31); res = 0 - (d->d < 0); break; case DT_SPFL_N_WCNT_MON: d->c = romstrtoi_lim(sp, &sp, 0, 5); res = 0 - (d->c < 0); break; } if (ep != NULL) { *ep = (char*)sp; } return res; } #if defined __INTEL_COMPILER /* we MUST return a char* */ # pragma warning (default:2203) #elif defined __GNUC__ # pragma GCC diagnostic warning "-Wcast-qual" #endif /* __INTEL_COMPILER */ static void __strfd_get_md(struct strpd_s *d, struct dt_d_s this) { struct __md_s both = dt_get_md(this); d->m = both.m; d->d = both.d; return; } static void __strfd_get_m(struct strpd_s *d, struct dt_d_s this) { d->m = dt_get_mon(this); return; } static void __strfd_get_d(struct strpd_s *d, struct dt_d_s this) { d->d = dt_get_mday(this); return; } DEFUN size_t __strfd_card( char *buf, size_t bsz, struct dt_spec_s s, struct strpd_s *d, struct dt_d_s that) { size_t res = 0; switch (s.spfl) { default: case DT_SPFL_UNK: break; case DT_SPFL_N_DSTD: if (UNLIKELY(!d->m && !d->d)) { __strfd_get_md(d, that); } else if (UNLIKELY(!d->d)) { __strfd_get_d(d, that); } if (LIKELY(bsz >= 10)) { ui32tostr(buf + 0, bsz, d->y, 4); buf[4] = '-'; res = ui32tostr(buf + 5, bsz, d->m, 2); buf[7] = '-'; ui32tostr(buf + 8, bsz, d->d, 2); res = 10; } break; case DT_SPFL_N_YEAR: { unsigned int y = d->y; int prec = 4; if (UNLIKELY(s.tai && d->flags.real_y_in_q)) { y = d->q; } if (UNLIKELY(s.abbr == DT_SPMOD_ABBR)) { prec = 2; } res = ui32tostr(buf, bsz, y, prec); break; } case DT_SPFL_N_MON: if (UNLIKELY(!d->m && !d->d)) { __strfd_get_md(d, that); } else if (UNLIKELY(!d->m)) { __strfd_get_m(d, that); } res = ui32tostr(buf, bsz, d->m, 2); break; case DT_SPFL_N_DCNT_MON: { /* ymd mode check? */ unsigned int pd; if (LIKELY(!s.bizda)) { if (UNLIKELY(!d->m && !d->d)) { __strfd_get_md(d, that); } else if (UNLIKELY(!d->d)) { __strfd_get_d(d, that); pd = d->d; } pd = d->d; } else { /* must be bizda now */ pd = dt_get_bday_q( that, __make_bizda_param(s.ab, BIZDA_ULTIMO)); } res = ui32tostr(buf, bsz, pd, 2); break; } case DT_SPFL_N_DCNT_WEEK: /* ymcw mode check */ with (unsigned int w = d->w ?: dt_get_wday(that)) { if (w == DT_SUNDAY && s.wk_cnt != YWD_MONWK_CNT) { /* turn Sun 07 to Sun 00 */ w = 0; } res = ui32tostr(buf, bsz, w, 2); } break; case DT_SPFL_N_WCNT_MON: { unsigned int c = d->c; /* ymcw mode check? */ if (!c || that.typ == DT_YWD) { /* don't store it */ c = (unsigned int)dt_get_wcnt_mon(that); } res = ui32tostr(buf, bsz, c, 2); break; } case DT_SPFL_S_WDAY: /* get the weekday in ymd mode!! */ d->w = d->w ? (dt_dow_t)d->w : dt_get_wday(that); switch (s.abbr) { case DT_SPMOD_NORM: res = arritostr( buf, bsz, d->w, dut_abbr_wday, dut_nabbr_wday); break; case DT_SPMOD_LONG: res = arritostr( buf, bsz, d->w, dut_long_wday, dut_nlong_wday); break; case DT_SPMOD_ABBR: /* super abbrev'd wday */ if (d->w < dut_nabab_wday) { buf[res++] = dut_abab_wday[d->w]; } break; case DT_SPMOD_ILL: default: break; } break; case DT_SPFL_S_MON: switch (s.abbr) { case DT_SPMOD_NORM: res = arritostr( buf, bsz, d->m, dut_abbr_mon, dut_nabbr_mon); break; case DT_SPMOD_LONG: res = arritostr( buf, bsz, d->m, dut_long_mon, dut_nlong_mon); break; case DT_SPMOD_ABBR: /* super abbrev'd month */ if (d->m < dut_nabab_mon) { buf[res++] = dut_abab_mon[d->m]; } break; case DT_SPMOD_ILL: default: break; } break; case DT_SPFL_S_QTR: buf[res++] = 'Q'; buf[res++] = (char)(dt_get_quarter(that) + '0'); break; case DT_SPFL_N_QTR: buf[res++] = '0'; buf[res++] = (char)(dt_get_quarter(that) + '0'); break; case DT_SPFL_LIT_PERCENT: /* literal % */ buf[res++] = '%'; break; case DT_SPFL_LIT_TAB: /* literal tab */ buf[res++] = '\t'; break; case DT_SPFL_LIT_NL: /* literal \n */ buf[res++] = '\n'; break; case DT_SPFL_N_DCNT_YEAR: switch (that.typ) { case DT_YMD: case DT_BIZDA: { /* %j */ int yd; if (LIKELY(!s.bizda)) { yd = __ymd_get_yday(that.ymd); } else { yd = __bizda_get_yday( that.bizda, __get_bizda_param(that)); } if (yd >= 0) { res = ui32tostr(buf, bsz, yd, 3); } else { buf[res++] = '0'; buf[res++] = '0'; buf[res++] = '0'; } break; } case DT_LDN: res = snprintf(buf, bsz, "%u", that.ldn); break; case DT_JDN: res = snprintf(buf, bsz, "%.6f", that.jdn); break; default: break; } break; case DT_SPFL_N_WCNT_YEAR: { int yw = dt_get_wcnt_year(that, s.wk_cnt); res = ui32tostr(buf, bsz, yw, 2); break; } } return res; } DEFUN size_t __strfd_rom( char *buf, size_t bsz, struct dt_spec_s s, struct strpd_s *d, struct dt_d_s that) { size_t res = 0; if (that.typ != DT_YMD) { /* not supported for non-ymds */ return res; } switch (s.spfl) { default: case DT_SPFL_UNK: break; case DT_SPFL_N_YEAR: if (s.abbr == DT_SPMOD_NORM) { res = ui32tostrrom(buf, bsz, d->y); break; } else if (s.abbr == DT_SPMOD_ABBR) { res = ui32tostrrom(buf, bsz, d->y % 100); break; } break; case DT_SPFL_N_MON: res = ui32tostrrom(buf, bsz, d->m); break; case DT_SPFL_N_DCNT_MON: res = ui32tostrrom(buf, bsz, d->d); break; case DT_SPFL_N_WCNT_MON: { unsigned int c = d->c; if (!c) { /* don't store the result */ c = (unsigned int)dt_get_wcnt_mon(that); } res = ui32tostrrom(buf, bsz, c); break; } } return res; } DEFUN size_t __strfd_dur( char *buf, size_t bsz, struct dt_spec_s s, struct strpd_s *d, struct dt_d_s UNUSED(that)) { size_t res = 0; switch (s.spfl) { default: case DT_SPFL_UNK: break; case DT_SPFL_N_DSTD: case DT_SPFL_N_DCNT_MON: res = snprintf(buf, bsz, "%d", d->sd); break; case DT_SPFL_N_YEAR: if (!d->y) { /* fill in for a mo, hack hack hack * we'll think about the consequences later */ d->y = __uidiv(d->m, GREG_MONTHS_P_YEAR); d->m = __uimod(d->m, GREG_MONTHS_P_YEAR); } res = snprintf(buf, bsz, "%d", d->y); break; case DT_SPFL_N_MON: res = snprintf(buf, bsz, "%d", d->m); break; case DT_SPFL_N_DCNT_WEEK: if (!d->w) { /* hack hack hack * we'll think about the consequences later */ d->w = __uidiv(d->d, GREG_DAYS_P_WEEK); d->d = __uimod(d->d, GREG_DAYS_P_WEEK); } res = snprintf(buf, bsz, "%d", d->w); break; case DT_SPFL_N_WCNT_MON: res = snprintf(buf, bsz, "%d", d->c); break; case DT_SPFL_S_WDAY: case DT_SPFL_S_MON: case DT_SPFL_S_QTR: case DT_SPFL_N_QTR: case DT_SPFL_N_DCNT_YEAR: case DT_SPFL_N_WCNT_YEAR: break; case DT_SPFL_LIT_PERCENT: /* literal % */ buf[res++] = '%'; break; case DT_SPFL_LIT_TAB: /* literal tab */ buf[res++] = '\t'; break; case DT_SPFL_LIT_NL: /* literal \n */ buf[res++] = '\n'; break; } return res; } #endif /* INCLUDED_date_core_strpf_c_ */ dateutils-0.3.1/lib/date-core-strpf.h000066400000000000000000000120321241477753400174430ustar00rootroot00000000000000/*** date-core-strpf.h -- parser and formatter funs for date-core * * Copyright (C) 2011-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ #if !defined INCLUDED_date_core_strpf_h_ #define INCLUDED_date_core_strpf_h_ #if defined __cplusplus extern "C" { #endif /* __cplusplus */ struct strpd_s { signed int y; signed int m; union { signed int d; signed int sd; }; signed int c; signed int w; /* general flags */ union { unsigned int u; struct { unsigned int ab:1; unsigned int bizda:1; unsigned int d_dcnt_p:1; unsigned int c_wcnt_p:1; unsigned int wk_cnt:2;/*%C,%W,%U,%V*/ unsigned int real_y_in_q:1; }; } flags; signed int b; signed int q; }; struct strpdi_s { signed int y; signed int m; signed int d; signed int w; signed int b; }; /* helpers */ static inline __attribute__((pure, const)) struct strpd_s strpd_initialiser(void) { #if defined HAVE_SLOPPY_STRUCTS_INIT static const struct strpd_s res = {}; #else static const struct strpd_s res; #endif /* HAVE_SLOPPY_STRUCTS_INIT */ return res; } static inline __attribute__((pure, const)) struct strpdi_s strpdi_initialiser(void) { #if defined HAVE_SLOPPY_STRUCTS_INIT static const struct strpdi_s res = {}; #else static const struct strpdi_s res; #endif /* HAVE_SLOPPY_STRUCTS_INIT */ return res; } /* textual representations of parts of the date */ /** * Long weekday names, english only. * Monday, Tuesday, ... */ extern const char **dut_long_wday; extern const ssize_t dut_nlong_wday; /** * Abbrev'd weekday names, english only. * Mon, Tue, ... */ extern const char **dut_abbr_wday; extern const ssize_t dut_nabbr_wday; /** * Even-more-abbrev'd weekday names, english only. * M, T, W, ... */ extern const char *dut_abab_wday; extern const ssize_t dut_nabab_wday; /** * Long month names, english only. * January, February, ... */ extern const char **dut_long_mon; extern const ssize_t dut_nlong_mon; /** * Abbrev'd month names, english only. * Jan, Feb, ... */ extern const char **dut_abbr_mon; extern const ssize_t dut_nabbr_mon; /** * Even-more-abbrev'd month names. * F, G, H, ... */ extern const char *dut_abab_mon; extern const ssize_t dut_nabab_mon; #if defined INCLUDED_date_core_h_ /** * Populate TGT with duration information from DUR. */ extern inline void __fill_strpdi(struct strpdi_s *tgt, struct dt_d_s dur); /** * Parse STR with the standard parser, put the end of the parsed string in EP.*/ extern struct dt_d_s __strpd_std(const char *str, char **ep); /** * Given a strpd object D, try to construct a dt_d object. * Defined in date-core.c */ extern struct dt_d_s __guess_dtyp(struct strpd_s d); #endif /* INCLUDED_date_core_h_ */ /* self-explanatory funs, innit? */ extern int __strpd_card(struct strpd_s *d, const char *sp, struct dt_spec_s s, char **ep); extern int __strpd_rom(struct strpd_s *d, const char *sp, struct dt_spec_s s, char **ep); extern size_t __strfd_card( char *buf, size_t bsz, struct dt_spec_s s, struct strpd_s *d, struct dt_d_s that); extern size_t __strfd_rom( char *buf, size_t bsz, struct dt_spec_s s, struct strpd_s *d, struct dt_d_s that); extern size_t __strfd_dur( char *buf, size_t bsz, struct dt_spec_s s, struct strpd_s *d, struct dt_d_s that); /* specific formatters and parsers */ extern void __prep_strfd_ywd(struct strpd_s *tgt, dt_ywd_t d); extern void __prep_strfd_daisy(struct strpd_s *tgt, dt_daisy_t d); extern void __prep_strfd_bizda(struct strpd_s *tgt, dt_bizda_t d, dt_bizda_param_t bp); #if defined __cplusplus } #endif /* __cplusplus */ #endif /* INCLUDED_date_core_strpf_h_ */ dateutils-0.3.1/lib/date-core.c000066400000000000000000001034141241477753400163070ustar00rootroot00000000000000/*** date-core.c -- our universe of dates * * Copyright (C) 2011-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ /* implementation part of date-core.h */ #if !defined INCLUDED_date_core_c_ #define INCLUDED_date_core_c_ #if defined HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include "date-core.h" #include "date-core-private.h" #include "strops.h" #include "token.h" #include "nifty.h" /* parsers and formatters */ #include "date-core-strpf.h" #if defined __INTEL_COMPILER /* we MUST return a char* */ # pragma warning (disable:2203) #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wcast-qual" #endif /* __INTEL_COMPILER */ #if !defined DEFUN # define DEFUN #endif /* !DEFUN */ #if !defined DEFVAR # define DEFVAR #endif /* !DEFVAR */ #if !defined assert # define assert(x) #endif /* !assert */ /* weekdays of the first day of the year, * 3 bits per year, times 10 years makes 1 uint32_t */ typedef struct { #define __JAN01_Y_PER_B (10) unsigned int y0:3; unsigned int y1:3; unsigned int y2:3; unsigned int y3:3; unsigned int y4:3; unsigned int y5:3; unsigned int y6:3; unsigned int y7:3; unsigned int y8:3; unsigned int y9:3; /* 2 bits left */ unsigned int rest:2; } __jan01_wday_block_t; struct __md_s { unsigned int m; unsigned int d; }; /* helpers */ #include "gmtime.h" /* bizda definitions, reference dates */ static __attribute__((unused)) const char *bizda_ult[] = {"ultimo", "ult"}; /* arithmetics helpers */ static inline unsigned int __uimod(signed int x, signed int m) { int res = x % m; return res >= 0 ? res : res + m; } static inline unsigned int __uidiv(signed int x, signed int m) { /* uidiv expects its counterpart (the mod) to be computed with __uimod */ int res = x / m; return x >= 0 ? res : x % m ? res - 1 : res; } /* helpers from the calendar files, don't define any aspect, so only * the helpers should get included */ #include "yd.c" #include "ymd.c" #include "ymcw.c" #include "ywd.c" #include "bizda.c" #include "daisy.c" #define ASPECT_GETTERS #include "yd.c" #include "ymd.c" #include "ymcw.c" #include "ywd.c" #include "bizda.c" #include "daisy.c" #undef ASPECT_GETTERS #define ASPECT_CONV #include "yd.c" #include "ymd.c" #include "ymcw.c" #include "ywd.c" #include "bizda.c" #include "daisy.c" #undef ASPECT_CONV /* converting accessors */ DEFUN int dt_get_year(struct dt_d_s that) { switch (that.typ) { case DT_YMD: return that.ymd.y; case DT_YMCW: return that.ymcw.y; case DT_DAISY: return __daisy_to_ymd(that.daisy).y; case DT_BIZDA: return that.bizda.y; default: case DT_DUNK: return 0; } } DEFUN int dt_get_mon(struct dt_d_s that) { switch (that.typ) { case DT_YMD: return that.ymd.m; case DT_YMCW: return that.ymcw.m; case DT_DAISY: return __daisy_to_ymd(that.daisy).m; case DT_BIZDA: return that.bizda.m; case DT_YWD: return __ywd_get_mon(that.ywd); default: case DT_DUNK: return 0; } } DEFUN dt_dow_t dt_get_wday(struct dt_d_s that) { switch (that.typ) { case DT_YMD: return __ymd_get_wday(that.ymd); case DT_YMCW: return __ymcw_get_wday(that.ymcw); case DT_DAISY: return __daisy_get_wday(that.daisy); case DT_BIZDA: return __bizda_get_wday(that.bizda); case DT_YWD: return __ywd_get_wday(that.ywd); default: case DT_DUNK: return DT_MIRACLEDAY; } } DEFUN int dt_get_mday(struct dt_d_s that) { if (LIKELY(that.typ == DT_YMD)) { return that.ymd.d; } switch (that.typ) { case DT_YMCW: return __ymcw_get_mday(that.ymcw); case DT_DAISY: return __daisy_to_ymd(that.daisy).d; case DT_BIZDA: return __bizda_get_mday(that.bizda);; case DT_YMD: /* to shut gcc up */ default: case DT_DUNK: return 0; } } static struct __md_s dt_get_md(struct dt_d_s that) { switch (that.typ) { default: return (struct __md_s){.m = 0, .d = 0}; case DT_YMD: return (struct __md_s){.m = that.ymd.m, .d = that.ymd.d}; case DT_YMCW: { unsigned int d = __ymcw_get_mday(that.ymcw); return (struct __md_s){.m = that.ymcw.m, .d = d}; } case DT_YWD: /* should have come throught the GETTERS aspect */ return __ywd_get_md(that.ywd); } } /* too exotic to be public */ static int dt_get_wcnt_mon(struct dt_d_s that) { if (LIKELY(that.typ == DT_YMCW)) { return that.ymcw.c; } switch (that.typ) { case DT_YMD: return __ymd_get_count(that.ymd); case DT_DAISY: return __ymd_get_count(__daisy_to_ymd(that.daisy)); case DT_BIZDA: return __bizda_get_count(that.bizda); case DT_YMCW: /* to shut gcc up */ case DT_YWD: return __ywd_get_wcnt_mon(that.ywd); default: case DT_DUNK: return 0; } } /* forward decl */ static dt_yd_t dt_conv_to_yd(struct dt_d_s this); DEFUN int dt_get_wcnt_year(struct dt_d_s this, unsigned int wkcnt_convention) { int res; switch (this.typ) { case DT_YMD: case DT_DAISY: case DT_YD: { dt_yd_t yd = dt_conv_to_yd(this); switch (wkcnt_convention) { default: case YWD_ABSWK_CNT: res = __yd_get_wcnt_abs(yd); break; case YWD_ISOWK_CNT: res = __yd_get_wcnt_iso(yd); break; case YWD_MONWK_CNT: case YWD_SUNWK_CNT: { /* using monwk_cnt is a minor trick * from = 1 = Mon or 0 = Sun */ dt_dow_t from; switch (wkcnt_convention) { case YWD_MONWK_CNT: from = DT_MONDAY; break; case YWD_SUNWK_CNT: from = DT_SUNDAY; break; default: /* huh? */ from = DT_MIRACLEDAY; break; } res = __yd_get_wcnt(yd, from); break; } } break; } case DT_YMCW: res = __ymcw_get_yday(this.ymcw); break; case DT_YWD: res = __ywd_get_wcnt_year(this.ywd, wkcnt_convention); break; default: res = 0; break; } return res; } DEFUN unsigned int dt_get_yday(struct dt_d_s that) { switch (that.typ) { case DT_YMD: return __ymd_get_yday(that.ymd); case DT_YMCW: return __ymcw_get_yday(that.ymcw); case DT_DAISY: return __daisy_get_yday(that.daisy); case DT_BIZDA: return __bizda_get_yday(that.bizda, __get_bizda_param(that)); case DT_YWD: return __ywd_get_yday(that.ywd); default: case DT_DUNK: return 0; } } DEFUN int dt_get_bday(struct dt_d_s that) { /* get N where N is the N-th business day after ultimo */ switch (that.typ) { case DT_BIZDA: { dt_bizda_param_t p = __get_bizda_param(that); if (p.ab == BIZDA_AFTER && p.ref == BIZDA_ULTIMO) { return that.bizda.bd; } else if (p.ab == BIZDA_BEFORE && p.ref == BIZDA_ULTIMO) { int mb = __get_bdays(that.bizda.y, that.bizda.m); return mb - that.bizda.bd; } return 0; } case DT_DAISY: that.ymd = __daisy_to_ymd(that.daisy); case DT_YMD: return __ymd_get_bday( that.ymd, __make_bizda_param(BIZDA_AFTER, BIZDA_ULTIMO)); case DT_YMCW: return __ymcw_get_bday( that.ymcw, __make_bizda_param(BIZDA_AFTER, BIZDA_ULTIMO)); default: case DT_DUNK: return 0; } } DEFUN int dt_get_bday_q(struct dt_d_s that, dt_bizda_param_t bp) { /* get N where N is the N-th business day Before/After REF */ switch (that.typ) { case DT_BIZDA: { dt_bizda_param_t thatp = __get_bizda_param(that); if (UNLIKELY(thatp.ref != bp.ref)) { ; } else if (thatp.ab == bp.ab) { return that.bizda.bd; } else { int mb = __get_bdays(that.bizda.y, that.bizda.m); return mb - that.bizda.bd; } return 0/*__bizda_to_bizda(that.bizda, ba, ref)*/; } case DT_DAISY: that.ymd = __daisy_to_ymd(that.daisy); case DT_YMD: return __ymd_get_bday(that.ymd, bp); case DT_YMCW: return __ymcw_get_bday(that.ymcw, bp); default: case DT_DUNK: return 0; } } DEFUN int dt_get_quarter(struct dt_d_s that) { int m; switch (that.typ) { case DT_YMD: m = that.ymd.m; break; case DT_YMCW: m = that.ymcw.m; break; case DT_BIZDA: m = that.bizda.m; break; default: case DT_DUNK: return 0; } return (m - 1) / 3 + 1; } /* converters */ DEFUN dt_daisy_t dt_conv_to_daisy(struct dt_d_s that) { switch (that.typ) { case DT_DAISY: return that.daisy; case DT_YMD: return __ymd_to_daisy(that.ymd); case DT_YMCW: return __ymcw_to_daisy(that.ymcw); case DT_YWD: return __ywd_to_daisy(that.ywd); case DT_BIZDA: return __bizda_to_daisy(that.bizda, __get_bizda_param(that)); case DT_LDN: return __ldn_to_daisy(that.ldn); case DT_JDN: return __jdn_to_daisy(that.jdn); case DT_DUNK: default: break; } return (dt_daisy_t)0; } static dt_ymd_t dt_conv_to_ymd(struct dt_d_s that) { switch (that.typ) { case DT_YMD: return that.ymd; case DT_YMCW: return __ymcw_to_ymd(that.ymcw); case DT_JDN: that.daisy = __jdn_to_daisy(that.jdn); goto daisy; case DT_LDN: that.daisy = __ldn_to_daisy(that.ldn); case DT_DAISY: daisy: return __daisy_to_ymd(that.daisy); case DT_BIZDA: return __bizda_to_ymd(that.bizda); case DT_YWD: return __ywd_to_ymd(that.ywd); case DT_DUNK: default: break; } return (dt_ymd_t){.u = 0}; } static dt_ymcw_t dt_conv_to_ymcw(struct dt_d_s that) { switch (that.typ) { case DT_YMD: return __ymd_to_ymcw(that.ymd); case DT_YMCW: return that.ymcw; case DT_JDN: that.daisy = __jdn_to_daisy(that.jdn); goto daisy; case DT_LDN: that.daisy = __ldn_to_daisy(that.ldn); case DT_DAISY: daisy: return __daisy_to_ymcw(that.daisy); case DT_BIZDA: return __bizda_to_ymcw(that.bizda, __get_bizda_param(that)); case DT_YWD: return __ywd_to_ymcw(that.ywd); case DT_DUNK: default: break; } return (dt_ymcw_t){.u = 0}; } static dt_bizda_t dt_conv_to_bizda(struct dt_d_s that) { /* the problem with this conversion is that not all dates can be mapped * to a bizda date, so we need a policy first what to do in case things * go massively pear-shaped. */ switch (that.typ) { case DT_BIZDA: return that.bizda; case DT_YMD: break; case DT_YMCW: break; case DT_DAISY: break; case DT_DUNK: default: break; } return (dt_bizda_t){.u = 0}; } static dt_ywd_t dt_conv_to_ywd(struct dt_d_s this) { switch (this.typ) { case DT_YWD: /* yay, that was quick */ return this.ywd; case DT_YMD: return __ymd_to_ywd(this.ymd); case DT_YMCW: return __ymcw_to_ywd(this.ymcw); case DT_JDN: this.daisy = __jdn_to_daisy(this.jdn); goto daisy; case DT_LDN: this.daisy = __ldn_to_daisy(this.ldn); case DT_DAISY: daisy: return __daisy_to_ywd(this.daisy); case DT_BIZDA: return __bizda_to_ywd(this.bizda, __get_bizda_param(this)); case DT_DUNK: default: break; } return (dt_ywd_t){.u = 0}; } static dt_yd_t dt_conv_to_yd(struct dt_d_s this) { switch (this.typ) { case DT_YD: /* yay, that was quick */ return this.yd; case DT_YMD: return __ymd_to_yd(this.ymd); case DT_JDN: this.daisy = __jdn_to_daisy(this.jdn); goto daisy; case DT_LDN: this.daisy = __ldn_to_daisy(this.ldn); case DT_DAISY: daisy: return __daisy_to_yd(this.daisy); case DT_YMCW: return __ymcw_to_yd(this.ymcw); case DT_YWD: return __ywd_to_yd(this.ywd); default: break; } return (dt_yd_t){.u = 0}; } /* arithmetic */ #define ASPECT_ADD #include "yd.c" #include "ymd.c" #include "ymcw.c" #include "ywd.c" #include "bizda.c" #include "daisy.c" #undef ASPECT_ADD #define ASPECT_DIFF #include "yd.c" #include "ymd.c" #include "ymcw.c" #include "ywd.c" #include "bizda.c" #include "daisy.c" #undef ASPECT_DIFF #define ASPECT_CMP #include "yd.c" #include "ymd.c" #include "ymcw.c" #include "ywd.c" #include "bizda.c" #include "daisy.c" #undef ASPECT_CMP /* guessing parsers */ #include "strops.h" #include "token.h" #include "date-core-strpf.c" #if !defined SKIP_LEAP_ARITH /* we assume this file is in the dist, it's gen'd from fmt-special.gperf */ # include "fmt-special.c" #endif /* SKIP_LEAP_ARITH */ DEFVAR const char ymd_dflt[] = "%F"; DEFVAR const char ymcw_dflt[] = "%Y-%m-%c-%w"; DEFVAR const char ywd_dflt[] = "%rY-W%V-%u"; DEFVAR const char yd_dflt[] = "%Y-%d"; DEFVAR const char daisy_dflt[] = "%d"; DEFVAR const char bizsi_dflt[] = "%db"; DEFVAR const char bizda_dflt[] = "%Y-%m-%db"; DEFVAR const char ymddur_dflt[] = "%Y-%0m-%0d"; DEFVAR const char ymcwdur_dflt[] = "%Y-%0m-%0w-%0d"; DEFVAR const char ywddur_dflt[] = "%rY-W%0w-%0d"; DEFVAR const char yddur_dflt[] = "%Y-%0d"; DEFVAR const char daisydur_dflt[] = "%d"; DEFVAR const char bizsidur_dflt[] = "%db"; DEFVAR const char bizdadur_dflt[] = "%Y-%0m-%0db"; DEFUN dt_dtyp_t __trans_dfmt_special(const char *fmt) { #if !defined SKIP_LEAP_ARITH size_t len = strlen(fmt); const struct dt_fmt_special_s *res; if (UNLIKELY((res = __fmt_special(fmt, len)) != NULL)) { return res->e; } #else /* SKIP_LEAP_ARITH */ (void)fmt; #endif /* !SKIP_LEAP_ARITH */ return DT_DUNK; } DEFUN dt_dtyp_t __trans_dfmt(const char **fmt) { if (UNLIKELY(*fmt == NULL)) { /* great, standing ovations to the user */ ; } else if (LIKELY(**fmt == '%')) { /* don't worry about it */ ; } else { const dt_dtyp_t tmp = __trans_dfmt_special(*fmt); switch (tmp) { default: break; case DT_YMD: *fmt = ymd_dflt; break; case DT_YMCW: *fmt = ymcw_dflt; break; case DT_YWD: *fmt = ywd_dflt; break; case DT_YD: *fmt = yd_dflt; break; case DT_BIZDA: *fmt = bizda_dflt; break; case DT_DAISY: *fmt = daisy_dflt; break; case DT_BIZSI: *fmt = bizsi_dflt; break; } return tmp; } return DT_DUNK; } DEFUN dt_dtyp_t __trans_ddurfmt(const char **fmt) { if (UNLIKELY(*fmt == NULL)) { /* great, standing ovations to the user */ ; } else if (LIKELY(**fmt == '%')) { /* don't worry about it */ ; } else { const dt_dtyp_t tmp = __trans_dfmt_special(*fmt); switch (tmp) { default: break; case DT_YMD: *fmt = ymddur_dflt; break; case DT_YMCW: *fmt = ymcwdur_dflt; break; case DT_YWD: *fmt = ywddur_dflt; break; case DT_YD: *fmt = yddur_dflt; break; case DT_BIZDA: *fmt = bizdadur_dflt; break; case DT_DAISY: *fmt = daisydur_dflt; break; case DT_BIZSI: *fmt = bizsidur_dflt; break; } return tmp; } return DT_DUNK; } /* strpf glue */ DEFUN struct dt_d_s __guess_dtyp(struct strpd_s d) { struct dt_d_s res = dt_d_initialiser(); if (LIKELY(d.y > 0 && d.c <= 0 && !d.flags.c_wcnt_p && !d.flags.bizda)) { /* nearly all goes to ymd */ res.typ = DT_YMD; res.ymd.y = d.y; if (LIKELY(!d.flags.d_dcnt_p)) { res.ymd.m = d.m; #if defined WITH_FAST_ARITH res.ymd.d = d.d; #else /* !WITH_FAST_ARITH */ unsigned int md = __get_mdays(d.y, d.m); /* check for illegal dates, like 31st of April */ if ((res.ymd.d = d.d) > md) { res.ymd.d = md; res.fix = 1U; } } else { /* convert dcnt to m + d */ struct __md_s r = __yday_get_md(d.y, d.d); res.ymd.m = r.m; res.ymd.d = r.d; } #endif /* !WITH_FAST_ARITH */ } else if (d.y > 0 && d.m <= 0 && !d.flags.bizda) { res.typ = DT_YWD; res.ywd = __make_ywd_c(d.y, d.c, (dt_dow_t)d.w, d.flags.wk_cnt); } else if (d.y > 0 && !d.flags.bizda) { /* its legit for d.w to be naught */ res.typ = DT_YMCW; res.ymcw.y = d.y; res.ymcw.m = d.m; #if defined WITH_FAST_ARITH res.ymcw.c = d.c; #else /* !WITH_FAST_ARITH */ if ((res.ymcw.c = d.c) >= 5) { /* the user meant the LAST wday actually */ res.ymcw.c = __get_mcnt(d.y, d.m, (dt_dow_t)d.w); } #endif /* WITH_FAST_ARITH */ res.ymcw.w = d.w; } else if (d.y > 0 && d.flags.bizda) { /* d.c can be legit'ly naught */ dt_bizda_param_t bp = __make_bizda_param(d.flags.ab, 0); res.param = bp.u; res.typ = DT_BIZDA; res.bizda.y = d.y; res.bizda.m = d.m; #if defined WITH_FAST_ARITH res.bizda.bd = d.b; #else /* !WITH_FAST_ARITH */ unsigned int bd = __get_bdays(d.y, d.m); if ((res.bizda.bd = d.b) > bd) { res.bizda.bd = bd; res.fix = 1U; } #endif /* WITH_FAST_ARITH */ } else { /* anything else is bollocks for now */ ; } return res; } /* parser implementations */ #if defined __INTEL_COMPILER /* we MUST return a char* */ # pragma warning (disable:2203) #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wcast-qual" #endif /* __INTEL_COMPILER */ DEFUN struct dt_d_s dt_strpd(const char *str, const char *fmt, char **ep) { struct dt_d_s res = dt_d_initialiser(); struct strpd_s d = strpd_initialiser(); const char *sp = str; const char *fp; if (UNLIKELY(fmt == NULL)) { return __strpd_std(str, ep); } /* translate high-level format names */ __trans_dfmt(&fmt); fp = fmt; while (*fp && *sp) { const char *fp_sav = fp; struct dt_spec_s spec = __tok_spec(fp_sav, &fp); if (spec.spfl == DT_SPFL_UNK) { /* must be literal */ if (*fp_sav != *sp++) { sp = str; goto out; } } else if (LIKELY(!spec.rom)) { const char *sp_sav = sp; if (__strpd_card(&d, sp, spec, (char**)&sp) < 0) { sp = str; goto out; } if (spec.ord && __ordinalp(sp_sav, sp - sp_sav, (char**)&sp) < 0) { ; } if (spec.bizda) { switch (*sp++) { case 'B': d.flags.ab = BIZDA_BEFORE; case 'b': d.flags.bizda = 1; break; default: /* it's a bizda anyway */ d.flags.bizda = 1; sp--; break; } } } else if (UNLIKELY(spec.rom)) { if (__strpd_rom(&d, sp, spec, (char**)&sp) < 0) { sp = str; goto out; } } } res = __guess_dtyp(d); out: /* set the end pointer */ if (ep != NULL) { *ep = (char*)sp; } return res; } #define ASPECT_STRF #include "yd.c" #include "ymd.c" #include "ymcw.c" #include "ywd.c" #include "bizda.c" #include "daisy.c" #undef ASPECT_STRF DEFUN size_t dt_strfd(char *restrict buf, size_t bsz, const char *fmt, struct dt_d_s that) { struct strpd_s d = strpd_initialiser(); const char *fp; char *bp; dt_dtyp_t tgttyp; int set_fmt = 0; if (UNLIKELY(buf == NULL || bsz == 0)) { return 0; } if (LIKELY(fmt == NULL)) { /* um, great */ set_fmt = 1; } else if (LIKELY(*fmt == '%')) { /* don't worry about it */ ; } else if ((tgttyp = __trans_dfmt_special(fmt)) != DT_DUNK) { that = dt_dconv(tgttyp, that); set_fmt = 1; } if (set_fmt) { switch (that.typ) { case DT_YMD: fmt = ymd_dflt; break; case DT_YMCW: fmt = ymcw_dflt; break; case DT_YWD: fmt = ywd_dflt; break; case DT_DAISY: /* subject to change */ fmt = ymd_dflt; break; case DT_BIZDA: fmt = bizda_dflt; break; default: /* fuck */ abort(); break; } } switch (that.typ) { case DT_YMD: d.y = that.ymd.y; d.m = that.ymd.m; d.d = that.ymd.d; break; case DT_YMCW: d.y = that.ymcw.y; d.m = that.ymcw.m; d.c = that.ymcw.c; d.w = that.ymcw.w; break; case DT_JDN: that.typ = DT_DAISY; that.daisy = __jdn_to_daisy(that.jdn); goto daisy_prep; case DT_LDN: that.typ = DT_DAISY; that.daisy = __ldn_to_daisy(that.ldn); /* FALLTHROUGH */ case DT_DAISY: daisy_prep: __prep_strfd_daisy(&d, that.daisy); break; case DT_BIZDA: __prep_strfd_bizda(&d, that.bizda, __get_bizda_param(that)); break; case DT_YWD: __prep_strfd_ywd(&d, that.ywd); break; default: case DT_DUNK: bp = buf; goto out; } /* assign and go */ bp = buf; fp = fmt; for (char *const eo = buf + bsz; *fp && bp < eo;) { const char *fp_sav = fp; struct dt_spec_s spec = __tok_spec(fp_sav, &fp); if (spec.spfl == DT_SPFL_UNK) { /* must be literal then */ *bp++ = *fp_sav; } else if (LIKELY(!spec.rom)) { bp += __strfd_card(bp, eo - bp, spec, &d, that); if (spec.ord) { bp += __ordtostr(bp, eo - bp); } else if (spec.bizda) { /* don't print the b after an ordinal */ if (spec.ab == BIZDA_AFTER) { *bp++ = 'b'; } else { *bp++ = 'B'; } } } else if (UNLIKELY(spec.rom)) { bp += __strfd_rom(bp, eo - bp, spec, &d, that); } } if (bp < buf + bsz) { out: *bp = '\0'; } return bp - buf; } DEFUN struct dt_d_s dt_strpddur(const char *str, char **ep) { /* at the moment we allow only one format */ struct dt_d_s res = dt_d_initialiser(); struct strpd_s d = strpd_initialiser(); const char *sp = str; int tmp; if (str == NULL) { goto out; } /* read just one component */ tmp = strtol(sp, (char**)&sp, 10); switch (*sp++) { case '\0': /* must have been day then */ d.d = tmp; sp--; break; case 'd': case 'D': d.d = tmp; break; case 'y': case 'Y': d.y = tmp; break; case 'm': case 'M': d.m = tmp; break; case 'w': case 'W': d.w = tmp; break; case 'b': case 'B': d.b = tmp; break; case 'q': case 'Q': d.q = tmp; break; default: sp = str; goto out; } /* assess */ if (d.b && (d.y || d.m >= 1)) { res.typ = DT_BIZDA; res.bizda.y = d.y; res.bizda.m = d.q * 3 + d.m; res.bizda.bd = d.b + d.w * DUWW_BDAYS_P_WEEK; } else if (LIKELY(d.y || d.m >= 1)) { res.typ = DT_YMD; res.ymd.y = d.y; res.ymd.m = d.q * 3 + d.m; res.ymd.d = d.d + d.w * GREG_DAYS_P_WEEK; } else if (d.d) { res.typ = DT_DAISY; res.daisydur = d.w * GREG_DAYS_P_WEEK + d.d; } else if (d.b) { res.typ = DT_BIZSI; res.bizsidur = d.w * DUWW_BDAYS_P_WEEK + d.b; } else { /* we leave out YMCW diffs simply because YMD diffs * cover them better * anything that doesn't fit shall be mapped to MD durs * using the definitions of MONTHS_P_YEAR and DAYS_P_WEEK */ res.typ = DT_MD; res.md.d = d.w * GREG_DAYS_P_WEEK + d.d; res.md.m = d.y * GREG_MONTHS_P_YEAR + d.m; } out: if (ep != NULL) { *ep = (char*)sp; } return res; } DEFUN size_t dt_strfddur(char *restrict buf, size_t bsz, const char *fmt, struct dt_d_s that) { struct strpd_s d = strpd_initialiser(); const char *fp; char *bp; if (UNLIKELY(buf == NULL || bsz == 0 || !that.dur)) { return 0; } switch (that.typ) { case DT_YMD: d.y = that.ymd.y; d.m = that.ymd.m; d.d = that.ymd.d; if (fmt == NULL) { fmt = ymddur_dflt; } break; case DT_YMCW: d.y = that.ymcw.y; d.m = that.ymcw.m; d.c = that.ymcw.c; d.d = that.ymcw.w; if (fmt == NULL) { fmt = ymcwdur_dflt; } break; case DT_YWD: d.y = that.ywd.y; d.c = that.ywd.c; d.d = that.ywd.w; if (fmt == NULL) { fmt = ywddur_dflt; } break; case DT_YD: d.y = that.yd.y; d.d = that.yd.d; if (fmt == NULL) { fmt = yddur_dflt; } break; case DT_DAISY: if (that.daisydur >= 0) { d.d = that.daisydur; } else { d.d = -that.daisydur; /* make sure the neg bit doesn't bite us */ that.neg = 1; } if (fmt == NULL) { /* subject to change */ fmt = daisydur_dflt; } break; case DT_BIZSI: if (that.bizsidur >= 0) { d.d = that.bizsidur; } else { d.d = -that.bizsidur; /* make sure the neg bit doesn't bite us */ that.neg = 1; } if (fmt == NULL) { /* subject to change */ fmt = bizsidur_dflt; } break; case DT_BIZDA: { dt_bizda_param_t bparam = __get_bizda_param(that); d.y = that.bizda.y; d.m = that.bizda.m; d.b = that.bizda.bd; if (LIKELY(bparam.ab == BIZDA_AFTER)) { d.flags.ab = BIZDA_AFTER; } else { d.flags.ab = BIZDA_BEFORE; } d.flags.bizda = 1; if (fmt == NULL) { fmt = bizdadur_dflt; } break; } case DT_MD: d.y = __uidiv(that.md.m, GREG_MONTHS_P_YEAR); d.m = __uimod(that.md.m, GREG_MONTHS_P_YEAR); d.w = __uidiv(that.md.d, GREG_DAYS_P_WEEK); d.d = __uimod(that.md.d, GREG_DAYS_P_WEEK); break; default: case DT_DUNK: bp = buf; goto out; } /* translate high-level format names */ __trans_ddurfmt(&fmt); /* assign and go */ bp = buf; fp = fmt; if (that.neg) { *bp++ = '-'; } for (char *const eo = buf + bsz; *fp && bp < eo;) { const char *fp_sav = fp; struct dt_spec_s spec = __tok_spec(fp_sav, &fp); if (spec.spfl == DT_SPFL_UNK) { /* must be literal then */ *bp++ = *fp_sav; } else if (LIKELY(!spec.rom)) { bp += __strfd_dur(bp, eo - bp, spec, &d, that); if (spec.bizda) { /* don't print the b after an ordinal */ if (d.flags.ab == BIZDA_AFTER) { *bp++ = 'b'; } else { *bp++ = 'B'; } } } } if (bp < buf + bsz) { out: *bp = '\0'; } return bp - buf; } #if defined __INTEL_COMPILER /* we MUST return a char* */ # pragma warning (default:2203) #elif defined __GNUC__ # pragma GCC diagnostic warning "-Wcast-qual" #endif /* __INTEL_COMPILER */ /* date getters, platform dependent */ DEFUN struct dt_d_s dt_date(dt_dtyp_t outtyp) { struct dt_d_s res; time_t t = time(NULL); switch ((res.typ = outtyp)) { case DT_YMD: case DT_YMCW: { struct tm tm; ffff_gmtime(&tm, t); switch (res.typ) { case DT_YMD: res.ymd.y = tm.tm_year; res.ymd.m = tm.tm_mon; res.ymd.d = tm.tm_mday; break; case DT_YMCW: { #if defined HAVE_ANON_STRUCTS_INIT dt_ymd_t tmp = { .y = tm.tm_year, .m = tm.tm_mon, .d = tm.tm_mday, }; #else dt_ymd_t tmp; tmp.y = tm.tm_year, tmp.m = tm.tm_mon, tmp.d = tm.tm_mday, #endif res.ymcw.y = tm.tm_year; res.ymcw.m = tm.tm_mon; res.ymcw.c = __ymd_get_count(tmp); res.ymcw.w = tm.tm_wday; break; } default: break; } break; } case DT_DAISY: /* time_t's base is 1970-01-01, which is daisy 19359 */ res.daisy = t / 86400 + 19359; break; default: case DT_MD: /* doesn't make sense */ case DT_DUNK: res.u = 0; } return res; } DEFUN struct dt_d_s dt_dconv(dt_dtyp_t tgttyp, struct dt_d_s d) { struct dt_d_s res = dt_d_initialiser(); switch ((res.typ = tgttyp)) { case DT_YMD: res.ymd = dt_conv_to_ymd(d); break; case DT_YMCW: res.ymcw = dt_conv_to_ymcw(d); break; case DT_DAISY: case DT_JDN: case DT_LDN: { dt_daisy_t tmp = dt_conv_to_daisy(d); switch (tgttyp) { case DT_DAISY: res.daisy = tmp; break; case DT_LDN: res.ldn = __daisy_to_ldn(tmp); break; case DT_JDN: res.jdn = __daisy_to_jdn(tmp); break; default: /* nice one gcc */ ; } break; } case DT_BIZDA: /* actually this is a parametrised date */ res.bizda = dt_conv_to_bizda(d); break; case DT_YWD: res.ywd = dt_conv_to_ywd(d); break; case DT_DUNK: default: res.typ = DT_DUNK; break; } return res; } DEFUN struct dt_d_s dt_dadd_d(struct dt_d_s d, int n) { /* add N (gregorian) days to D */ switch (d.typ) { case DT_JDN: d.daisy = __jdn_to_daisy(d.jdn); goto daisy_add_d; case DT_LDN: d.daisy = __ldn_to_daisy(d.ldn); goto daisy_add_d; case DT_DAISY: daisy_add_d: d.daisy = __daisy_add_d(d.daisy, n); /* transform back (maybe) */ switch (d.typ) { case DT_DAISY: default: break; case DT_LDN: d.ldn = __daisy_to_ldn(d.daisy); break; case DT_JDN: d.jdn = __daisy_to_jdn(d.daisy); break; } break; case DT_YMD: d.ymd = __ymd_add_d(d.ymd, n); break; case DT_YMCW: d.ymcw = __ymcw_add_d(d.ymcw, n); break; case DT_BIZDA: d.bizda = __bizda_add_d(d.bizda, n); break; case DT_YWD: d.ywd = __ywd_add_d(d.ywd, n); break; case DT_DUNK: default: d.typ = DT_DUNK; d.u = 0; break; } return d; } DEFUN struct dt_d_s dt_dadd_b(struct dt_d_s d, int n) { /* add N business days to D */ switch (d.typ) { case DT_JDN: d.daisy = __jdn_to_daisy(d.jdn); goto daisy_add_b; case DT_LDN: d.daisy = __ldn_to_daisy(d.ldn); goto daisy_add_b; case DT_DAISY: daisy_add_b: d.daisy = __daisy_add_b(d.daisy, n); /* transform back (maybe) */ switch (d.typ) { case DT_DAISY: default: break; case DT_LDN: d.ldn = __daisy_to_ldn(d.daisy); break; case DT_JDN: d.jdn = __daisy_to_jdn(d.daisy); break; } break; case DT_YMD: d.ymd = __ymd_add_b(d.ymd, n); break; case DT_YMCW: d.ymcw = __ymcw_add_b(d.ymcw, n); break; case DT_BIZDA: d.bizda = __bizda_add_b(d.bizda, n); break; case DT_YWD: d.ywd = __ywd_add_b(d.ywd, n); break; case DT_DUNK: default: d.typ = DT_DUNK; d.u = 0; break; } return d; } DEFUN struct dt_d_s dt_dadd_w(struct dt_d_s d, int n) { /* add N weeks to D */ switch (d.typ) { case DT_JDN: d.daisy = __jdn_to_daisy(d.jdn); goto daisy_add_w; case DT_LDN: d.daisy = __ldn_to_daisy(d.ldn); goto daisy_add_w; case DT_DAISY: daisy_add_w: d.daisy = __daisy_add_w(d.daisy, n); /* transform back (maybe) */ switch (d.typ) { case DT_DAISY: default: break; case DT_LDN: d.ldn = __daisy_to_ldn(d.daisy); break; case DT_JDN: d.jdn = __daisy_to_jdn(d.daisy); break; } break; case DT_YMD: d.ymd = __ymd_add_w(d.ymd, n); break; case DT_YMCW: d.ymcw = __ymcw_add_w(d.ymcw, n); break; case DT_BIZDA: d.bizda = __bizda_add_w(d.bizda, n); break; case DT_YWD: d.ywd = __ywd_add_w(d.ywd, n); break; case DT_DUNK: default: d.typ = DT_DUNK; d.u = 0; break; } return d; } DEFUN struct dt_d_s dt_dadd_m(struct dt_d_s d, int n) { /* add N months to D */ switch (d.typ) { case DT_LDN: case DT_JDN: case DT_DAISY: /* daisy objects have no notion of months */ break; case DT_YMD: d.ymd = __ymd_add_m(d.ymd, n); break; case DT_YMCW: d.ymcw = __ymcw_add_m(d.ymcw, n); break; case DT_BIZDA: d.bizda = __bizda_add_m(d.bizda, n); break; case DT_YWD: /* ywd have no notion of months */ break; case DT_DUNK: default: d.typ = DT_DUNK; d.u = 0; break; } return d; } DEFUN struct dt_d_s dt_dadd_y(struct dt_d_s d, int n) { /* add N years to D */ switch (d.typ) { case DT_LDN: case DT_JDN: case DT_DAISY: /* daisy objects have no notion of years */ break; case DT_YMD: d.ymd = __ymd_add_y(d.ymd, n); break; case DT_YMCW: d.ymcw = __ymcw_add_y(d.ymcw, n); break; case DT_BIZDA: d.bizda = __bizda_add_y(d.bizda, n); break; case DT_YWD: d.ywd = __ywd_add_y(d.ywd, n); break; case DT_DUNK: default: d.typ = DT_DUNK; d.u = 0; break; } return d; } DEFUN struct dt_d_s dt_dadd(struct dt_d_s d, struct dt_d_s dur) { struct strpdi_s durcch = strpdi_initialiser(); __fill_strpdi(&durcch, dur); if (durcch.d) { d = dt_dadd_d(d, durcch.d); } else if (durcch.b) { d = dt_dadd_b(d, durcch.b); } if (durcch.w) { d = dt_dadd_w(d, durcch.w); } if (durcch.m) { d = dt_dadd_m(d, durcch.m); } if (durcch.y) { d = dt_dadd_y(d, durcch.y); } return d; } DEFUN struct dt_d_s dt_neg_dur(struct dt_d_s dur) { dur.neg = (uint16_t)(~dur.neg & 0x01); switch (dur.typ) { case DT_DAISY: dur.daisydur = -dur.daisydur; break; case DT_BIZSI: dur.bizsidur = -dur.bizsidur; break; default: break; } return dur; } DEFUN int dt_dur_neg_p(struct dt_d_s dur) { switch (dur.typ) { case DT_DAISY: return dur.daisydur < 0; case DT_BIZSI: return dur.bizsidur < 0; default: return dur.neg; } } DEFUN struct dt_d_s dt_ddiff(dt_dtyp_t tgttyp, struct dt_d_s d1, struct dt_d_s d2) { struct dt_d_s res = {.typ = DT_DUNK}; dt_dtyp_t tmptyp = tgttyp; if (tgttyp == DT_MD) { if (d1.typ == DT_YMD || d2.typ == DT_YMD) { tmptyp = DT_YMD; } else if (d1.typ == DT_YMCW || d2.typ == DT_YMCW) { tmptyp = DT_YMCW; } else { tmptyp = DT_DAISY; } } switch (tmptyp) { case DT_BIZSI: case DT_DAISY: { dt_daisy_t tmp1 = dt_conv_to_daisy(d1); dt_daisy_t tmp2 = dt_conv_to_daisy(d2); res = __daisy_diff(tmp1, tmp2); /* fix up result in case it's bizsi, i.e. kick weekends */ if (tgttyp == DT_BIZSI) { dt_dow_t wdb = __daisy_get_wday(tmp2); res.bizsidur = __get_nbdays(res.daisydur, wdb); } break; } case DT_YMD: { dt_ymd_t tmp1 = dt_conv_to_ymd(d1); dt_ymd_t tmp2 = dt_conv_to_ymd(d2); res = __ymd_diff(tmp1, tmp2); break; } case DT_YMCW: { dt_ymcw_t tmp1 = dt_conv_to_ymcw(d1); dt_ymcw_t tmp2 = dt_conv_to_ymcw(d2); res = __ymcw_diff(tmp1, tmp2); break; } case DT_YD: { dt_yd_t tmp1 = dt_conv_to_yd(d1); dt_yd_t tmp2 = dt_conv_to_yd(d2); res = __yd_diff(tmp1, tmp2); break; } case DT_YWD: { dt_ywd_t tmp1 = dt_conv_to_ywd(d1); dt_ywd_t tmp2 = dt_conv_to_ywd(d2); res = __ywd_diff(tmp1, tmp2); break; } case DT_BIZDA: case DT_DUNK: default: res.typ = DT_DUNK; res.u = 0; /* @fallthrough@ */ case DT_MD: /* md is handled later */ break; } /* check if we had DT_MD as tgttyp */ if (tgttyp == DT_MD) { /* convert res back to DT_MD */ struct dt_d_s tmp = {.typ = DT_MD}; switch (tmptyp) { case DT_YMD: tmp.md.m = res.ymd.y * GREG_MONTHS_P_YEAR + res.ymd.m; tmp.md.d = res.ymd.d; break; case DT_YMCW: tmp.md.m = res.ymcw.y * GREG_MONTHS_P_YEAR + res.ymcw.m; tmp.md.d = res.ymcw.w * GREG_DAYS_P_WEEK + res.ymcw.c; break; case DT_DAISY: tmp.md.m = 0; tmp.md.d = res.daisy; break; default: break; } res = tmp; } return res; } DEFUN int dt_dcmp(struct dt_d_s d1, struct dt_d_s d2) { /* for the moment D1 and D2 have to be of the same type. */ if (UNLIKELY(d1.typ != d2.typ)) { /* always the left one */ return -2; } switch (d1.typ) { case DT_DUNK: default: return -2; case DT_YMD: case DT_DAISY: case DT_BIZDA: case DT_YWD: /* use arithmetic comparison */ if (d1.u == d2.u) { return 0; } else if (d1.u < d2.u) { return -1; } else /*if (d1.u > d2.u)*/ { return 1; } case DT_YMCW: /* use designated thing since ymcw dates aren't * increasing */ return __ymcw_cmp(d1.ymcw, d2.ymcw); } } DEFUN int dt_d_in_range_p(struct dt_d_s d, struct dt_d_s d1, struct dt_d_s d2) { return dt_dcmp(d, d1) >= 0 && dt_dcmp(d, d2) <= 0; } #endif /* INCLUDED_date_core_c_ */ /* date-core.c ends here */ dateutils-0.3.1/lib/date-core.h000066400000000000000000000353621241477753400163220ustar00rootroot00000000000000/*** date-core.h -- our universe of dates * * Copyright (C) 2011-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ #if !defined INCLUDED_date_core_h_ #define INCLUDED_date_core_h_ #include #include #include #include #include "token.h" #if defined __cplusplus extern "C" { #endif /* __cplusplus */ typedef enum { DT_DUNK, #define DT_DUNK (dt_dtyp_t)(DT_DUNK) DT_YMD, #define DT_YMD (dt_dtyp_t)(DT_YMD) DT_YMCW, #define DT_YMCW (dt_dtyp_t)(DT_YMCW) DT_BIZDA, #define DT_BIZDA (dt_dtyp_t)(DT_BIZDA) DT_DAISY, #define DT_DAISY (dt_dtyp_t)(DT_DAISY) DT_BIZSI, #define DT_BIZSI (dt_dtyp_t)(DT_BIZSI) DT_MD, #define DT_MD (dt_dtyp_t)(DT_MD) DT_YWD, #define DT_YWD (dt_dtyp_t)(DT_YWD) DT_YD, #define DT_YD (dt_dtyp_t)(DT_YD) DT_JDN, #define DT_JDN (dt_dtyp_t)(DT_JDN) DT_LDN, #define DT_LDN (dt_dtyp_t)(DT_LDN) DT_NDTYP, } dt_dtyp_t; #if defined WITH_FAST_ARITH # define DT_MIN_YEAR (1917) # define DT_MAX_YEAR (2099) #else # define DT_MIN_YEAR (1601) # define DT_MAX_YEAR (4095) #endif /* WITH_FAST_ARITH */ /** ymds * ymds are just bcd coded concatenations of 8601 dates */ typedef union { uint32_t u; struct { #if defined WORDS_BIGENDIAN /* 11 bits left */ unsigned int:11; unsigned int y:12; unsigned int m:4; unsigned int d:5; #else /* !WORDS_BIGENDIAN */ unsigned int d:5; unsigned int m:4; unsigned int y:12; /* 11 bits left */ unsigned int:11; #endif /* WORDS_BIGENDIAN */ }; } dt_ymd_t; /** ymcws * ymcws are year-month-count-weekday bcd coded. */ typedef union { uint32_t u; struct { #if defined WORDS_BIGENDIAN /* 10 bits left */ unsigned int:10; unsigned int y:12; unsigned int m:4; unsigned int c:3; unsigned int w:3; #else /* !WORDS_BIGENDIAN */ unsigned int w:3; unsigned int c:3; unsigned int m:4; unsigned int y:12; /* 10 bits left */ unsigned int:10; #endif /* WORDS_BIGENDIAN */ }; } dt_ymcw_t; /** ywds * ywds are ISO 8601's year-week-day calendars. * By coincidence ycw's y and w slots are accessible through the ymcw bit field, * whether that's useful or not will occur to us later and then we might change * the layout. * Also, there's one auxiliary parameter the number of overhanging days * before the first day (Mon) in the first week, this number is in the * range of -3 to 3. For a year to start on Sunday it's +1, for a year * to start on Tuesday it's -1. */ typedef union { uint32_t u; struct { #define YWD_SUNWK_CNT (0) #define YWD_MONWK_CNT (1) #define YWD_ISOWK_CNT (2) #define YWD_ABSWK_CNT (3) #if defined WORDS_BIGENDIAN /* 8 bits left */ unsigned int:7; unsigned int y:12; unsigned int c:7; unsigned int w:3; signed int hang:3; #else /* !WORDS_BIGENDIAN */ signed int hang:3; unsigned int w:3; unsigned int c:7; unsigned int y:12; /* 8 bits left */ unsigned int:7; #endif /* WORDS_BIGENDIAN */ }; } dt_ywd_t; typedef union { uint16_t u; uint32_t bs:16; struct { /* counting convention */ unsigned int cc:2; unsigned int:14; }; } __attribute__((__packed__)) dt_ywd_param_t; /** yds * yds are pure helpers and don't exist in the wild. */ typedef union { uint32_t u; struct { #if defined WORDS_BIGENDIAN unsigned int y:16U; signed int d:16U; #else /* !WORDS_BIGENDIAN */ signed int d:16U; unsigned int y:16U; #endif /* WORDS_BIGENDIAN */ }; } dt_yd_t; /** daysi * daisys are days since X, -01-00 here */ typedef uint32_t dt_daisy_t; #define DT_DAISY_BASE_YEAR (DT_MIN_YEAR) /* and a signed version for durations */ typedef int32_t dt_sdaisy_t; /** jdn (julian day number) * julian days are whole solar days since noon 1 Jan 4713 BC. * We will mostly use the daisy type for this. */ typedef float dt_jdn_t; /** ldn (lilian day number) * lilian days are whole solar days since the inception of the Gregorian * calendar, i.e. 15 Oct 1582. * We will mostly use the daisy type for this. */ typedef dt_daisy_t dt_ldn_t; /** bizda * bizdas is a calendar that counts business days before or after a * certain day in the month, mostly ultimo. */ typedef union { uint32_t u; struct { #define BIZDA_AFTER (0U)/*>*/ #define BIZDA_BEFORE (1U)/*<*/ #define BIZDA_ULTIMO (0U) #if defined WORDS_BIGENDIAN /* 5 bits left */ unsigned int:5; /* business day */ unsigned int y:12; unsigned int m:4; unsigned int bd:5; #else /* !WORDS_BIGENDIAN */ /* business day */ unsigned int bd:5; unsigned int m:4; unsigned int y:12; /* 5 bits left */ unsigned int:5; #endif /* WORDS_BIGENDIAN */ }; } dt_bizda_t; typedef union { uint16_t u; uint32_t bs:16; struct { /* before or after */ unsigned int ab:1; /* reference day, use 00 for ultimo */ unsigned int ref:5; unsigned int:10; }; } __attribute__((__packed__)) dt_bizda_param_t; /** * One more type that's only used for durations. */ typedef union { uint32_t u; struct { unsigned int d:16; unsigned int m:16; }; } dt_md_t; /** * Collection of all date types. */ struct dt_d_s { /* date type */ dt_dtyp_t typ:4; /* unused here, but used by inherited types (e.g. dt_dt_s) */ uint32_t:3; /* error indicator, usually means date has been fixed up */ uint32_t fix:1; /* duration predicate */ uint32_t dur:1; /* negated predicate */ uint32_t neg:1; /* fill up to next ui16 boundary */ uint32_t:6; /* for parametrised types */ uint32_t param:16; union { uint32_t u; dt_ymd_t ymd; dt_ymcw_t ymcw; dt_ywd_t ywd; dt_daisy_t daisy; dt_daisy_t bizsi; dt_jdn_t jdn; dt_ldn_t ldn; /* all bizdas mixed into this */ dt_bizda_t bizda; /* for durations only */ dt_md_t md; dt_sdaisy_t daisydur; dt_sdaisy_t bizsidur; /* for helper purposes only */ dt_yd_t yd; }; }; /* widely understood notion of weekdays */ typedef enum { DT_MIRACLEDAY, DT_MONDAY, DT_TUESDAY, DT_WEDNESDAY, DT_THURSDAY, DT_FRIDAY, DT_SATURDAY, DT_SUNDAY, } dt_dow_t; /* match operations */ typedef uint32_t/*:3*/ oper_t; enum { OP_UNK = 0, OP_FALSE = OP_UNK, /* bit 1 set */ OP_EQ, /* bit 2 set */ OP_LT, OP_LE, /* bit 3 set */ OP_GT, OP_GE, /* bits 2 and 3 set */ OP_NE, /* bits 1, 2 and 3 set */ OP_TRUE, }; /* constants (for known calendars) */ #define GREG_DAYS_P_WEEK (7U) #define GREG_MONTHS_P_YEAR (12U) #define DUWW_BDAYS_P_WEEK (5U) /* decls */ /** * Like strptime() for our dates. * The format characters are _NOT_ compatible with strptime(). * If FMT is NULL the standard format for each calendric system is used, * see format.texi or dateutils info page. * * FMT can also be the name of a calendar: * - ymd for YMD dates * - ymcw for YMCW dates * - bizda for bizda/YMDU dates * * If optional EP is non-NULL it will point to the end of the parsed * date string. */ extern struct dt_d_s dt_strpd(const char *str, const char *fmt, char **ep); /** * Like strftime() for our dates */ extern size_t dt_strfd(char *restrict buf, size_t bsz, const char *fmt, struct dt_d_s); /** * Parse durations as in 1w5d, etc. */ extern struct dt_d_s dt_strpddur(const char *str, char **ep); /** * Print a duration. */ extern size_t dt_strfddur(char *restrict buf, size_t bsz, const char *fmt, struct dt_d_s); /** * Like time() but return the current date in the desired format. */ extern struct dt_d_s dt_date(dt_dtyp_t outtyp); /** * Convert D to another calendric system, specified by TGTTYP. */ extern struct dt_d_s dt_dconv(dt_dtyp_t tgttyp, struct dt_d_s); /** * Get the year count (gregorian) of a date, * calendars without the notion of a year will return 0. */ extern int dt_get_year(struct dt_d_s); /** * Get the month within the year of a date, * calendars without the notion of a month will return 0. */ extern int dt_get_mon(struct dt_d_s); /** * Get the weekday of a date. */ extern dt_dow_t dt_get_wday(struct dt_d_s); /** * Get the day of the month of a date. */ extern int dt_get_mday(struct dt_d_s d); /** * Get the business day count of a date in a month. */ extern int dt_get_bday(struct dt_d_s d); /** * Get the business day count of a date in a month Before/After REF. */ extern int dt_get_bday_q(struct dt_d_s d, dt_bizda_param_t bp); /** * Get the quarter number of a date. */ extern int dt_get_quarter(struct dt_d_s d); /** * Get the day of the year of a date. * This might only be intuitive for YMD dates. The formal definition * is to find a representation of D that lacks the notion of a month, * so for YMD dates this would be the sum of the days in the months * preceding M and the current day of the month in M. * For YMCW dates this will yield the n-th W-day in Y. * For calendars without the notion of a year this will return 0. */ extern unsigned int dt_get_yday(struct dt_d_s d); /** * Return N where N is the week within the year that THIS is in. */ extern int dt_get_wcnt_year(struct dt_d_s this, unsigned int wkcnt_convention); /* converters */ extern dt_daisy_t dt_conv_to_daisy(struct dt_d_s); extern dt_ymd_t __daisy_to_ymd(dt_daisy_t); /* adders */ /** * Add duration DUR to date D. */ extern struct dt_d_s dt_dadd(struct dt_d_s d, struct dt_d_s dur); /** * Add N (gregorian) days to date D. */ extern struct dt_d_s dt_dadd_d(struct dt_d_s d, int n); /** * Add N business days to date D. */ extern struct dt_d_s dt_dadd_b(struct dt_d_s d, int n); /** * Add N weeks to date D. */ extern struct dt_d_s dt_dadd_w(struct dt_d_s d, int n); /** * Add N months to date D. * For calendars without the notion of months the result is D. */ extern struct dt_d_s dt_dadd_m(struct dt_d_s d, int n); /** * Add N years to date D. * For calendars without the notion of years the result is D. */ extern struct dt_d_s dt_dadd_y(struct dt_d_s d, int n); /** * Negate the duration. */ extern struct dt_d_s dt_neg_dur(struct dt_d_s); /** * Is duration DUR negative? */ extern int dt_dur_neg_p(struct dt_d_s dur); /** * Get duration between D1 and D2. * The result will be of type TGTTYP, * the calendar of D1 will be used, e.g. its month-per-year, days-per-week, * etc. conventions count. * If instead D2 should count, swap D1 and D2 and negate the duration * by setting/clearing the neg bit. */ extern struct dt_d_s dt_ddiff(dt_dtyp_t tgttyp, struct dt_d_s d1, struct dt_d_s d2); /** * Compare two dates, yielding 0 if they are equal, -1 if D1 is older, * 1 if D1 is younger than the D2. */ extern int dt_dcmp(struct dt_d_s d1, struct dt_d_s d2); /** * Check if D is in the interval spanned by D1 and D2, * 1 if D1 is younger than the D2. */ extern int dt_d_in_range_p(struct dt_d_s d, struct dt_d_s d1, struct dt_d_s d2); /** * Get the week count of D in the year when weeks start at _1st_wd. */ extern int __yd_get_wcnt(dt_yd_t d, dt_dow_t _1st_wd); /** * Like __yd_get_wcnt() but for ISO week convention. */ extern int __yd_get_wcnt_iso(dt_yd_t d); /** * Like __yd_get_wcnt() but disregard what day the year started with. */ extern int __yd_get_wcnt_abs(dt_yd_t d); /** * Return the N-th W-day in the year of THAT. * This is equivalent with 8601's Y-W-D calendar where W is the week * of the year and D the day in the week */ extern unsigned int __ymcw_get_yday(dt_ymcw_t that); /** * Get the number of days in month M of year Y. */ extern unsigned int __get_mdays(unsigned int y, unsigned int m); /** * Get the number of business days in month M of year Y. */ extern unsigned int __get_bdays(unsigned int y, unsigned int m); /** * Compare two ymcw objects, return <0, 0, >0 when D1 < D2, D1 == D2, D1 > D2 */ extern int __ymcw_cmp(dt_ymcw_t d1, dt_ymcw_t d2); /** * Get N where N is the N-th occurrence of wday in the month of that year */ extern unsigned int __ymd_get_count(dt_ymd_t that); /* some useful gimmicks, sort of */ static inline __attribute__((pure, const)) struct dt_d_s dt_d_initialiser(void) { #if defined HAVE_SLOPPY_STRUCTS_INIT static const struct dt_d_s res = {}; #else /* HAVE_SLOPPY_STRUCTS_INIT */ static const struct dt_d_s res; #endif /* HAVE_SLOPPY_STRUCTS_INIT */ return res; } /* other ctors */ static inline struct dt_d_s dt_make_ymd(unsigned int y, unsigned int m, unsigned int d) { struct dt_d_s res; res.typ = DT_YMD; res.dur = 0U; res.neg = 0U; res.fix = 0U; res.param = 0U; res.ymd.y = y; res.ymd.m = m; res.ymd.d = d; return res; } static inline struct dt_d_s dt_make_ymcw(unsigned int y, unsigned int m, unsigned int c, unsigned int w) { struct dt_d_s res; res.typ = DT_YMCW; res.dur = 0U; res.neg = 0U; res.fix = 0U; res.param = 0U; res.ymcw.y = y; res.ymcw.m = m; res.ymcw.c = c; res.ymcw.w = w; return res; } static inline struct dt_d_s dt_make_daisydur(signed int d) { struct dt_d_s res; res.typ = DT_DAISY; res.dur = 1U; res.neg = 0U; res.fix = 0U; res.param = 0U; res.daisydur = d; return res; } static inline dt_bizda_param_t __get_bizda_param(struct dt_d_s that) { dt_bizda_param_t p; p.bs = that.param; return p; } static inline dt_bizda_param_t __make_bizda_param(unsigned int ab, unsigned int ref) { dt_bizda_param_t p; p.ab = ab; p.ref = ref; return p; } static inline dt_ywd_param_t __get_ywd_param(struct dt_d_s that) { return (dt_ywd_param_t){.bs = that.param}; } static inline dt_ywd_param_t __make_ywd_param(unsigned int cc) { dt_ywd_param_t p; p.cc = cc; return p; } static inline bool __leapp(unsigned int y) { #if defined WITH_FAST_ARITH return y % 4 == 0; #else /* !WITH_FAST_ARITH */ return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); #endif /* WITH_FAST_ARITH */ } #if defined __cplusplus } #endif /* __cplusplus */ #endif /* INCLUDED_date_core_h_ */ dateutils-0.3.1/lib/dt-core-private.h000066400000000000000000000036641241477753400174640ustar00rootroot00000000000000/*** dt-core-private.h -- our universe of datetimes, private bits * * Copyright (C) 2012-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ /* private portion of dt-core.h */ #if !defined INCLUDED_dt_core_private_h_ #define INCLUDED_dt_core_private_h_ #include "dt-core.h" extern dt_dttyp_t __trans_dtfmt(const char **fmt); extern dt_dttyp_t __trans_dtdurfmt(const char**fmt); #endif /* INCLUDED_dt_core_private_h_ */ dateutils-0.3.1/lib/dt-core-strpf.c000066400000000000000000000252451241477753400171420ustar00rootroot00000000000000/*** dt-core-strpf.c -- parser and formatter funs for dt-core * * Copyright (C) 2011-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ /* implementation part of date-core-strpf.h */ #if !defined INCLUDED_dt_core_strpf_c_ #define INCLUDED_dt_core_strpf_c_ #if defined HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include "strops.h" #include "token.h" #include "dt-core.h" #include "dt-core-strpf.h" #if defined __INTEL_COMPILER /* we MUST return a char* */ # pragma warning (disable:2203) #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wcast-qual" #endif /* __INTEL_COMPILER */ #if !defined DEFUN # define DEFUN #endif /* !DEFUN */ #if defined SKIP_LEAP_ARITH # undef WITH_LEAP_SECONDS #endif /* SKIP_LEAP_ARITH */ static int32_t try_zone(const char *str, const char **ep) { int minusp = 0; const char *sp = str; int32_t res = 0; switch (*sp) { int32_t tmp; case '-': minusp = 1; case '+': /* read hour part */ if ((tmp = strtoi_lim(++sp, &sp, 0, 14)) < 0) { break; } res += 3600 * tmp; /* colon separator is optional */ if (*sp == ':') { sp++; } /* read minute part */ if ((tmp = strtoi_lim(sp, &sp, 0, 59)) < 0) { break; } res += 60 * tmp; /* again colon separator is optional */ if (*sp == ':') { sp++; } /* read second part */ if ((tmp = strtoi_lim(sp, &sp, 0, 59)) < 0) { break; } res += tmp; break; default: /* clearly a mistake to advance SP */ break; } /* res.typ coincides with DT_SANDWICH_D_ONLY() if we jumped here */ if (ep != NULL) { *ep = sp; } return minusp ? -res : res; } static struct dt_dt_s __fixup_zdiff(struct dt_dt_s dt, int32_t zdiff) { /* apply time zone difference */ struct dt_dt_s zd = dt_dt_initialiser(); dt_make_t_only(&zd, DT_HMS); zd.t.dur = 1; zd.t.sdur = -zdiff; /* reuse dt for result */ dt = dt_dtadd(dt, zd); dt.znfxd = 1; return dt; } DEFUN struct dt_dt_s __strpdt_std(const char *str, char **ep) { /* code dupe, see __strpd_std() */ struct dt_dt_s res = dt_dt_initialiser(); struct strpdt_s d = strpdt_initialiser(); const char *sp; if ((sp = str) == NULL) { goto out; } /* check for epoch notation */ if (*sp == '@') { /* yay, epoch */ const char *tmp; d.i = strtoi(++sp, &tmp); if (UNLIKELY(d.i == -1 && sp == tmp)) { sp--; } else { /* let's make a DT_SEXY */ res.typ = DT_SEXY; res.sxepoch = d.i; } goto out; } /* read the year */ if ((d.sd.y = strtoi_lim(sp, &sp, DT_MIN_YEAR, DT_MAX_YEAR)) < 0 || *sp++ != '-') { sp = str; goto try_time; } /* check for ywd dates */ if (UNLIKELY(*sp == 'W')) { /* brilliant */ if ((sp++, d.sd.c = strtoi_lim(sp, &sp, 0, 53)) < 0 || *sp++ != '-') { goto try_time; } d.sd.flags.c_wcnt_p = 1; d.sd.flags.wk_cnt = YWD_ISOWK_CNT; goto dow; } /* read the month */ if ((d.sd.m = strtoi_lim(sp, &sp, 0, 12)) < 0 || *sp++ != '-') { sp = str; goto out; } /* read the day or the count */ if ((d.sd.d = strtoi_lim(sp, &sp, 0, 31)) < 0) { /* didn't work, fuck off */ sp = str; goto out; } /* check the date type */ switch (*sp) { case '-': /* it is a YMCW date */ if ((d.sd.c = d.sd.d) > 5) { /* nope, it was bollocks */ break; } d.sd.d = 0; dow: if ((d.sd.w = strtoi_lim(++sp, &sp, 0, 7)) < 0) { /* didn't work, fuck off */ sp = str; goto out; } /* fix up d.sd.w right away */ d.sd.w = d.sd.w ?: DT_SUNDAY; break; case 'B': /* it's a bizda/YMDU before ultimo date */ d.sd.flags.ab = BIZDA_BEFORE; case 'b': /* it's a bizda/YMDU after ultimo date */ d.sd.flags.bizda = 1; d.sd.b = d.sd.d; d.sd.d = 0; sp++; break; default: /* we don't care */ break; } /* guess what we're doing */ if ((res.d = __guess_dtyp(d.sd)).typ == DT_DUNK) { /* not much use parsing on */ goto out; } /* check for the d/t separator */ switch (*sp) { case 'T': case ' ': case '\t': /* could be a time, could be something, else * make sure we leave a mark */ str = sp++; break; default: /* should be a no-op */ dt_make_d_only(&res, res.d.typ); goto out; } try_time: /* and now parse the time */ if ((d.st.h = strtoi_lim(sp, &sp, 0, 23)) < 0 || *sp != ':') { sp = str; goto out; } else if ((d.st.m = strtoi_lim(++sp, &sp, 0, 59)) < 0) { d.st.m = 0; goto eval_time; } else if (*sp != ':') { goto eval_time; } else if ((d.st.s = strtoi_lim(++sp, &sp, 0, 60)) < 0) { d.st.s = 0; } else if (*sp != '.') { goto eval_time; } else if ((d.st.ns = strtoi_lim(++sp, &sp, 0, 999999999)) < 0) { d.st.ns = 0; goto eval_time; } eval_time: res.t.hms.h = d.st.h; res.t.hms.m = d.st.m; res.t.hms.s = d.st.s; if (res.d.typ > DT_DUNK) { const char *tp; dt_make_sandwich(&res, res.d.typ, DT_HMS); /* check for the zone stuff */ if ((d.zdiff = try_zone(sp, &tp))) { res = __fixup_zdiff(res, d.zdiff); } else if (tp > sp) { res.znfxd = 1U; } sp = tp; } else { dt_make_t_only(&res, DT_HMS); } out: /* res.typ coincides with DT_SANDWICH_D_ONLY() if we jumped here */ if (ep != NULL) { *ep = (char*)sp; } return res; } DEFUN int __strpdt_card(struct strpdt_s *d, const char *sp, struct dt_spec_s s, char **ep) { int res = 0; switch (s.spfl) { default: case DT_SPFL_UNK: res = -1; break; case DT_SPFL_N_DSTD: case DT_SPFL_N_YEAR: case DT_SPFL_N_MON: case DT_SPFL_N_DCNT_MON: case DT_SPFL_N_DCNT_WEEK: case DT_SPFL_N_DCNT_YEAR: case DT_SPFL_N_WCNT_MON: case DT_SPFL_N_WCNT_YEAR: case DT_SPFL_S_WDAY: case DT_SPFL_S_MON: case DT_SPFL_S_QTR: case DT_SPFL_N_QTR: res = __strpd_card(&d->sd, sp, s, ep); goto out_direct; case DT_SPFL_N_TSTD: case DT_SPFL_N_HOUR: case DT_SPFL_N_MIN: case DT_SPFL_N_SEC: case DT_SPFL_N_NANO: case DT_SPFL_S_AMPM: res = __strpt_card(&d->st, sp, s, ep); goto out_direct; case DT_SPFL_N_EPOCH: /* read over @ */ if (UNLIKELY(*sp == '@')) { sp++; } d->i = strtoi(sp, &sp); break; case DT_SPFL_N_ZDIFF: { const char *tp; if ((d->zdiff = try_zone(sp, &tp)) || tp > sp) { d->zngvn = 1; } sp = tp; break; } case DT_SPFL_LIT_PERCENT: if (*sp++ != '%') { res = -1; } break; case DT_SPFL_LIT_TAB: if (*sp++ != '\t') { res = -1; } break; case DT_SPFL_LIT_NL: if (*sp++ != '\n') { res = -1; } break; } /* assign end pointer */ if (ep != NULL) { *ep = (char*)sp; } out_direct: return res; } DEFUN size_t __strfdt_card( char *buf, size_t bsz, struct dt_spec_s s, struct strpdt_s *d, struct dt_dt_s that) { size_t res = 0; switch (s.spfl) { default: case DT_SPFL_UNK: break; case DT_SPFL_N_DSTD: case DT_SPFL_N_YEAR: case DT_SPFL_N_MON: case DT_SPFL_N_DCNT_WEEK: case DT_SPFL_N_DCNT_MON: case DT_SPFL_N_DCNT_YEAR: case DT_SPFL_N_WCNT_MON: case DT_SPFL_N_WCNT_YEAR: case DT_SPFL_S_WDAY: case DT_SPFL_S_MON: case DT_SPFL_S_QTR: case DT_SPFL_N_QTR: res = __strfd_card(buf, bsz, s, &d->sd, that.d); break; case DT_SPFL_N_TSTD: case DT_SPFL_N_HOUR: case DT_SPFL_N_MIN: case DT_SPFL_N_SEC: case DT_SPFL_S_AMPM: case DT_SPFL_N_NANO: res = __strft_card(buf, bsz, s, &d->st, that.t); break; case DT_SPFL_N_EPOCH: { /* convert to sexy */ int64_t sexy = dt_conv_to_sexy(that).sexy; res = snprintf(buf, bsz, "%" PRIi64, sexy); break; } case DT_SPFL_N_ZDIFF: { int32_t z = d->zdiff; char sign = '+'; if (z < 0) { z = -z; sign = '-'; } res = snprintf( buf, bsz, "%c%02u:%02u", sign, (uint32_t)z / 3600U, ((uint32_t)z / 60U) % 60U); break; } case DT_SPFL_LIT_PERCENT: /* literal % */ buf[res++] = '%'; break; case DT_SPFL_LIT_TAB: /* literal tab */ buf[res++] = '\t'; break; case DT_SPFL_LIT_NL: /* literal \n */ buf[res++] = '\n'; break; } return res; } DEFUN size_t __strfdt_dur( char *buf, size_t bsz, struct dt_spec_s s, struct strpdt_s *d, struct dt_dt_s that) { switch (s.spfl) { default: case DT_SPFL_UNK: return 0; case DT_SPFL_N_DSTD: case DT_SPFL_N_YEAR: case DT_SPFL_N_MON: case DT_SPFL_N_DCNT_WEEK: case DT_SPFL_N_DCNT_MON: case DT_SPFL_N_DCNT_YEAR: case DT_SPFL_N_WCNT_MON: case DT_SPFL_N_WCNT_YEAR: case DT_SPFL_S_WDAY: case DT_SPFL_S_MON: case DT_SPFL_S_QTR: case DT_SPFL_N_QTR: return __strfd_dur(buf, bsz, s, &d->sd, that.d); /* noone's ever bothered doing the same thing for times */ case DT_SPFL_N_TSTD: case DT_SPFL_N_SEC: if (that.typ == DT_SEXY) { /* use the sexy slot */ int64_t dur = that.sexydur; return (size_t)snprintf(buf, bsz, "%" PRIi64 "s", dur); } else { /* replace me!!! */ int32_t dur = that.t.sdur; return (size_t)snprintf(buf, bsz, "%" PRIi32 "s", dur); } case DT_SPFL_LIT_PERCENT: /* literal % */ *buf = '%'; break; case DT_SPFL_LIT_TAB: /* literal tab */ *buf = '\t'; break; case DT_SPFL_LIT_NL: /* literal \n */ *buf = '\n'; break; } return 1; } static size_t __strfdt_xdn(char *buf, size_t bsz, struct dt_dt_s that) { double dn; switch (that.d.typ) { case DT_JDN: dn = (double)that.d.jdn; break; case DT_LDN: dn = (double)that.d.ldn; if (dt_sandwich_only_d_p(that)) { return snprintf(buf, bsz, "%.0f", dn); } break; default: return 0; } if (dt_sandwich_p(that)) { unsigned int ss = __secs_since_midnight(that.t); dn += (double)ss / (double)SECS_PER_DAY; } return snprintf(buf, bsz, "%.6f", dn); } #endif /* INCLUDED_dt_core_strpf_c_ */ dateutils-0.3.1/lib/dt-core-strpf.h000066400000000000000000000053161241477753400171440ustar00rootroot00000000000000/*** dt-core-strpf.h -- parser and formatter funs for dt-core * * Copyright (C) 2011-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ #if !defined INCLUDED_dt_core_strpf_h_ #define INCLUDED_dt_core_strpf_h_ #if defined __cplusplus extern "C" { #endif /* __cplusplus */ /* helpers */ static inline __attribute__((pure, const)) struct strpdt_s strpdt_initialiser(void) { #if defined HAVE_SLOPPY_STRUCTS_INIT static const struct strpdt_s res = {}; #else static const struct strpdt_s res; #endif /* HAVE_SLOPPY_STRUCTS_INIT */ return res; } #if defined INCLUDED_dt_core_h_ /** * Parse STR with the standard parser, put the end of the parsed string in EP.*/ extern struct dt_dt_s __strpdt_std(const char *str, char **ep); #endif /* INCLUDED_dt_core_h_ */ /* self-explanatory funs, innit? */ extern int __strpdt_card(struct strpdt_s*, const char *sp, struct dt_spec_s s, char **ep); extern size_t __strfdt_card( char *buf, size_t bsz, struct dt_spec_s s, struct strpdt_s *d, struct dt_dt_s that); extern size_t __strfdt_dur( char *buf, size_t bsz, struct dt_spec_s s, struct strpdt_s *d, struct dt_dt_s that); #if defined __cplusplus } #endif /* __cplusplus */ #endif /* INCLUDED_dt_core_strpf_h_ */ dateutils-0.3.1/lib/dt-core-tz-glue.c000066400000000000000000000072501241477753400173670ustar00rootroot00000000000000/*** dt-core-tz-glue.c -- gluing date/times and tzs * * Copyright (C) 2012-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ /* dt-core-tz-glue.h implementation */ #if !defined INCLUDED_dt_core_tz_glue_c_ #define INCLUDED_dt_core_tz_glue_c_ #if defined HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include "nifty.h" #include "dt-core-tz-glue.h" #if !defined DEFUN # define DEFUN #endif /* !DEFUN */ /** * Return a dt object that forgot about DT's zone and uses ZONE instead. */ DEFUN struct dt_dt_s dtz_forgetz(struct dt_dt_s d, zif_t zone) { dt_ssexy_t d_unix; dt_ssexy_t d_locl; int32_t zdiff; if (dt_sandwich_only_d_p(d) || dt_sandwich_only_t_p(d)) { return d; } else if (d.znfxd) { /* already forgotten about */ return d; } /* convert date/time part to unix stamp */ d_locl = dt_to_unix_epoch(d); d_unix = zif_utc_time(zone, d_locl); if (LIKELY((zdiff = d_unix - d_locl))) { /* let dt_dtadd() do the magic */ struct dt_dt_s zd = dt_dt_initialiser(); dt_make_t_only(&zd, DT_HMS); zd.t.dur = 1; zd.t.sdur = zdiff; d = dt_dtadd(d, zd); d.znfxd = 1; if (zdiff > 0) { d.neg = 1; d.zdiff = (uint16_t)(zdiff / ZDIFF_RES); } else if (zdiff < 0) { d.zdiff = (uint16_t)(-zdiff / ZDIFF_RES); } } return d; } /** * Return a dt object from a UTC'd DT that uses ZONE. */ DEFUN struct dt_dt_s dtz_enrichz(struct dt_dt_s d, zif_t zone) { dt_ssexy_t d_unix; dt_ssexy_t d_locl; int32_t zdiff; if (dt_sandwich_only_d_p(d) || dt_sandwich_only_t_p(d)) { return d; } /* convert date/time part to unix stamp */ d_unix = dt_to_unix_epoch(d); d_locl = zif_local_time(zone, d_unix); if (LIKELY((zdiff = d_locl - d_unix))) { /* let dt_dtadd() do the magic */ struct dt_dt_s zd = dt_dt_initialiser(); dt_make_t_only(&zd, DT_HMS); zd.t.dur = 1; zd.t.sdur = zdiff; d = dt_dtadd(d, zd); if (zdiff > 0) { d.zdiff = (uint16_t)(zdiff / ZDIFF_RES); } else if (zdiff < 0) { d.neg = 1; d.zdiff = (uint16_t)(-zdiff / ZDIFF_RES); } } else { /* no difference to UTC means the offset is +00:00 */ d.zdiff = 0U; d.neg = 0U; } return d; } #endif /* INCLUDED_dt_core_tz_glue_c_ */ /* dt-core-tz-glue.c ends here */ dateutils-0.3.1/lib/dt-core-tz-glue.h000066400000000000000000000045671241477753400174040ustar00rootroot00000000000000/*** dt-core-tz-glue.h -- glue between tzraw and dt-core * * Copyright (C) 2012-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ #if !defined INCLUDED_dt_core_tz_glue_h_ #define INCLUDED_dt_core_tz_glue_h_ /* include the guys we need gluing, innit */ #include "dt-core.h" #include "tzraw.h" #if defined __cplusplus extern "C" { #endif /* __cplusplus */ /* decls */ /** * Return a dt object that forgot about DT's zone and uses ZONE instead. * In other words: convert from locally represented DT to UTC. */ extern struct dt_dt_s dtz_forgetz(struct dt_dt_s dt, zif_t zone); /** * Return a dt object from a UTC'd DT that uses ZONE. * In other words: convert from UTC represented DT to local ZONE time. */ extern struct dt_dt_s dtz_enrichz(struct dt_dt_s dt, zif_t zone); #if defined __cplusplus } #endif /* __cplusplus */ #endif /* INCLUDED_dt_core_tz_glue_h_ */ dateutils-0.3.1/lib/dt-core.c000066400000000000000000001111351241477753400160000ustar00rootroot00000000000000/*** dt-core.c -- our universe of datetimes * * Copyright (C) 2011-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ /* implementation part of dt-core.h */ #if !defined INCLUDED_dt_core_c_ #define INCLUDED_dt_core_c_ #if defined HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include "date-core.h" #include "time-core.h" #include "strops.h" #include "leaps.h" #include "nifty.h" #include "dt-core.h" #include "dt-core-private.h" #include "date-core.h" #include "date-core-private.h" #include "time-core.h" #include "time-core-private.h" /* parsers and formatters */ #include "date-core-strpf.h" #include "time-core-strpf.h" #if defined SKIP_LEAP_ARITH # undef WITH_LEAP_SECONDS #endif /* SKIP_LEAP_ARITH */ #if defined WITH_LEAP_SECONDS # include "leapseconds.h" #endif /* WITH_LEAP_SECONDS */ #if defined __INTEL_COMPILER /* we MUST return a char* */ # pragma warning (disable:2203) #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wcast-qual" #endif /* __INTEL_COMPILER */ #if !defined DEFUN # define DEFUN #endif /* !DEFUN */ struct strpdt_s { struct strpd_s sd; struct strpt_s st; long int i; /* use 31 bits for the difference */ int32_t zdiff:31; /* and 1 to indicate if it was specified */ int32_t zngvn:1; }; /* used for arithmetic */ struct strpdti_s { signed int m; signed int d; signed int w; signed int b; signed int S; }; /* converters and stuff */ #if !defined DT_DAISY_BASE_YEAR # error daisy base year cannot be obtained #elif DT_DAISY_BASE_YEAR == 1917 # define DAISY_UNIX_BASE (19359L) # define DAISY_GPS_BASE (23016L) #elif DT_DAISY_BASE_YEAR == 1753 # define DAISY_UNIX_BASE (79258L) # define DAISY_GPS_BASE (82915L) #elif DT_DAISY_BASE_YEAR == 1601 # define DAISY_UNIX_BASE (134775L) # define DAISY_GPS_BASE (138432L) #else # error unknown daisy base year #endif /* DT_DAISY_BASE_YEAR */ #if DAISY_GPS_BASE - DAISY_UNIX_BASE != 3657L # error daisy unix and gps bases diverge #endif /* static assert */ static inline dt_ssexy_t __to_unix_epoch(struct dt_dt_s dt) { /* daisy is competing with the prevalent unix epoch, this is the offset */ if (dt.typ == DT_SEXY) { /* no way to find out, is there */ return dt.sexy; } else if (dt_sandwich_p(dt) || dt_sandwich_only_d_p(dt)) { dt_daisy_t d = dt_conv_to_daisy(dt.d); dt_ssexy_t res = (d - DAISY_UNIX_BASE) * SECS_PER_DAY; if (dt_sandwich_p(dt)) { res += (dt.t.hms.h * 60 + dt.t.hms.m) * 60 + dt.t.hms.s; } return res; } return 0; } /* public version */ dt_ssexy_t dt_to_unix_epoch(struct dt_dt_s dt) { return __to_unix_epoch(dt); } static inline dt_ssexy_t __to_gps_epoch(struct dt_dt_s dt) { if (dt.typ == DT_SEXY) { /* no way to find out, is there */ return dt.sexy; } else if (dt_sandwich_p(dt) || dt_sandwich_only_d_p(dt)) { dt_daisy_t d = dt_conv_to_daisy(dt.d); dt_ssexy_t res = (d - DAISY_GPS_BASE) * SECS_PER_DAY; if (dt_sandwich_p(dt)) { res += (dt.t.hms.h * 60 + dt.t.hms.m) * 60 + dt.t.hms.s; } return res; } return 0; } /* public version */ dt_ssexy_t dt_to_gps_epoch(struct dt_dt_s dt) { return __to_gps_epoch(dt); } static inline struct dt_dt_s dt_conv_to_sexy(struct dt_dt_s dt) { if (dt.typ == DT_SEXY) { return dt; } else if (dt_sandwich_only_t_p(dt)) { dt.sxepoch = (dt.t.hms.h * 60 + dt.t.hms.m) * 60 + dt.t.hms.s; } else if (dt_sandwich_p(dt) || dt_sandwich_only_d_p(dt)) { dt.sxepoch = __to_unix_epoch(dt); } else { dt = dt_dt_initialiser(); } /* make sure we hand out sexies */ dt.typ = DT_SEXY; return dt; } static inline struct dt_dt_s __sexy_to_daisy(dt_ssexy_t sx) { struct dt_dt_s res = dt_dt_initialiser(); res.t.hms.s = sx % SECS_PER_MIN; sx /= SECS_PER_MIN; res.t.hms.m = sx % MINS_PER_HOUR; sx /= MINS_PER_HOUR; res.t.hms.h = sx % HOURS_PER_DAY; sx /= HOURS_PER_DAY; /* rest is a day-count, move to daisy */ res.d.daisy = sx + DAISY_UNIX_BASE; /* sandwichify */ dt_make_sandwich(&res, DT_DAISY, DT_HMS); return res; } static inline struct dt_dt_s __ymdhms_to_ymd(dt_ymdhms_t x) { struct dt_dt_s res = dt_dt_initialiser(); res.t.hms.s = x.S; res.t.hms.m = x.M; res.t.hms.h = x.H; /* rest is a day-count, move to daisy */ res.d.ymd.y = x.y; res.d.ymd.m = x.m; res.d.ymd.d = x.d; /* sandwichify */ dt_make_sandwich(&res, DT_YMD, DT_HMS); return res; } static inline __attribute__((unused)) struct dt_dt_s __epoch_to_ymd_sandwich(dt_ssexy_t sx) { struct dt_dt_s res; res.t.hms.s = sx % SECS_PER_MIN; sx /= SECS_PER_MIN; res.t.hms.m = sx % MINS_PER_HOUR; sx /= MINS_PER_HOUR; res.t.hms.h = sx % HOURS_PER_DAY; sx /= HOURS_PER_DAY; res.d.ymd = __daisy_to_ymd(sx + DAISY_UNIX_BASE); dt_make_sandwich(&res, DT_YMD, DT_HMS); return res; } static inline dt_sexy_t __sexy_add(dt_sexy_t sx, struct dt_dt_s dur) { /* sexy add * only works for continuous types (DAISY, etc.) * we need to take leap seconds into account here */ signed int delta = 0; switch (dur.d.typ) { case DT_SEXY: case DT_SEXYTAI: delta = dur.sexydur; break; case DT_DAISY: delta = dur.d.daisydur * SECS_PER_DAY; case DT_DUNK: delta += dur.t.sdur; default: break; } /* just go through with it */ return sx + delta; } #if defined WITH_LEAP_SECONDS && defined SKIP_LEAP_ARITH #error "bugger" #endif /* guessing parsers */ #include "token.h" #include "strops.h" #if defined WITH_LEAP_SECONDS && defined SKIP_LEAP_ARITH #error "bugger" #endif #include "dt-core-strpf.c" static const char ymdhms_dflt[] = "%FT%T"; static const char ymcwhms_dflt[] = "%Y-%m-%c-%wT%T"; static const char ywdhms_dflt[] = "%rY-W%V-%uT%T"; static const char ydhms_dflt[] = "%Y-%d"; static const char daisyhms_dflt[] = "%dT%T"; static const char sexy_dflt[] = "%s"; static const char bizsihms_dflt[] = "%dbT%T"; static const char bizdahms_dflt[] = "%Y-%m-%dbT%T"; static const char ymdhmsdur_dflt[] = "%0Y-%0m-%0dT%0H:%0M:%0S"; static const char ymcwhmsdur_dflt[] = "%Y-%0m-%0w-%0dT%0H:%0M:%0S"; static const char ywdhmsdur_dflt[] = "%rY-W%0w-%0dT%0H:%0M:%0S"; static const char ydhmsdur_dflt[] = "%Y-%0dT%0H:%0M:%0S"; static const char daisyhmsdur_dflt[] = "%dT%0H:%0M:%0S"; static const char sexydur_dflt[] = "%s"; static const char bizsihmsdur_dflt[] = "%dbT%0H:%0M:%0S"; static const char bizdahmsdur_dflt[] = "%Y-%0m-%0dbT%0H:%0M:%0S"; DEFUN dt_dttyp_t __trans_dtfmt(const char **fmt) { if (UNLIKELY(*fmt == NULL)) { /* um, great */ ; } else if (LIKELY(**fmt == '%')) { /* don't worry about it */ ; } else { const dt_dtyp_t tmp = __trans_dfmt_special(*fmt); /* thanks gcc for making me cast this :( */ switch ((unsigned int)tmp) { default: break; case DT_YMD: *fmt = ymdhms_dflt; break; case DT_YMCW: *fmt = ymcwhms_dflt; break; case DT_BIZDA: *fmt = bizdahms_dflt; break; case DT_DAISY: *fmt = daisyhms_dflt; break; case DT_SEXY: *fmt = sexy_dflt; break; case DT_BIZSI: *fmt = bizsihms_dflt; break; case DT_YWD: *fmt = ywdhms_dflt; break; case DT_YD: *fmt = ydhms_dflt; break; } return (dt_dttyp_t)tmp; } return (dt_dttyp_t)DT_DUNK; } DEFUN dt_dttyp_t __trans_dtdurfmt(const char **fmt) { if (UNLIKELY(*fmt == NULL)) { /* um, great */ ; } else if (LIKELY(**fmt == '%')) { /* don't worry about it */ ; } else { const dt_dtyp_t tmp = __trans_dfmt_special(*fmt); /* thanks gcc for making me cast this :( */ switch ((unsigned int)tmp) { default: break; case DT_YMD: *fmt = ymdhmsdur_dflt; break; case DT_YMCW: *fmt = ymcwhmsdur_dflt; break; case DT_BIZDA: *fmt = bizdahmsdur_dflt; break; case DT_DAISY: *fmt = daisyhmsdur_dflt; break; case DT_SEXY: *fmt = sexydur_dflt; break; case DT_BIZSI: *fmt = bizsihmsdur_dflt; break; case DT_YWD: *fmt = ywdhmsdur_dflt; break; case DT_YD: *fmt = ydhmsdur_dflt; break; } return (dt_dttyp_t)tmp; } return (dt_dttyp_t)DT_DUNK; } #define FFFF_GMTIME_SUBDAY #include "gmtime.h" static struct timeval now_tv(void) { /* singleton, gives a consistent `now' throughout the whole run */ static struct timeval tv; if (LIKELY(tv.tv_sec)) { /* perfect */ ; } else if (gettimeofday(&tv, NULL) < 0) { /* big cinema :( */ tv = (struct timeval){0U, 0U}; } return tv; } static struct tm now_tm(void) { /* singleton, gives a consistent `now' throughout the whole run */ static struct tm tm; struct timeval tv; if (LIKELY(tm.tm_year)) { /* sit back and relax */ ; } else if ((tv = now_tv()).tv_sec == 0U) { /* big cinema :( */ #if defined HAVE_SLOPPY_STRUCTS_INIT return (struct tm){}; #else /* !HAVE_SLOPPY_STRUCTS_INIT */ memset(&tm, 0, sizeof(tm)); #endif /* HAVE_SLOPPY_STRUCTS_INIT */ } else { ffff_gmtime(&tm, tv.tv_sec); } return tm; } static struct tm dflt_tm(const struct dt_dt_s *set) { /* getter/setter and singleton for SET == NULL */ static struct tm tm; if (LIKELY(set == NULL && tm.tm_year != 0U)) { /* show what we've got */ ; } else if (set == NULL) { /* take over the value of now */ tm = now_tm(); } else { switch (set->typ) { case DT_YMD: tm.tm_year = set->d.ymd.y; tm.tm_mon = set->d.ymd.m; tm.tm_mday = set->d.ymd.d; tm.tm_hour = set->t.hms.h; tm.tm_min = set->t.hms.m; tm.tm_sec = set->t.hms.s; break; default: /* good question */ #if defined HAVE_SLOPPY_STRUCTS_INIT return (struct tm){}; #else /* !HAVE_SLOPPY_STRUCTS_INIT */ memset(&tm, 0, sizeof(tm)); break; #endif /* HAVE_SLOPPY_STRUCTS_INIT */ } } return tm; } static struct strpdt_s massage_strpdt(struct strpdt_s d) { /* the reason we do this separately is that we don't want to bother * the pieces of code that use the guesser for different reasons */ if (UNLIKELY(d.sd.y == 0U)) { #if defined HAVE_SLOPPY_STRUCTS_INIT static const struct strpd_s d0 = {}; #else /* !HAVE_SLOPPY_STRUCTS_INIT */ static const struct strpd_s d0; #endif /* HAVE_SLOPPY_STRUCTS_INIT */ struct tm now = dflt_tm(NULL); if (UNLIKELY(memcmp(&d.sd, &d0, sizeof(d0)) == 0U)) { goto msgg_time; } d.sd.y = now.tm_year; if (LIKELY(d.sd.m)) { goto out; } d.sd.m = now.tm_mon; if (LIKELY(d.sd.d)) { goto out; } d.sd.d = now.tm_mday; msgg_time: /* same for time values, but obtain those through now_tv() */ if (UNLIKELY(!d.st.flags.h_set)) { d.st.h = now.tm_hour; if (LIKELY(d.st.flags.m_set)) { goto out; } d.st.m = now.tm_min; if (LIKELY(d.st.flags.s_set)) { goto out; } d.st.s = now.tm_sec; } } out: return d; } #if defined WITH_LEAP_SECONDS static zidx_t leaps_before(struct dt_dt_s d) { zidx_t res; bool on; switch (d.typ) { case DT_YMD: res = leaps_before_ui32(leaps_ymd, nleaps, d.d.ymd.u); on = res + 1 < nleaps && leaps_ymd[res + 1] == d.d.ymd.u; break; case DT_YMCW: res = leaps_before_ui32(leaps_ymcw, nleaps, d.d.ymcw.u); on = res + 1 < nleaps && leaps_ymcw[res + 1] == d.d.ymcw.u; break; case DT_DAISY: res = leaps_before_ui32(leaps_d, nleaps, d.d.daisy); on = res + 1 < nleaps && leaps_d[res + 1] == d.d.daisy; break; case DT_SEXY: case DT_SEXYTAI: res = leaps_before_si32(leaps_s, nleaps, (int32_t)d.sexy); on = (res + 1U < nleaps) && (leaps_s[res + 1] == (int32_t)d.sexy); break; default: res = 0; on = false; break; } /* clang 3.3 will fuck the following up * see http://llvm.org/bugs/show_bug.cgi?id=18028 * we have to access d.t.hms.u24 once (the failing access), * then again and magically it'll work, thanks a bunch clang! */ if (dt_sandwich_p(d) && on) { #if defined __clang__ && __clang_major__ == 3 && __clang_minor__ >= 3 # warning clang bug! \ see http://llvm.org/bugs/show_bug.cgi?id=18028 /* access d.t.hms.u24 once */ volatile unsigned int hms = d.t.hms.u24; /* check the time part too */ if ((hms & 0xffffffU) > leaps_hms[res + 1]) { res++; } #else /* !__clang__ 3.3 */ /* check the time part too */ if (d.t.hms.u24 > leaps_hms[res + 1]) { res++; } #endif /* __clang__ 3.3 */ } return res; } #endif /* WITH_LEAP_SECONDS */ static inline int32_t zdiff_sec(struct dt_dt_s d) { /* obtain zdiff in signed seconds, instead of absolute ZDIFF_RES multiples */ int32_t zdiff = d.zdiff * ZDIFF_RES; if (d.neg) { zdiff = -zdiff; } return zdiff; } /* parser implementations */ DEFUN struct dt_dt_s dt_strpdt(const char *str, const char *fmt, char **ep) { struct dt_dt_s res = dt_dt_initialiser(); struct strpdt_s d; const char *sp = str; const char *fp; if (LIKELY(fmt == NULL)) { return __strpdt_std(str, ep); } /* translate high-level format names, for sandwiches */ switch ((dt_dtyp_t)__trans_dtfmt(&fmt)) { char *on; default: break; /* special case julian/lilian dates as they have * no format specifiers */ case DT_JDN: res.d.jdn = (dt_jdn_t)strtod(str, &on); /* fix up const-ness problem */ sp = on; /* don't worry about time slot or date/time sandwiches */ dt_make_d_only(&res, DT_JDN); goto sober; case DT_LDN: res.d.ldn = (dt_ldn_t)strtoi(str, &sp); if (*sp != '.') { dt_make_d_only(&res, DT_LDN); } else { /* yes, big cluster fuck */ double tmp = strtod(sp, &on); /* fix up const-ness problem */ sp = on; /* convert to HMS */ res.t.hms.h = (tmp *= HOURS_PER_DAY); tmp -= (double)res.t.hms.h; res.t.hms.m = (tmp *= MINS_PER_HOUR); tmp -= (double)res.t.hms.m; res.t.hms.s = (tmp *= SECS_PER_MIN); tmp -= (double)res.t.hms.s; res.t.hms.ns = (tmp *= NANOS_PER_SEC); dt_make_sandwich(&res, DT_LDN, DT_HMS); } goto sober; } fp = fmt; d = strpdt_initialiser(); while (*fp && *sp) { const char *fp_sav = fp; struct dt_spec_s spec = __tok_spec(fp_sav, &fp); if (spec.spfl == DT_SPFL_UNK) { /* must be literal */ if (*fp_sav != *sp++) { goto fucked; } } else if (LIKELY(!spec.rom)) { const char *sp_sav = sp; if (__strpdt_card(&d, sp, spec, (char**)&sp) < 0) { goto fucked; } if (spec.ord && __ordinalp(sp_sav, sp - sp_sav, (char**)&sp) < 0) { ; } if (spec.bizda) { switch (*sp++) { case 'B': d.sd.flags.ab = BIZDA_BEFORE; case 'b': d.sd.flags.bizda = 1; break; default: /* it's a bizda anyway */ d.sd.flags.bizda = 1; sp--; break; } } } else if (UNLIKELY(spec.rom)) { if (__strpd_rom(&d.sd, sp, spec, (char**)&sp) < 0) { goto fucked; } } } /* check suffix literal */ if (*fp && *fp != *sp) { goto fucked; } /* check if it's a sexy type */ if (d.i) { res.typ = DT_SEXY; res.sexy = d.i; } else { /* assign d and t types using date and time core routines */ d = massage_strpdt(d); res.d = __guess_dtyp(d.sd); res.t = __guess_ttyp(d.st); if (res.d.typ > DT_DUNK && res.t.typ > DT_TUNK) { res.sandwich = 1; } else if (res.d.typ > DT_DUNK) { res.t.typ = DT_TUNK; res.sandwich = 0; } else if (res.t.typ > DT_TUNK) { res.d.typ = DT_DUNK; res.sandwich = 1; } } if (d.zdiff && dt_sandwich_p(res)) { res = __fixup_zdiff(res, d.zdiff); } else if (d.zngvn && dt_sandwich_p(res)) { res.znfxd = 1; } sober: /* set the end pointer */ if (ep != NULL) { *ep = (char*)sp; } return res; fucked: if (ep != NULL) { *ep = (char*)str; } return dt_dt_initialiser(); } DEFUN size_t dt_strfdt(char *restrict buf, size_t bsz, const char *fmt, struct dt_dt_s that) { struct strpdt_s d = strpdt_initialiser(); const char *fp; char *bp; dt_dtyp_t tgttyp; int set_fmt = 0; if (UNLIKELY(buf == NULL || bsz == 0)) { bp = buf; goto out; } if (LIKELY(fmt == NULL)) { /* um, great */ set_fmt = 1; } else if (LIKELY(*fmt == '%')) { /* don't worry about it */ ; } else if ((tgttyp = __trans_dfmt_special(fmt)) != (dt_dtyp_t)DT_UNK) { that = dt_dtconv((dt_dttyp_t)tgttyp, that); set_fmt = 1; } if (set_fmt && dt_sandwich_p(that)) { switch (that.typ) { case DT_YMD: fmt = ymdhms_dflt; break; case DT_YMCW: fmt = ymcwhms_dflt; break; case DT_YWD: fmt = ywdhms_dflt; break; case DT_DAISY: /* subject to change */ fmt = ymdhms_dflt; break; case DT_JDN: case DT_LDN: strf_xian: /* short cut, just print the guy here */ bp = buf + __strfdt_xdn(buf, bsz, that); goto out; case DT_BIZDA: fmt = bizdahms_dflt; break; case DT_SEXY: case DT_YMDHMS: fmt = ymdhms_dflt; break; default: /* fuck */ abort(); break; } } else if (set_fmt && dt_sandwich_only_d_p(that)) { switch (that.d.typ) { case DT_YMD: fmt = ymd_dflt; break; case DT_YMCW: fmt = ymcw_dflt; break; case DT_YWD: fmt = ywd_dflt; break; case DT_DAISY: /* subject to change */ fmt = ymd_dflt; break; case DT_BIZDA: fmt = bizda_dflt; break; case DT_JDN: case DT_LDN: goto strf_xian; default: /* fuck */ abort(); break; } } else if (set_fmt && that.typ >= DT_PACK && that.typ < DT_NDTTYP) { /* must be sexy or ymdhms */ fmt = ymdhms_dflt; } else if (dt_sandwich_only_t_p(that)) { /* transform time specs */ __trans_tfmt(&fmt); } /* make sure we always snarf the zdiff info */ d.zdiff = zdiff_sec(that); switch (that.typ) { case DT_YMD: ymd_prep: d.sd.y = that.d.ymd.y; d.sd.m = that.d.ymd.m; d.sd.d = that.d.ymd.d; break; case DT_YMCW: d.sd.y = that.d.ymcw.y; d.sd.m = that.d.ymcw.m; d.sd.c = that.d.ymcw.c; d.sd.w = that.d.ymcw.w; break; case DT_YWD: __prep_strfd_ywd(&d.sd, that.d.ywd); break; case DT_JDN: that = dt_dtconv((dt_dttyp_t)DT_DAISY, that); goto daisy_prep; case DT_LDN: that = dt_dtconv((dt_dttyp_t)DT_DAISY, that); /* FALLTHROUGH */ case DT_DAISY: daisy_prep: __prep_strfd_daisy(&d.sd, that.d.daisy); break; case DT_BIZDA: __prep_strfd_bizda( &d.sd, that.d.bizda, __get_bizda_param(that.d)); break; case DT_SEXY: /* instead of leaving this as SEXY turn it into * DAISY/HMS sandwich */ that = dt_dtconv((dt_dttyp_t)DT_DAISY, that); /* prep d.sd */ goto daisy_prep; case DT_YMDHMS: /* convert this to a YMD/HMS sandwich */ that = dt_dtconv((dt_dttyp_t)DT_YMD, that); /* prep d.sd */ goto ymd_prep; default: case DT_DUNK: if (!dt_sandwich_only_t_p(that)) { bp = buf; goto out; } } if (dt_sandwich_p(that) || dt_sandwich_only_t_p(that)) { /* cope with the time part */ d.st.h = that.t.hms.h; d.st.m = that.t.hms.m; d.st.s = that.t.hms.s; d.st.ns = that.t.hms.ns; } /* assign and go */ bp = buf; fp = fmt; for (char *const eo = buf + bsz; *fp && bp < eo;) { const char *fp_sav = fp; struct dt_spec_s spec = __tok_spec(fp_sav, &fp); if (spec.spfl == DT_SPFL_UNK) { /* must be literal then */ *bp++ = *fp_sav; } else if (LIKELY(!spec.rom)) { bp += __strfdt_card(bp, eo - bp, spec, &d, that); if (spec.ord) { bp += __ordtostr(bp, eo - bp); } else if (spec.bizda) { /* don't print the b after an ordinal */ if (spec.ab == BIZDA_AFTER) { *bp++ = 'b'; } else { *bp++ = 'B'; } } } else if (UNLIKELY(spec.rom)) { bp += __strfd_rom(bp, eo - bp, spec, &d.sd, that.d); } } out: if (bp < buf + bsz) { *bp = '\0'; } return bp - buf; } DEFUN struct dt_dt_s dt_strpdtdur(const char *str, char **ep) { /* at the moment we allow only one format */ struct dt_dt_s res = dt_dt_initialiser(); const char *sp; long int tmp; struct strpdt_s d; if ((sp = str) == NULL) { goto out; } /* read just one component, use rudi's errno trick */ errno = 0; if ((tmp = strtol(str, (char**)&sp, 10)) == 0 && str == sp) { /* didn't work aye? */ goto out; } else if (tmp > INT_MAX || errno) { errno = ERANGE; goto out; } d = strpdt_initialiser(); sp: switch (*sp++) { case '\0': /* must have been day then */ d.sd.d = tmp; sp--; break; case 'd': case 'D': d.sd.d = tmp; break; case 'y': case 'Y': d.sd.y = tmp; break; case 'm': case 'M': d.sd.m = tmp; if (*sp == 'o') { /* that makes it unique */ sp++; break; } case '\'': /* could stand for minute, so just to be sure ... */ d.st.m = tmp; break; case 'w': case 'W': d.sd.w = tmp; break; case 'b': case 'B': d.sd.b = tmp; break; case 'q': case 'Q': d.sd.q = tmp; break; case 'h': case 'H': d.st.h = tmp; break; case 's': case 'S': case '"': /* could also stand for second, so update this as well */ d.st.s = tmp; break; case 'r': /* real seconds */ res.tai = 1; goto sp; case 'n': d.st.ns = tmp; if (*sp == 's') { /* nanoseconds, my favourite */ sp++; } break; default: sp = str; goto out; } /* assess */ if (d.sd.b && (d.sd.m || d.sd.y)) { res.d.typ = DT_BIZDA; res.d.bizda.y = d.sd.y; res.d.bizda.m = d.sd.q * 3 + d.sd.m; res.d.bizda.bd = d.sd.b + d.sd.w * 5; } else if (d.sd.y || (d.sd.m && !d.st.m)) { dflt: res.d.typ = DT_YMD; res.d.ymd.y = d.sd.y; res.d.ymd.m = d.sd.q * 3 + d.sd.m; res.d.ymd.d = d.sd.d + d.sd.w * 7; } else if (d.sd.b) { res.d.typ = DT_BIZSI; res.d.bizsi = d.sd.w * 5 + d.sd.b; } else if (d.sd.d || d.sd.w) { res.d.typ = DT_DAISY; res.d.daisy = d.sd.w * 7 + d.sd.d; /* time specs here */ } else if (d.st.h || d.st.m || d.st.s || d.st.ns) { /* treat as m for minute */ dt_make_t_only(&res, DT_HMS); res.t.dur = 1; res.t.nsdur = d.st.ns; res.t.sdur = d.st.h * SECS_PER_HOUR + d.st.m * SECS_PER_MIN + d.st.s; /* but also put the a note in the md slot */ if (!d.st.h && !d.st.s && d.sd.m) { res.d.md.m = d.sd.m; } } else { /* we leave out YMCW diffs simply because YMD diffs * cover them better */ goto dflt; } out: if (ep != NULL) { *ep = (char*)sp; } res.dur = 1; return res; } DEFUN size_t dt_strfdtdur( char *restrict buf, size_t bsz, const char *fmt, struct dt_dt_s that) { struct strpdt_s d; const char *fp; char *bp; if (UNLIKELY(buf == NULL || bsz == 0)) { bp = buf; goto out; } d = strpdt_initialiser(); switch (that.d.typ) { case DT_YMD: d.sd.y = that.d.ymd.y; d.sd.m = that.d.ymd.m; d.sd.d = that.d.ymd.d; if (fmt == NULL && dt_sandwich_p(that)) { fmt = ymdhmsdur_dflt; } else if (fmt == NULL && dt_sandwich_only_d_p(that)) { fmt = ymddur_dflt; } else if (fmt == NULL) { goto try_time; } break; case DT_YMCW: d.sd.y = that.d.ymcw.y; d.sd.m = that.d.ymcw.m; d.sd.c = that.d.ymcw.c; d.sd.d = that.d.ymcw.w; if (fmt == NULL && dt_sandwich_p(that)) { fmt = ymcwhmsdur_dflt; } else if (fmt == NULL && dt_sandwich_only_d_p(that)) { fmt = ymcwdur_dflt; } else if (fmt == NULL) { goto try_time; } break; case DT_YWD: d.sd.y = that.d.ywd.y; d.sd.c = that.d.ywd.c; d.sd.d = that.d.ywd.w; if (fmt == NULL && dt_sandwich_p(that)) { fmt = ywdhmsdur_dflt; } else if (fmt == NULL && dt_sandwich_only_d_p(that)) { fmt = ywddur_dflt; } else if (fmt == NULL) { goto try_time; } break; case DT_YD: d.sd.y = that.d.yd.y; d.sd.d = that.d.yd.d; if (fmt == NULL && dt_sandwich_p(that)) { fmt = ydhmsdur_dflt; } else if (fmt == NULL && dt_sandwich_only_d_p(that)) { fmt = yddur_dflt; } else if (fmt == NULL) { goto try_time; } break; case DT_DAISY: d.sd.d = that.d.daisy; if (fmt == NULL && dt_sandwich_p(that)) { fmt = daisydur_dflt; } else if (fmt == NULL && dt_sandwich_only_d_p(that)) { fmt = daisydur_dflt; } else if (fmt == NULL) { goto try_time; } break; case DT_BIZSI: d.sd.d = that.d.bizsi; if (fmt == NULL && dt_sandwich_p(that)) { /* subject to change */ fmt = bizsidur_dflt; } else if (fmt == NULL && dt_sandwich_only_d_p(that)) { fmt = bizsidur_dflt; } else if (fmt == NULL) { goto try_time; } break; case DT_BIZDA: { dt_bizda_param_t bparam = __get_bizda_param(that.d); d.sd.y = that.d.bizda.y; d.sd.m = that.d.bizda.m; d.sd.b = that.d.bizda.bd; if (LIKELY(bparam.ab == BIZDA_AFTER)) { d.sd.flags.ab = BIZDA_AFTER; } else { d.sd.flags.ab = BIZDA_BEFORE; } d.sd.flags.bizda = 1; if (fmt == NULL && dt_sandwich_p(that)) { fmt = bizdahmsdur_dflt; } else if (fmt == NULL && dt_sandwich_only_d_p(that)) { fmt = bizdadur_dflt; } else if (fmt == NULL) { goto try_time; } break; } default: case DT_DUNK: break; } /* translate high-level format names */ if (dt_sandwich_p(that)) { __trans_dtdurfmt(&fmt); } else if (dt_sandwich_only_d_p(that)) { __trans_ddurfmt(&fmt); } else if (dt_sandwich_only_t_p(that)) { try_time: fmt = "%S"; } else { bp = buf; goto out; } /* assign and go */ bp = buf; fp = fmt; if (that.d.neg) { *bp++ = '-'; } for (char *const eo = buf + bsz; *fp && bp < eo;) { const char *fp_sav = fp; struct dt_spec_s spec = __tok_spec(fp_sav, &fp); if (spec.spfl == DT_SPFL_UNK) { /* must be literal then */ *bp++ = *fp_sav; } else if (LIKELY(!spec.rom)) { bp += __strfdt_dur(bp, eo - bp, spec, &d, that); if (spec.bizda) { /* don't print the b after an ordinal */ if (d.sd.flags.ab == BIZDA_AFTER) { *bp++ = 'b'; } else { *bp++ = 'B'; } } } } out: if (bp < buf + bsz) { *bp = '\0'; } return bp - buf; } DEFUN struct dt_dt_s dt_neg_dtdur(struct dt_dt_s dur) { dur.neg = (uint16_t)(~dur.neg & 0x01); dur.t.neg = (uint16_t)(~dur.t.neg & 0x01); /* treat daisy and bizsi durs specially */ switch (dur.d.typ) { case DT_DAISY: dur.d.daisydur = -dur.d.daisydur; break; case DT_BIZSI: dur.d.bizsidur = -dur.d.bizsidur; break; default: break; } /* there's just DT_SEXY as time duration type atm, negate it */ dur.t.sdur = -dur.t.sdur; return dur; } DEFUN int dt_dtdur_neg_p(struct dt_dt_s dur) { /* daisy durs and bizsi durs are special */ switch (dur.d.typ) { case DT_DAISY: return dur.d.daisydur < 0; case DT_BIZSI: return dur.d.bizsidur < 0; default: return dur.neg; } } /* date getters, platform dependent */ DEFUN struct dt_dt_s dt_datetime(dt_dttyp_t outtyp) { struct dt_dt_s res = dt_dt_initialiser(); const dt_dtyp_t outdtyp = (dt_dtyp_t)outtyp; struct tm tm = now_tm(); struct timeval tv = now_tv(); switch (outdtyp) { case DT_YMD: case DT_YMCW: switch (outdtyp) { case DT_YMD: res.d.ymd.y = tm.tm_year; res.d.ymd.m = tm.tm_mon; res.d.ymd.d = tm.tm_mday; break; case DT_YMCW: { #if defined HAVE_ANON_STRUCTS_INIT dt_ymd_t tmp = { .y = tm.tm_year, .m = tm.tm_mon, .d = tm.tm_mday, }; #else dt_ymd_t tmp; tmp.y = tm.tm_year, tmp.m = tm.tm_mon, tmp.d = tm.tm_mday, #endif res.d.ymcw.y = tm.tm_year; res.d.ymcw.m = tm.tm_mon; res.d.ymcw.c = __ymd_get_count(tmp); res.d.ymcw.w = tm.tm_wday; break; } default: /* grrrr */ ; } break; case DT_DAISY: /* time_t's base is 1970-01-01, which is daisy 19359 */ res.d.daisy = tv.tv_sec / (unsigned int)SECS_PER_DAY + DAISY_UNIX_BASE; break; case DT_MD: /* this one doesn't make sense at all */ case DT_BIZDA: case DT_BIZSI: /* could be an idea to have those, innit? */ default: case DT_DUNK: break; } /* time assignment */ if (outdtyp <= DT_NDTYP) { unsigned int tonly = tv.tv_sec % (unsigned int)SECS_PER_DAY; res.t.hms.h = tonly / SECS_PER_HOUR; tonly %= SECS_PER_HOUR; res.t.hms.m = tonly / SECS_PER_MIN; tonly %= SECS_PER_MIN; res.t.hms.s = tonly; res.t.hms.ns = tv.tv_usec * 1000; dt_make_sandwich(&res, (dt_dtyp_t)outtyp, DT_HMS); } else { /* must be one of the sexies then, aye? */ res.sexy = tv.tv_sec; } return res; } DEFUN struct dt_dt_s dt_dtconv(dt_dttyp_t tgttyp, struct dt_dt_s d) { if (dt_sandwich_p(d) || dt_sandwich_only_d_p(d)) { /* thanks gcc for making me cast tgttyp */ switch ((unsigned int)tgttyp) { short unsigned int sw; case DT_YMD: case DT_YMCW: case DT_BIZDA: case DT_DAISY: case DT_BIZSI: case DT_MD: case DT_YWD: case DT_YD: case DT_JDN: case DT_LDN: /* backup sandwich state */ sw = d.sandwich; /* convert */ d.d = dt_dconv((dt_dtyp_t)tgttyp, d.d); /* restore sandwich state */ d.sandwich = sw; break; case DT_SEXY: case DT_SEXYTAI: { dt_daisy_t dd = dt_conv_to_daisy(d.d); unsigned int ss = __secs_since_midnight(d.t); switch (tgttyp) { int32_t sx; #if defined WITH_LEAP_SECONDS case DT_SEXYTAI: { zidx_t zi; sx = (dd - DAISY_UNIX_BASE) * SECS_PER_DAY + ss; zi = leaps_before_si32(leaps_s, nleaps, sx); d.sexy = sx + leaps_corr[zi]; break; } #else /* !WITH_LEAP_SECONDS */ case DT_SEXYTAI: #endif /* WITH_LEAP_SECONDS */ case DT_SEXY: sx = (dd - DAISY_UNIX_BASE) * SECS_PER_DAY + ss; d.sexy = sx; break; default: /* grrrr */ ; } d.sandwich = 0; d.typ = tgttyp; break; } case DT_YMDHMS: /* no support for this guy yet */ case DT_DUNK: default: d = dt_dt_initialiser(); break; } } else if (dt_sandwich_only_t_p(d)) { /* ah, how good is that? */ ; } else if (!dt_separable_p(d)) { switch (d.typ) { case DT_SEXY: case DT_SEXYTAI: if (tgttyp > DT_UNK && tgttyp < DT_PACK) { /* go through daisy */ d = __sexy_to_daisy(d.sxepoch); d.d = dt_dconv((dt_dtyp_t)tgttyp, d.d); d.sandwich = 1U; } else if (tgttyp == DT_YMDHMS) { ; } break; case DT_YMDHMS: if (tgttyp > DT_UNK && tgttyp < DT_PACK) { /* go through ymd */ d = __ymdhms_to_ymd(d.ymdhms); d.d = dt_dconv((dt_dtyp_t)tgttyp, d.d); d.sandwich = 1U; } else if (tgttyp == DT_SEXY) { ; } break; default: d = dt_dt_initialiser(); break; } } else { /* great, what now? */ ; } return d; } DEFUN struct dt_dt_s dt_dtadd(struct dt_dt_s d, struct dt_dt_s dur) { /* we decompose the problem like so: * carry <- dpart(dur); * tpart(res), carry <- tadd(d, tpart(dur), corr); * res <- dadd(dpart(res), carry); */ signed int carry = 0; dt_dttyp_t typ = d.typ; #if defined WITH_LEAP_SECONDS struct dt_dt_s orig; if (UNLIKELY(dur.tai)) { /* make a copy */ orig = d; } #endif /* WITH_LEAP_SECONDS */ if (UNLIKELY(dur.t.dur && dt_sandwich_only_d_p(d))) { /* probably +/-[n]m where `m' was meant to be `mo' */ dur.d.typ = DT_MD; goto dadd; } else if (dur.t.dur && d.sandwich) { /* make sure we don't blow the carry slot */ carry = dur.t.sdur / (signed int)SECS_PER_DAY; dur.t.sdur = dur.t.sdur % (signed int)SECS_PER_DAY; /* accept both t-onlies and sandwiches */ d.t = dt_tadd(d.t, dur.t, 0); carry += d.t.carry; } else if (d.typ == DT_SEXY) { d.sexy = __sexy_add(d.sexy, dur); goto pre_corr; } /* store the carry somehow */ if (carry) { switch (dur.d.typ) { case DT_DAISY: /* just add the carry, daisydur is signed enough */ dur.d.daisydur += carry; break; case DT_DUNK: /* fiddle with DUR, so we can use date-core's adder */ dur.d.typ = DT_DAISY; /* add the carry */ dur.d.daisydur = carry; break; default: /* we're fucked */ ; } } /* demote D's and DUR's type temporarily */ if (d.typ != DT_SANDWICH_UNK && dur.d.typ != DT_DUNK) { dadd: /* let date-core do the addition */ d.d = dt_dadd(d.d, dur.d); } else if (dur.d.typ != DT_DUNK) { /* put the carry back into d's daisydur slot */ d.d.daisydur += dur.d.daisydur; } /* and promote the whole shebang again */ d.typ = typ; pre_corr: #if defined WITH_LEAP_SECONDS if (UNLIKELY(dur.tai) && d.typ != DT_SEXY) { /* the reason we omitted SEXY is because there's simply * no representation in there */ zidx_t i_orig = leaps_before(orig); zidx_t i_d = leaps_before(d); if (UNLIKELY(i_orig != i_d)) { /* insert leaps */ int nltr = leaps_corr[i_orig] - leaps_corr[i_d]; /* save a copy of d again */ orig = d; i_orig = i_d; /* reuse dur for the correction */ if ((dur.t.sdur = nltr) && /* get our special tadd with carry */ (d.t = dt_tadd(d.t, dur.t, 0), d.t.carry)) { /* great, we need to sub/add again * as there's been a wrap-around at * midnight, spooky */ dur.d.typ = DT_DAISY; dur.d.daisydur = d.t.carry; d.d = dt_dadd(d.d, dur.d); } /* check if we transitioned again */ if (d.typ == DT_SEXYTAI || (i_d = leaps_before(d), 0)) { /* don't have to */ ; } else if (UNLIKELY(i_d < i_orig)) { d.t.hms.s -= nltr; } else if (UNLIKELY(i_d > i_orig)) { d = orig; d.t.hms.s += nltr; } } } #endif /* WITH_LEAP_SECONDS */ return d; } DEFUN struct dt_dt_s dt_dtdiff(dt_dttyp_t tgttyp, struct dt_dt_s d1, struct dt_dt_s d2) { struct dt_dt_s res = dt_dt_initialiser(); if (!dt_sandwich_only_d_p(d1) && !dt_sandwich_only_d_p(d2)) { /* do the time portion difference right away */ res.t = dt_tdiff(d1.t, d2.t); } /* now assess what else is to be done */ if (dt_sandwich_only_t_p(d1) && dt_sandwich_only_t_p(d2)) { dt_make_t_only(&res, (dt_ttyp_t)DT_SEXY); } else if (tgttyp > DT_UNK && tgttyp < DT_PACK) { /* check for negative carry */ if (UNLIKELY(res.t.sdur < 0)) { d2.d = dt_dadd(d2.d, dt_make_daisydur(-1)); res.t.sdur += SECS_PER_DAY; } res.d = dt_ddiff((dt_dtyp_t)tgttyp, d1.d, d2.d); if (dt_sandwich_only_d_p(d1) || dt_sandwich_only_d_p(d2)) { dt_make_d_only(&res, (dt_dtyp_t)tgttyp); } else { dt_make_sandwich(&res, (dt_dtyp_t)tgttyp, DT_HMS); } } else if (tgttyp == DT_SEXY || tgttyp == DT_SEXYTAI) { int64_t sxdur; if (d1.typ < DT_PACK && d2.typ < DT_PACK) { /* go for tdiff and ddiff independently */ res.d = dt_ddiff(DT_DAISY, d1.d, d2.d); /* since target type is SEXY do the conversion here */ sxdur = (int64_t)res.t.sdur + (int64_t)res.d.daisydur * SECS_PER_DAY; } else { /* oh we're in the sexy domain already, * note, we can't diff ymdhms packs */ d1 = dt_dtconv(tgttyp, d1); d2 = dt_dtconv(tgttyp, d2); /* now it's fuck-easy */ sxdur = d2.sexy - d1.sexy; } /* set up the output here */ res.typ = tgttyp; res.dur = 0; res.neg = 0; res.tai = (uint16_t)(tgttyp == DT_SEXYTAI); res.sexydur = sxdur; #if defined WITH_LEAP_SECONDS if (tgttyp == DT_SEXYTAI) { /* check for transitions */ zidx_t i_d1 = leaps_before(d1); zidx_t i_d2 = leaps_before(d2); # if defined WORDS_BIGENDIAN /* not needed on little-endians * the little means just that */ res.soft = sxdur; # endif /* WORDS_BIGENDIAN */ if (UNLIKELY(i_d1 != i_d2)) { int nltr = leaps_corr[i_d2] - leaps_corr[i_d1]; res.corr = nltr; # if defined WORDS_BIGENDIAN } else { /* always repack res.corr to remove clutter * from the earlier res.sexydur ass'ment */ res.corr = 0; # endif /* WORDS_BIGENDIAN */ } } #endif /* WITH_LEAP_SECONDS */ } return res; } DEFUN int dt_dtcmp(struct dt_dt_s d1, struct dt_dt_s d2) { /* for the moment D1 and D2 have to be of the same type. */ if (UNLIKELY(d1.typ != d2.typ)) { /* always equal */ return -2; } /* go through it hierarchically and without upmotes */ switch (d1.d.typ) { int res; case DT_DUNK: default: goto try_time; case DT_YMD: case DT_DAISY: case DT_BIZDA: case DT_YWD: /* use arithmetic comparison */ if (d1.d.u < d2.d.u) { return -1; } else if (d1.d.u > d2.d.u) { return 1; } else { /* means they're equal, so try the time part */ goto try_time; } case DT_YMCW: /* use designated thing since ymcw dates aren't * increasing */ if (!(res = __ymcw_cmp(d1.d.ymcw, d2.d.ymcw))) { goto try_time; } return res; } try_time: if (d1.t.hms.u < d2.t.hms.u) { return -1; } else if (d1.t.hms.u > d2.t.hms.u) { return 1; } return 0; } DEFUN int dt_dt_in_range_p(struct dt_dt_s d, struct dt_dt_s d1, struct dt_dt_s d2) { return dt_dtcmp(d, d1) >= 0 && dt_dtcmp(d, d2) <= 0; } #if defined __INTEL_COMPILER # pragma warning (default:2203) #elif defined __GNUC__ # pragma GCC diagnostic warning "-Wcast-qual" #endif /* __INTEL_COMPILER */ DEFUN void dt_set_default(struct dt_dt_s dt) { (void)dflt_tm(&dt); return; } #endif /* INCLUDED_date_core_c_ */ /* dt-core.c ends here */ dateutils-0.3.1/lib/dt-core.h000066400000000000000000000213401241477753400160030ustar00rootroot00000000000000/*** dt-core.h -- our universe of datetimes * * Copyright (C) 2011-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **/ #if !defined INCLUDED_dt_core_h_ #define INCLUDED_dt_core_h_ #include #include #include #include #if defined __cplusplus extern "C" { #endif /* __cplusplus */ #include "date-core.h" #include "time-core.h" typedef enum { /* this one's our own version of UNK */ DT_UNK = 0, #define DT_UNK (dt_dttyp_t)(DT_UNK) /* the lower date types come from date-core.h */ DT_PACK = DT_NDTYP, DT_YMDHMS = DT_PACK, #define DT_YMDHMS (dt_dttyp_t)(DT_YMDHMS) DT_SEXY, #define DT_SEXY (dt_dttyp_t)(DT_SEXY) DT_SEXYTAI, #define DT_SEXYTAI (dt_dttyp_t)(DT_SEXYTAI) DT_NDTTYP, } dt_dttyp_t; /** packs * packs are just packs of dates and times */ typedef union { uint64_t u:53; struct { #if defined WORDS_BIGENDIAN #define DT_YEAR_OFFS (1900) /* offset by the year 1900 */ unsigned int y:12; unsigned int m:4; unsigned int d:5; /* round up to 32 bits, remaining bits are seconds east */ unsigned int offs:11; /* time part */ unsigned int H:5; unsigned int M:8; unsigned int S:8; #else /* !WORDS_BIGENDIAN */ unsigned int d:5; unsigned int m:4; /* offset by the year 1900 */ #define DT_YEAR_OFFS (1900) unsigned int y:12; /* round up to 32 bits, remaining bits are seconds east */ unsigned int offs:11; /* time part */ unsigned int S:8; unsigned int M:8; unsigned int H:5; #endif /* WORDS_BIGENDIAN */ }; } dt_ymdhms_t; /** sexy * sexy is really, secsi, seconds since X, 1970-01-01T00:00:00 here */ typedef uint64_t dt_sexy_t; typedef int64_t dt_ssexy_t; #define DT_SEXY_BASE_YEAR (1917) struct dt_dt_s { union { /* packs */ struct { /* dt type, or date type */ dt_dttyp_t typ:4; /* sandwich indicator (use d and t slots below) */ uint16_t sandwich:1; /* whether we had zone info already but fixed it */ uint16_t znfxd:1; /* whether to be aware of leap-seconds */ uint16_t tai:1; /* error indicator to denote date has been fixed up */ uint16_t fix:1; /* duration indicator */ uint16_t dur:1; /* negation indicator */ uint16_t neg:1; /* we've got 6 bits left here to coincide with dt_d_s * use that and the neg flag for zdiffs * zdiff itself has 15-minute resolution, * range [0, 63] aka [00:00 16:00] * The policy is to store the time always in UTC * but keep the difference in this slot. */ uint16_t zdiff:6; #define ZDIFF_RES (15U * 60U) union { uint64_t u:48; dt_ymdhms_t ymdhms; dt_sexy_t sexy:48; dt_ssexy_t sexydur:48; dt_ssexy_t sxepoch:48; struct { #if defined WORDS_BIGENDIAN int32_t corr:16; int32_t soft:32; #else /* !WORDS_BIGENDIAN */ int32_t soft:32; int32_t corr:16; #endif /* WORDS_BIGENDIAN */ }; }; } __attribute__((packed)); /* sandwich types */ struct { struct dt_d_s d; struct dt_t_s t; }; }; }; /* decls */ /** * Like strptime() for our dates. * The format characters are _NOT_ compatible with strptime(). * If FMT is NULL the standard format for each calendric system is used, * see format.texi or dateutils info page. * * FMT can also be the name of a calendar: * - ymd for YMD dates * - ymcw for YMCW dates * - bizda for bizda/YMDU dates * * If optional EP is non-NULL it will point to the end of the parsed * date string. */ extern struct dt_dt_s dt_strpdt(const char *str, const char *fmt, char **ep); /** * Like strftime() for our dates */ extern size_t dt_strfdt(char *restrict buf, size_t bsz, const char *fmt, struct dt_dt_s); /** * Parse durations as in 1w5d, etc. */ extern struct dt_dt_s dt_strpdtdur(const char *str, char **ep); /** * Print a duration. */ extern size_t dt_strfdtdur(char *restrict buf, size_t bsz, const char *fmt, struct dt_dt_s); /** * Negate the duration. */ extern struct dt_dt_s dt_neg_dtdur(struct dt_dt_s); /** * Is duration DUR negative? */ extern int dt_dtdur_neg_p(struct dt_dt_s dur); /** * Like time() but return the current date in the desired format. */ extern struct dt_dt_s dt_datetime(dt_dttyp_t dttyp); /** * Convert D to another calendric system, specified by TGTTYP. */ extern struct dt_dt_s dt_dtconv(dt_dttyp_t tgttyp, struct dt_dt_s); /** * Add duration DUR to date/time D. * The result will be in the calendar as specified by TGTTYP, or if * DT_UNK is given, the calendar of D will be used. */ extern struct dt_dt_s dt_dtadd(struct dt_dt_s d, struct dt_dt_s dur); /** * Get duration between D1 and D2. * The result will be of type TGTTYP, * the calendar of D1 will be used, e.g. its month-per-year, days-per-week, * etc. conventions count. * If instead D2 should count, swap D1 and D2 and negate the duration * by setting/clearing the neg bit. */ extern struct dt_dt_s dt_dtdiff(dt_dttyp_t tgttyp, struct dt_dt_s d1, struct dt_dt_s d2); /** * Compare two dates, yielding 0 if they are equal, -1 if D1 is older, * 1 if D1 is younger than the D2. */ extern int dt_dtcmp(struct dt_dt_s d1, struct dt_dt_s d2); /** * Check if D is in the interval spanned by D1 and D2, * 1 if D1 is younger than the D2. */ extern int dt_dt_in_range_p(struct dt_dt_s d, struct dt_dt_s d1, struct dt_dt_s d2); /* more specific but still useful functions */ /** * Convert a dt_dt_s to an epoch difference, based on the Unix epoch. */ extern dt_ssexy_t dt_to_unix_epoch(struct dt_dt_s); /** * Convert a dt_dt_s to an epoch difference, based on the GPS epoch. */ extern dt_ssexy_t dt_to_gps_epoch(struct dt_dt_s); /** * Set specific fallback date/time to use when input is underspecified. * Internally, when no default is set and input is underspecified the * value of `dt_datetime()' (i.e. now) is used to fill fields up. */ extern void dt_set_default(struct dt_dt_s); /* some useful gimmicks, sort of */ static inline __attribute__((pure, const)) struct dt_dt_s dt_dt_initialiser(void) { #if defined HAVE_SLOPPY_STRUCTS_INIT static const struct dt_dt_s res = {}; #else static const struct dt_dt_s res; #endif /* HAVE_SLOPPY_STRUCTS_INIT */ return res; } static inline __attribute__((pure, const)) bool dt_unk_p(struct dt_dt_s d) { return !(d.sandwich || d.typ > DT_UNK); } static inline __attribute__((pure, const)) bool dt_sandwich_p(struct dt_dt_s d) { return d.sandwich && d.d.typ > DT_DUNK; } static inline __attribute__((pure, const)) bool dt_sandwich_only_d_p(struct dt_dt_s d) { return !d.sandwich && d.d.typ > DT_DUNK && d.d.typ < DT_NDTYP; } static inline __attribute__((pure, const)) bool dt_sandwich_only_t_p(struct dt_dt_s d) { return d.sandwich && d.typ == DT_UNK; } static inline __attribute__((pure, const)) bool dt_separable_p(struct dt_dt_s d) { /* return true if D is a d+t sandwich or D is d-only or D is t-only */ return d.typ < DT_PACK; } #define DT_SANDWICH_UNK (DT_UNK) static inline void dt_make_sandwich(struct dt_dt_s *d, dt_dtyp_t dty, dt_ttyp_t tty) { d->d.typ = dty; d->t.typ = tty; d->sandwich = 1; return; } static inline void dt_make_d_only(struct dt_dt_s *d, dt_dtyp_t dty) { d->d.typ = dty; d->t.typ = DT_TUNK; d->sandwich = 0; return; } static inline void dt_make_t_only(struct dt_dt_s *d, dt_ttyp_t tty) { d->d.typ = DT_DUNK; d->t.typ = tty; d->sandwich = 1; return; } #if defined __cplusplus } #endif /* __cplusplus */ #endif /* INCLUDED_dt_core_h_ */ dateutils-0.3.1/lib/fmt-special.gperf000066400000000000000000000010231241477753400175220ustar00rootroot00000000000000%{ #if !defined DT_SEXY_BASE_YEAR # define DT_SEXY DT_DUNK #endif /* !DT_SEXY_BASE_YEAR */ %} %7bit %readonly-tables %switch=1 %ignore-case %enum %struct-type %define slot-name special %define hash-function-name ____fmt_special %define lookup-function-name __fmt_special %null-strings struct dt_fmt_special_s { const char *special; dt_dtyp_t e; }; %% ymd, DT_YMD ymcw, DT_YMCW bizda, DT_BIZDA daisy, DT_DAISY sexy, (dt_dtyp_t)DT_SEXY bizsi, DT_BIZSI ywd, DT_YWD yd, DT_YD julian, DT_JDN jdn, DT_JDN lilian, DT_LDN ldn, DT_LDN dateutils-0.3.1/lib/generics.h000066400000000000000000000050201241477753400162420ustar00rootroot00000000000000/*** generics.h -- type invariant generic funs * * Copyright (C) 2012-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***/ #if !defined INCLUDED_generics_h_ #define INCLUDED_generics_h_ #if defined HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #if defined __cplusplus extern "C" { #endif /* __cplusplus */ /** * Compare two dates, yielding 0 if they are equal, -1 if D1 is older, * 1 if D1 is younger than the D2. */ #define dt_cmp(d1, d2) \ _Generic((d1), \ struct dt_d_s: dt_dcmp, \ struct dt_t_s: dt_tcmp, \ struct dt_dt_s: dt_dtcmp, \ default: NULL \ )(d1, d2) /** * Check if D is in the interval spanned by D1 and D2, * 1 if D1 is younger than the D2. */ #define dt_in_range_p(d, d1, d2) \ _Generic((d1), \ struct dt_d_s: dt_d_in_range_p, \ struct dt_t_s: dt_t_in_range_p, \ struct dt_dt_s: dt_dt_in_range_p, \ default: NULL \ )(d, d1, d2) #if defined __cplusplus } #endif /* __cplusplus */ #endif /* INCLUDED_generics_h_ */ dateutils-0.3.1/lib/gmtime.h000066400000000000000000000042431241477753400157330ustar00rootroot00000000000000/* metaprogramming */ #if !defined INCLUDED_gmtime_h_ #define INCLUDED_gmtime_h_ /* UTC has a constant day length */ #define UTC_SECS_PER_DAY (86400) static void ffff_gmtime(struct tm *tm, const time_t t) { static uint16_t __mon_yday[] = { /* this is \sum ml, * first element is a bit set of leap days to add */ 0xfff8, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; register int days; register unsigned int yy; const uint16_t *ip; /* just go to day computation */ days = (int)(t / UTC_SECS_PER_DAY); /* week day computation, that one's easy, 1 jan '70 was Thu */ tm->tm_wday = (days + 4) % GREG_DAYS_P_WEEK; /* gotta do the date now */ yy = 1970; /* stolen from libc */ #define DIV(a, b) ((a) / (b)) /* we only care about 1901 to 2099 and there are no bullshit leap years */ #define LEAPS_TILL(y) (DIV(y, 4)) while (days < 0 || days >= (!__leapp(yy) ? 365 : 366)) { /* Guess a corrected year, assuming 365 days per year. */ register unsigned int yg = yy + days / 365 - (days % 365 < 0); /* Adjust DAYS and Y to match the guessed year. */ days -= (yg - yy) * 365 + LEAPS_TILL(yg - 1) - LEAPS_TILL(yy - 1); yy = yg; } /* set the year */ tm->tm_year = (int)yy; ip = __mon_yday; /* unrolled */ yy = 13; if (days < ip[--yy] && days < ip[--yy] && days < ip[--yy] && days < ip[--yy] && days < ip[--yy] && days < ip[--yy] && days < ip[--yy] && days < ip[--yy] && days < ip[--yy] && days < ip[--yy] && days < ip[--yy]) { yy = 1; } /* set the rest of the tm structure */ tm->tm_mday = days - ip[yy] + 1; tm->tm_yday = days; tm->tm_mon = (int)yy; /* fix up leap years */ if (UNLIKELY(__leapp(tm->tm_year))) { if ((ip[0] >> (yy)) & 1) { if (UNLIKELY(tm->tm_yday == 59)) { tm->tm_mon = 2; tm->tm_mday = 29; } else if (UNLIKELY(tm->tm_yday == ip[yy])) { tm->tm_mday = tm->tm_yday - ip[--tm->tm_mon]; } else { tm->tm_mday--; } } } #if defined FFFF_GMTIME_SUBDAY tm->tm_hour = (t % UTC_SECS_PER_DAY) / 60U / 60U; tm->tm_min = (tm->tm_sec % 3600U) / 60U; tm->tm_sec = (tm->tm_sec % 60U); #endif /* FFFF_GMTIME_SUBDAY */ return; } #endif /* INCLUDED_gmtime_h_ */ dateutils-0.3.1/lib/iata.tzminfo000066400000000000000000000007431241477753400166270ustar00rootroot00000000000000- Domain: IATA 3-letter airport codes - Author: [Sebastian Freundt][1] - Source: [The GeoNames geographical database][2] - Licence: [Creative Commons Attribution 3.0 License][3] This list maps airports by their IATA 3-letter airport code to the local IANA timezone. It is generally assumed that the airport in question indeed operates in local time. [1]: http://www.fresse.org/ [2]: http://download.geonames.org/export/dump/ [3]: http://creativecommons.org/licenses/by/3.0/ dateutils-0.3.1/lib/icao.tzminfo000066400000000000000000000007431241477753400166240ustar00rootroot00000000000000- Domain: ICAO 4-letter airport codes - Author: [Sebastian Freundt][1] - Source: [The GeoNames geographical database][2] - Licence: [Creative Commons Attribution 3.0 License][3] This list maps airports by their ICAO 4-letter airport code to the local IANA timezone. It is generally assumed that the airport in question indeed operates in local time. [1]: http://www.fresse.org/ [2]: http://download.geonames.org/export/dump/ [3]: http://creativecommons.org/licenses/by/3.0/ dateutils-0.3.1/lib/leaps.c000066400000000000000000000072561241477753400155570ustar00rootroot00000000000000/*** leaps.c -- materialised leap seconds * * Copyright (C) 2012-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***/ /* implementation part of leaps.h */ #if !defined INCLUDED_leaps_c_ #define INCLUDED_leaps_c_ #if defined HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include "nifty.h" #include "leaps.h" typedef ssize_t sidx_t; #if !defined DEFUN # define DEFUN #endif /* !DEFUN */ /* this can be called roughly 100m/sec */ #define DEF_FIND_BEFORE(N, X) \ static zidx_t \ find_before_##N( \ const X v[], size_t nv, X key, zidx_t i, zidx_t min, zidx_t max) \ { \ /* Given key K find the index of the transition before */ \ do { \ X lo, up; \ \ lo = v[i]; \ up = v[i + 1]; \ \ if (key > lo && key <= up) { \ /* found him */ \ break; \ } else if (key > up) { \ min = i + 1; \ i = (i + max) / 2; \ } else if (key <= lo) { \ max = i - 1; \ i = (i + min) / 2; \ } \ } while (max - min > 0 && i < nv); \ return i; \ } \ static const int UNUSED(defined_find_before_##name##_p) DEF_FIND_BEFORE(ui32, uint32_t); DEF_FIND_BEFORE(si32, int32_t); DEF_FIND_BEFORE(ui64, uint64_t); DEF_FIND_BEFORE(si64, int64_t); /* public apis */ DEFUN zidx_t leaps_before_ui32(const uint32_t fld[], size_t nfld, uint32_t key) { zidx_t min = 0; zidx_t max = nfld - 1; zidx_t this = max / 2; return find_before_ui32(fld, nfld, key, this, min, max); } DEFUN zidx_t leaps_before_si32(const int32_t fld[], size_t nfld, int32_t key) { zidx_t min = 0; zidx_t max = nfld - 1; zidx_t this = max / 2; return find_before_si32(fld, nfld, key, this, min, max); } DEFUN zidx_t leaps_before_ui64(const uint64_t fld[], size_t nfld, uint64_t key) { zidx_t min = 0; zidx_t max = nfld - 1; zidx_t this = max / 2; return find_before_ui64(fld, nfld, key, this, min, max); } DEFUN zidx_t leaps_before_si64(const int64_t fld[], size_t nfld, int64_t key) { zidx_t min = 0; zidx_t max = nfld - 1; zidx_t this = max / 2; return find_before_si64(fld, nfld, key, this, min, max); } #endif /* INCLUDED_leaps_c_ */ /* leaps.c ends here */ dateutils-0.3.1/lib/leaps.h000066400000000000000000000052641241477753400155610ustar00rootroot00000000000000/*** leaps.h -- materialised leap seconds * * Copyright (C) 2012-2014 Sebastian Freundt * * Author: Sebastian Freundt * * This file is part of dateutils. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of any contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***/ #if !defined INCLUDED_leaps_h_ #define INCLUDED_leaps_h_ #include #include #if defined __cplusplus extern "C" { #endif /* __cplusplus */ typedef const struct zleap_s *zleap_t; typedef const int32_t *zltr_t; typedef size_t zidx_t; /* row-based */ struct zleap_s { union { uint32_t u; int32_t v; }; int32_t corr; }; /* col-based funs */ /** * Return last leap transition before KEY in a uint32_t field FLD. */ extern zidx_t leaps_before_ui32(const uint32_t fld[], size_t nfld, uint32_t key); /** * Return last leap transition before KEY in a int32_t field FLD. */ extern zidx_t leaps_before_si32(const int32_t fld[], size_t nfld, int32_t key); /** * Return last leap transition before KEY in a uint64_t field FLD. */ extern zidx_t leaps_before_ui64(const uint64_t fld[], size_t nfld, uint64_t key); /** * Return last leap transition before KEY in a int64_t field FLD. */ extern zidx_t leaps_before_si64(const int64_t fld[], size_t nfld, int64_t key); #if defined __cplusplus } #endif /* __cplusplus */ #endif /* INCLUDED_leaps_h_ */ dateutils-0.3.1/lib/leapseconds000066400000000000000000000062201241477753400165200ustar00rootroot00000000000000#
# @(#)leapseconds	8.13
# This file is in the public domain, so clarified as of
# 2009-05-17 by Arthur David Olson.

# Allowance for leapseconds added to each timezone file.

# The International Earth Rotation Service periodically uses leap seconds
# to keep UTC to within 0.9 s of UT1
# (which measures the true angular orientation of the earth in space); see
# Terry J Quinn, The BIPM and the accurate measure of time,
# Proc IEEE 79, 7 (July 1991), 894-905.
# There were no leap seconds before 1972, because the official mechanism
# accounting for the discrepancy between atomic time and the earth's rotation
# did not exist until the early 1970s.

# The correction (+ or -) is made at the given time, so lines
# will typically look like:
#	Leap	YEAR	MON	DAY	23:59:60	+	R/S
# or
#	Leap	YEAR	MON	DAY	23:59:59	-	R/S

# If the leapsecond is Rolling (R) the given time is local time
# If the leapsecond is Stationary (S) the given time is UTC

# Leap	YEAR	MONTH	DAY	HH:MM:SS	CORR	R/S
Leap	1972	Jun	30	23:59:60	+	S
Leap	1972	Dec	31	23:59:60	+	S
Leap	1973	Dec	31	23:59:60	+	S
Leap	1974	Dec	31	23:59:60	+	S
Leap	1975	Dec	31	23:59:60	+	S
Leap	1976	Dec	31	23:59:60	+	S
Leap	1977	Dec	31	23:59:60	+	S
Leap	1978	Dec	31	23:59:60	+	S
Leap	1979	Dec	31	23:59:60	+	S
Leap	1981	Jun	30	23:59:60	+	S
Leap	1982	Jun	30	23:59:60	+	S
Leap	1983	Jun	30	23:59:60	+	S
Leap	1985	Jun	30	23:59:60	+	S
Leap	1987	Dec	31	23:59:60	+	S
Leap	1989	Dec	31	23:59:60	+	S
Leap	1990	Dec	31	23:59:60	+	S
Leap	1992	Jun	30	23:59:60	+	S
Leap	1993	Jun	30	23:59:60	+	S
Leap	1994	Jun	30	23:59:60	+	S
Leap	1995	Dec	31	23:59:60	+	S
Leap	1997	Jun	30	23:59:60	+	S
Leap	1998	Dec	31	23:59:60	+	S
Leap	2005	Dec	31	23:59:60	+	S
Leap	2008	Dec	31	23:59:60	+	S
Leap	2012	Jun	30	23:59:60	+	S

# INTERNATIONAL EARTH ROTATION AND REFERENCE SYSTEMS SERVICE (IERS)
#
# SERVICE INTERNATIONAL DE LA ROTATION TERRESTRE ET DES SYSTEMES DE REFERENCE
#
#
# SERVICE DE LA ROTATION TERRESTRE
# OBSERVATOIRE DE PARIS
# 61, Av. de l'Observatoire 75014 PARIS (France)
# Tel.      : 33 (0) 1 40 51 22 26
# FAX       : 33 (0) 1 40 51 22 91
# e-mail    : (E-Mail Removed)
# http://hpiers.obspm.fr/eop-pc
#
# Paris, 5 January 2012
#
#
# Bulletin C 43
#
# To authorities responsible
# for the measurement and
# distribution of time
#
#
# UTC TIME STEP
# on the 1st of July 2012
#
#
# A positive leap second will be introduced at the end of June 2012.
# The sequence of dates of the UTC second markers will be:		
# 		
#                          2012 June 30,     23h 59m 59s
#                          2012 June 30,     23h 59m 60s
#                          2012 July  1,      0h  0m  0s
#
# The difference between UTC and the International Atomic Time TAI is:
#
# from 2009 January 1, 0h UTC, to 2012 July 1  0h UTC  : UTC-TAI = - 34s
# from 2012 July 1,    0h UTC, until further notice    : UTC-TAI = - 35s
#
# Leap seconds can be introduced in UTC at the end of the months of December
# or June, depending on the evolution of UT1-TAI. Bulletin C is mailed every
# six months, either to announce a time step in UTC or to confirm that there
# will be no time step at the next possible date.
#
#
# Daniel GAMBIS
# Head		
# Earth Orientation Center of IERS
# Observatoire de Paris, France
dateutils-0.3.1/lib/leapseconds.h000066400000000000000000000014051241477753400167460ustar00rootroot00000000000000/*** header counterpart to auto-gen'd leapseconds.def */
#if !defined INCLUDED_leapseconds_h_
#define INCLUDED_leapseconds_h_

#include 

/**
 * Number of known leap corrections. */
extern const size_t nleaps;

/**
 * Absolute difference in seconds, TAI - UTC, at transition points */
extern const int32_t leaps_corr[];

/**
 * YMD representation of transitions. */
extern const uint32_t leaps_ymd[];

/**
 * YMCW representation of transitions. */
extern const uint32_t leaps_ymcw[];

/**
 * daisy representation of transitions. */
extern const uint32_t leaps_d[];

/**
 * sexy representation of transitions. */
extern const int32_t leaps_s[];

/**
 * HMS representation of transitions. */
extern const uint32_t leaps_hms[];

#endif	/* INCLUDED_leapseconds_h_ */
dateutils-0.3.1/lib/ltrcc.c000066400000000000000000000222011241477753400155450ustar00rootroot00000000000000/*** ltrcc.c -- leapseconds materialiser
 *
 * Copyright (C) 2012-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/
#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#if defined HAVE_SYS_STDINT_H
# include 
#endif	/* HAVE_SYS_STDINT_H */
#include 
#include 

#include "leaps.h"
#include "date-core.h"
#include "dt-core.h"
#include "nifty.h"

#include "version.c"


#define PROLOGUE	(-1UL)
#define EPILOGUE	(0UL)

static int
pr_line_corr(const char *line, size_t llen, va_list UNUSED(vap))
{
	static int32_t corr = 0;
	char *ep;

	if (llen == PROLOGUE) {
		/* prologue */
		corr = 0;
		fprintf(stdout, "\
const int32_t %s[] = {\n\
	0,\n", line);
		return 0;
	} else if (llen == EPILOGUE) {
		fprintf(stdout, "\
	%i\n\
};\n", corr);
		return 0;
	} else if (line == NULL) {
		/* grrrr */
		return -1;
	} else if (line[0] == '#') {
		/* comment line */
		return 0;
	} else if (line[0] == '\n') {
		/* empty line */
		return 0;
	}
	/* otherwise process */
	if ((dt_strpd(line, "Leap\t%Y\t%b\t%d\t", &ep), ep) == NULL) {
		return -1;
	} else if (llen - (ep - line) < 9) {
		return -1;
	} else if (ep[8] != '\t') {
		return -1;
	}

	switch (ep[9]) {
	case '+':
		++corr;
		break;
	case '-':
		--corr;
		break;
	default:
		/* still buggered */
		return -1;
	}
	/* output the correction then */
	fprintf(stdout, "\t%i,\n", corr);
	return 0;
}

static int
pr_line_d(const char *line, size_t llen, va_list vap)
{
	static int32_t corr = 0;
	struct dt_d_s d;
	dt_dtyp_t typ;
	int colp;
	char *ep;

	/* extract type from inner list */
	typ = va_arg(vap, dt_dtyp_t);
	colp = va_arg(vap, int);

	if (llen == PROLOGUE) {
		/* prologue */
		corr = 0;
		if (!colp) {
			fprintf(stdout, "\
const struct zleap_s %s[] = {\n\
	{0x00U/* 0 */, 0},\n", line);
		} else {
			fprintf(stdout, "\
const uint32_t %s[] = {\n\
	0x00U/* 0 */,\n", line);
		}
		return 0;
	} else if (llen == EPILOGUE) {
		/* epilogue */
		if (!colp) {
			fprintf(stdout, "\
	{UINT32_MAX, %i}\n\
};\n", corr);
		} else {
			fputs("\
	UINT32_MAX\n\
};\n", stdout);
		}
		return 0;
	} else if (line == NULL) {
		/* something's fucked */
		return -1;
	} else if (line[0] == '#') {
		/* comment line */
		return 0;
	} else if (line[0] == '\n') {
		/* empty line */
		return 0;
	}
	/* otherwise process */
	if ((d = dt_strpd(line, "Leap\t%Y\t%b\t%d\t", &ep), ep) == NULL) {
		return -1;
	} else if (llen - (ep - line) < 9) {
		return -1;
	} else if (ep[8] != '\t') {
		return -1;
	}

	/* convert to target type */
	d = dt_dconv(typ, d);

	if (!colp) {
		switch (ep[9]) {
		case '+':
			++corr;
			break;
		case '-':
			--corr;
			break;
		default:
			/* still buggered */
			return -1;
		}
		/* just output the line then */
		fprintf(stdout, "\t{0x%xU/* %i */, %i},\n",
			d.u, (int32_t)d.u, corr);
	} else {
		fprintf(stdout, "\t0x%xU/* %i */,\n", d.u, (int32_t)d.u);
	}
	return 0;
}

static int
pr_line_dt(const char *line, size_t llen, va_list vap)
{
	static int32_t corr = 0;
	struct dt_dt_s d;
	dt_dtyp_t __attribute__((unused)) typ;
	int colp;
	char *ep;
	dt_ssexy_t val;

	/* extract type from inner list */
	typ = va_arg(vap, dt_dtyp_t);
	colp = va_arg(vap, int);

	if (llen == PROLOGUE) {
		/* prologue */
		corr = 0;
		if (!colp) {
			fprintf(stdout, "\
const struct zleap_s %s[] = {\n\
	{INT32_MIN, 0},\n", line);
		} else {
			fprintf(stdout, "\
const int32_t %s[] = {\n\
	INT32_MIN,\n", line);
		}
		return 0;
	} else if (llen == EPILOGUE) {
		/* epilogue */
		if (!colp) {
			fprintf(stdout, "\
	{INT32_MAX, %i}\n\
};\n", corr);
		} else {
			fputs("\
	INT32_MAX\n\
};\n", stdout);
		}
		return 0;
	} else if (line == NULL) {
		/* buggre */
		return -1;
	} else if (line[0] == '#') {
		/* comment line */
		return 0;
	} else if (line[0] == '\n') {
		/* empty line */
		return 0;
	}
	/* otherwise process */
	if ((d = dt_strpdt(
		     line, "Leap\t%Y\t%b\t%d\t%H:%M:%S", &ep), ep) == NULL) {
		return -1;
	} else if (llen - (ep - line) < 1) {
		return -1;
	} else if (ep[0] != '\t') {
		return -1;
	}

	/* fix up and convert to target type */
	d.t.hms.s--;
	val = dt_to_unix_epoch(d);

	if (!colp) {
		switch (ep[1]) {
		case '+':
			++corr;
			break;
		case '-':
			--corr;
			break;
		default:
			/* still buggered */
			return -1;
		}
		/* just output the line then */
		fprintf(stdout, "\t{0x%xU/* %li */, %i},\n",
			(uint32_t)val, val, corr);
	} else {
		/* column-oriented mode */
		fprintf(stdout, "\t0x%xU/* %li */,\n", (uint32_t)val, val);
	}
	return 0;
}

static int
pr_line_t(const char *line, size_t llen, va_list vap)
{
	struct dt_dt_s d;
	dt_dtyp_t typ;
	int colp;
	char *ep;
	uint32_t val;

	/* extract type from inner list */
	typ = va_arg(vap, dt_dtyp_t);
	colp = va_arg(vap, int);

	if (llen == PROLOGUE) {
		/* prologue */
		fprintf(stdout, "\
const uint32_t %s[] = {\n\
	UINT32_MAX,\n", line);
		return 0;
	} else if (llen == EPILOGUE) {
		/* epilogue */
		fputs("\
	UINT32_MAX\n\
};\n", stdout);
		return 0;
	} else if (typ != (dt_dtyp_t)DT_HMS || !colp) {
		return 0;
	} else if (line == NULL) {
		/* do fuckall */
		return -1;
	} else if (line[0] == '#') {
		/* comment line */
		return 0;
	} else if (line[0] == '\n') {
		/* empty line */
		return 0;
	}
	/* otherwise process */
	if ((d = dt_strpdt(
		     line, "Leap\t%Y\t%b\t%d\t%H:%M:%S", &ep), ep) == NULL) {
		return -1;
	} else if (llen - (ep - line) < 1) {
		return -1;
	} else if (ep[0] != '\t') {
		return -1;
	}

	/* fix up and convert to target type */
	val = d.t.hms.u24;
	/* column-oriented mode */
	fprintf(stdout, "\t0x%xU/* %u */,\n", val, val);
	return 0;
}

static int
pr_file(FILE *fp, const char *var, int(*cb)(const char*, size_t, va_list), ...)
{
	va_list vap;
	char *line = NULL;
	size_t len = 0;
	ssize_t nrd;

	/* prologue */
	va_start(vap, cb);
	cb(var, PROLOGUE, vap);
	va_end(vap);
	/* main loop */
	while ((nrd = getline(&line, &len, fp)) >= 0) {
		va_start(vap, cb);
		if (cb(line, nrd, vap) < 0) {
			fprintf(stderr, "line buggered: %s", line);
		}
		va_end(vap);
	}
	/* epilogue */
	va_start(vap, cb);
	cb(var, EPILOGUE, vap);
	va_end(vap);
	/* standard epilogue */
	fprintf(stdout, "\
const size_t n%s = countof(%s);\n\n", var, var);

	if (line != NULL) {
		free(line);
	}
	return 0;
}


static int col = 0;

static int
parse_file(const char *file)
{
	FILE *fp;

	if ((fp = fopen(file, "r")) == NULL) {
		return -1;
	}

	fprintf(stdout, "\
/*** autogenerated by: ltrcc %s */\n\
\n\
#include \n\
#include \n\
#include \"leaps.h\"\n\
#include \"leapseconds.h\"\n\
\n\
#if !defined INCLUDED_ltrcc_generated_def_\n\
#define INCLUDED_ltrcc_generated_def_\n\
\n\
#if !defined countof\n\
# define countof(x)	(sizeof(x) / sizeof(*x))\n\
#endif	/* !countof */\n\
\n", file);

	if (col) {
		pr_file(fp, "leaps_corr", pr_line_corr);
		rewind(fp);
	}

	pr_file(fp, "leaps_ymd", pr_line_d, DT_YMD, col);
	rewind(fp);
	pr_file(fp, "leaps_ymcw", pr_line_d, DT_YMCW, col);
	rewind(fp);
	pr_file(fp, "leaps_d", pr_line_d, DT_DAISY, col);
	rewind(fp);
	pr_file(fp, "leaps_s", pr_line_dt, DT_YMD, col);
	rewind(fp);
	pr_file(fp, "leaps_hms", pr_line_t, DT_HMS, col);

	fputs("\
/* exported number of leap transitions */\n\
const size_t nleaps = countof(leaps_corr);\n\
\n\
#endif  /* INCLUDED_ltrcc_generated_def_ */\n", stdout);
	return 0;
}


#include "ltrcc.yucc"

int
main(int argc, char *argv[])
{
	yuck_t argi[1U];
	int rc = 0;

	if (yuck_parse(argi, argc, argv) < 0) {
		rc = 1;
		goto out;
	} else if (!argi->nargs) {
		fputs("LEAPS_FILE argument is mandatory\n", stderr);
		rc = 1;
		goto out;
	}

	/* assign params */
	col = argi->column_oriented_flag;

	if (parse_file(argi->args[0U]) < 0) {
		perror("Cannot parse file");
		rc = 1;
	}

out:
	yuck_free(argi);
	return rc;
}

/* ltrcc.c ends here */
dateutils-0.3.1/lib/ltrcc.yuck000066400000000000000000000001721241477753400163010ustar00rootroot00000000000000Usage: ltrcc LEAPS_FILE

Compile LEAPS_FILE into C source code.

  -C, --column-oriented  Produce column-oriented output.
dateutils-0.3.1/lib/mic.tzminfo000066400000000000000000000010251241477753400164530ustar00rootroot00000000000000- Domain: ISO-10383 4-letter Market Identifier Codes
- Author: [Sebastian Freundt][1]
- Source: [Codes for exchanges and market identification][2]
- Licence: [Creative Commons Attribution 3.0 License][3]

This list maps market codes to their IANA timezones based on a market's
official trading hours and report times.  I.e. the mapping does not
necessarily reflect where the market is headquartered.

  [1]: http://www.fresse.org/
  [2]: http://www.iso15022.org/MIC/homepageMIC.htm
  [3]: http://creativecommons.org/licenses/by/3.0/
dateutils-0.3.1/lib/nifty.h000066400000000000000000000044141241477753400156020ustar00rootroot00000000000000/*** nifty.h -- generally handy macroes
 *
 * Copyright (C) 2009-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/

#if !defined INCLUDED_nifty_h_
#define INCLUDED_nifty_h_

#if !defined LIKELY
# define LIKELY(_x)	__builtin_expect((_x), 1)
#endif	/* !LIKELY */
#if !defined UNLIKELY
# define UNLIKELY(_x)	__builtin_expect((_x), 0)
#endif	/* UNLIKELY */

#if !defined UNUSED
# define UNUSED(_x)	_x __attribute__((unused))
#endif	/* !UNUSED */

#if !defined ALGN
# define ALGN(_x, to)	_x __attribute__((aligned(to)))
#endif	/* !ALGN */

#if !defined countof
# define countof(x)	(sizeof(x) / sizeof(*x))
#endif	/* !countof */

#if !defined with
# define with(args...)	for (args, *__ep__ = (void*)1; __ep__; __ep__ = 0)
#endif	/* !with */

#endif	/* INCLUDED_nifty_h_ */
dateutils-0.3.1/lib/strops.c000066400000000000000000000251351241477753400160010ustar00rootroot00000000000000/*** strops.c -- useful string operations
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
/* implementation part of strops.h */
#if !defined INCLUDED_strops_c_
#define INCLUDED_strops_c_

#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
/* for strncasecmp() */
#include 
#include 
#if defined HAVE_SYS_STDINT_H
# include 
#endif	/* HAVE_SYS_STDINT_H */
#include "nifty.h"
#include "strops.h"

#if defined __INTEL_COMPILER
/* we MUST return a char* */
# pragma warning (disable:2203)
#elif defined __GNUC__
# pragma GCC diagnostic ignored "-Wcast-qual"
#endif	/* __INTEL_COMPILER */

#if !defined DEFUN
# define DEFUN
#endif	/* DEFUN */

/* stolen from Klaus Klein/David Laight's strptime() */
DEFUN int32_t
strtoi_lim(const char *str, const char **ep, int32_t llim, int32_t ulim)
{
	int32_t res = 0;
	const char *sp;
	/* we keep track of the number of digits via rulim */
	int32_t rulim;

	for (sp = str, rulim = ulim > 10 ? ulim : 10;
	     res * 10 <= ulim && rulim && *sp >= '0' && *sp <= '9';
	     sp++, rulim /= 10) {
		res *= 10;
		res += *sp - '0';
	}
	if (UNLIKELY(sp == str)) {
		res = -1;
	} else if (UNLIKELY(res < llim || res > ulim)) {
		res = -2;
	}
	*ep = (char*)sp;
	return res;
}

DEFUN int32_t
strtoi(const char *str, const char **ep)
{
	const char *sp = str;
	bool negp = false;
	int32_t res;

	if (*str == '-') {
		negp = true;
		sp++;
	}
	if ((res = strtoi_lim(sp, ep, 0, INT32_MAX)) < 0) {
		*ep = str;
	} else if (negp) {
		res = -res;
	}
	return res;
}

DEFUN size_t
ui32tostr(char *restrict buf, size_t bsz, uint32_t d, int width)
{
/* all strings should be little */
#define C(x, d)	(char)((x) / (d) % 10 + '0')
	size_t res;

	if (UNLIKELY(d > 1000000000U)) {
		return 0U;
	}
	switch ((res = (size_t)width) < bsz ? res : bsz) {
	case 9:
		/* for nanoseconds */
		buf[width - 9] = C(d, 100000000);
		buf[width - 8] = C(d, 10000000);
		buf[width - 7] = C(d, 1000000);
	case 6:
		/* for microseconds */
		buf[width - 6] = C(d, 100000);
		buf[width - 5] = C(d, 10000);
	case 4:
		/* for western year numbers */
		buf[width - 4] = C(d, 1000);
	case 3:
		/* for milliseconds or doy et al. numbers */
		buf[width - 3] = C(d, 100);
	case 2:
		/* hours, mins, secs, doms, moys, etc. */
		buf[width - 2] = C(d, 10);
	case 1:
		buf[width - 1] = C(d, 1);
		break;
	default:
	case 0:
		res = 0U;
		break;
	}
#undef C
	return res;
}

DEFUN size_t
ui32topstr(char *restrict b, size_t z, uint32_t d, int width, char pad)
{
/* all strings should be little */
#define C(x)	(char)((x) + '0')
	char *restrict bp = b;
	const char *const ep = b + z;

	if (UNLIKELY(d > 1000000000U)) {
		return 0U;
	} else if (!d) {
		*bp++ = C(0U);
		width--;
	}
	/* write the mantissa right to left */
	for (; d && bp < ep; width--) {
		register unsigned int x = d % 10U;

		d /= 10U;
		*bp++ = C(x);
	}
	/* fill up with padding */
	if (LIKELY(pad)) {
		while (width-- > 0) {
			*bp++ = pad;
		}
	}
	/* reverse the string */
	for (char *ip = b, *jp = bp - 1; ip < jp; ip++, jp--) {
		register char tmp = *ip;
		*ip = *jp;
		*jp = tmp;
	}
#undef C
	return bp - b;
}


/* roman numerals */
static int32_t
__romstr_v(const char c)
{
	switch (c) {
	case 'n':
	case 'N':
		return 0;
	case 'i':
	case 'I':
		return 1;
	case 'v':
	case 'V':
		return 5;
	case 'x':
	case 'X':
		return 10;
	case 'l':
	case 'L':
		return 50;
	case 'c':
	case 'C':
		return 100;
	case 'd':
	case 'D':
		return 500;
	case 'm':
	case 'M':
		return 1000;
	default:
		return -1;
	}
}

DEFUN int32_t
romstrtoi_lim(const char *str, const char **ep, int32_t llim, int32_t ulim)
{
	int32_t res = 0;
	const char *sp;
	int32_t v;

	/* loops through characters */
	for (sp = str, v = __romstr_v(*sp); *sp; sp++) {
		int32_t nv = __romstr_v(sp[1]);

		if (UNLIKELY(v < 0)) {
			break;
		} else if (LIKELY(nv < 0 || v >= nv)) {
			res += v;
		} else {
			res -= v;
		}
		v = nv;
	}
	if (UNLIKELY(sp == str)) {
		res = -1;
	} else if (UNLIKELY(res < llim || res > ulim)) {
		res = -2;
	}
	*ep = (char*)sp;
	return res;
}

static size_t
__rom_pr1(char *buf, size_t bsz, unsigned int i, char cnt, char hi, char lo)
{
	size_t res = 0;

	if (UNLIKELY(bsz < 4)) {
		return 0;
	}
	switch (i) {
	case 9:
		buf[res++] = cnt;
		buf[res++] = hi;
		break;
	case 4:
		buf[res++] = cnt;
		buf[res++] = lo;
		break;
	case 8:
		buf[++res] = cnt;
	case 7:
		buf[++res] = cnt;
	case 6:
		buf[++res] = cnt;
	case 5:
		buf[0] = lo;
		res++;
		break;
	case 3:
		buf[res++] = cnt;
	case 2:
		buf[res++] = cnt;
	case 1:
		buf[res++] = cnt;
		break;
	default:
		buf[res] = '\0';
		break;
	}
	return res;
}

DEFUN size_t
ui32tostrrom(char *restrict buf, size_t bsz, uint32_t d)
{
	size_t res;

	for (res = 0; d >= 1000 && res < bsz; d -= 1000) {
		buf[res++] = 'M';
	}

	res += __rom_pr1(buf + res, bsz - res, d / 100U, 'C', 'M', 'D');
	d %= 100;
	res += __rom_pr1(buf + res, bsz - res, d / 10U, 'X', 'C', 'L');
	d %= 10;
	res += __rom_pr1(buf + res, bsz - res, d, 'I', 'X', 'V');
	return res;
}


DEFUN int
__ordinalp(const char *num, size_t off_suf, char **ep)
{
#define __tolower(c)	(c | 0x20)
#define ILEA(a, b)	(((a) << 8) | (b))
	const char *p = num + off_suf;
	int res = 0;
	int p2;

	if (UNLIKELY(off_suf == 0 || p[0] == '\0')) {
		res = -1;
		goto yep;
	} else if ((p2 = ILEA(__tolower(p[0]), __tolower(p[1]))),
		   LIKELY(p2 == ILEA('t', 'h'))) {
		/* we accept 1th 2th 3th */
		p += 2;
		goto yep;
	} else if (UNLIKELY(off_suf >= 2 && p[-2] == '1')) {
		res = -1;
		goto yep;
	}
	/* irregular ordinals */
	switch (p[-1]) {
	case '1':
		if (p2 == ILEA('s', 't')) {
			p += 2;
		}
		break;
	case '2':
		if (p2 == ILEA('n', 'd')) {
			p += 2;
		}
		break;
	case '3':
		if (p2 == ILEA('r', 'd')) {
			p += 2;
		}
		break;
	default:
		res = -1;
		break;
	}
yep:
	*ep = (char*)p;
	return res;
#undef ILEA
#undef __tolower
}

DEFUN size_t
__ordtostr(char *buf, size_t bsz)
{
	char *p = buf;

	if (UNLIKELY(bsz < 2)) {
		return 0;
	}
	/* assumes the actual number is printed in BUF already, 2 digits long */
	if (UNLIKELY(p[-2] == '1')) {
		/* must be 11, 12, or 13 then */
		goto teens;
	} else if (p[-2] == '0') {
		/* discard */
		p[-2] = p[-1];
		p--;
	}
	switch (p[-1]) {
	default:
	teens:
		*p++ = 't';
		*p++ = 'h';
		break;
	case '1':
		*p++ = 's';
		*p++ = 't';
		break;
	case '2':
		*p++ = 'n';
		*p++ = 'd';
		break;
	case '3':
		*p++ = 'r';
		*p++ = 'd';
		break;
	}
	return p - buf;
}


/* string array funs */
DEFUN int32_t
strtoarri(const char *buf, const char **ep, const char *const *arr, size_t narr)
{
/* take a string, compare it to an array of string (case-insensitively) and
 * return its index if found or -1 if not */
	for (size_t i = 0; i < narr; i++) {
		const char *chk = arr[i];
		size_t len = strlen(chk);

		if (strncasecmp(chk, buf, len) == 0) {
			if (ep != NULL) {
				*ep = buf + len;
			}
			return i;
		}
	}
	/* no matches */
	if (ep != NULL) {
		*ep = buf;
	}
	return -1;
}

DEFUN size_t
arritostr(
	char *restrict buf, size_t bsz, size_t i,
	const char *const *arr, size_t narr)
{
/* take a string array, an index into the array and print the string
 * behind it into BUF, return the number of bytes copied */
	size_t ncp;
	size_t len;

	if (i > narr) {
		return 0;
	}
	len = strlen(arr[i]);
	ncp = bsz > len ? len : bsz;
	memcpy(buf, arr[i], ncp);
	return ncp;
}


/* faster strpbrk, strspn and strcspn, code by Richard A. O'Keefe
 * comp.unix.programmer Message-ID: <5449jv$p21$1@goanna.cs.rmit.edu.au>#1/1 */

#define ALPHABET_SIZE	(256)

/* not reentrant */
static unsigned char table[ALPHABET_SIZE];
static unsigned char cycle = 0;

static inline bool
in_current_set(unsigned char c)
{
	return table[c] == cycle;
}

static inline void
set_up_table(const unsigned char *set, bool include_NUL)
{
	if (LIKELY(set != NULL)) {
		/* useful for strtok() too */
                if (UNLIKELY(cycle == ALPHABET_SIZE - 1)) {
			memset(table, 0, sizeof(table));
			cycle = (unsigned char)1;
                } else {
			cycle = (unsigned char)(cycle + 1);
                }
                while (*set) {
			table[*set++] = cycle;
		}
	}
	table[0] = (unsigned char)(include_NUL ? cycle : 0);
	return;
}

DEFUN size_t
xstrspn(const char *src, const char *set)
{
	size_t i;

	set_up_table((const unsigned char*)set, false);
	for (i = 0; in_current_set((unsigned char)src[i]); i++);
	return i;
}

DEFUN size_t
xstrcspn(const char *src, const char *set)
{
	size_t i;

	set_up_table((const unsigned char*)set, true);
	for (i = 0; !in_current_set((unsigned char)src[i]); i++);
	return i;
}

DEFUN char*
xstrpbrk(const char *src, const char *set)
{
	const char *p;

	set_up_table((const unsigned char*)set, true);
	for (p = src; !in_current_set((unsigned char)*p); p++);
	return (char*)p;
}

DEFUN char*
xstrpbrkp(const char *src, const char *set, size_t *set_offs)
{
	const char *p;

	set_up_table((const unsigned char*)set, true);
	for (p = src; !in_current_set((unsigned char)*p); p++);
	if (LIKELY(set_offs != NULL)) {
		size_t idx;
		for (idx = 0; set[idx] != *p; idx++);
		*set_offs = idx;
	}
	return (char*)p;
}

#if defined __INTEL_COMPILER
# pragma warning (default:2203)
#elif defined __GNUC__
# pragma GCC diagnostic warning "-Wcast-qual"
#endif	/* __INTEL_COMPILER */

#endif	/* INCLUDED_strops_c_ */
dateutils-0.3.1/lib/strops.h000066400000000000000000000104101241477753400157740ustar00rootroot00000000000000/*** strops.h -- useful string operations
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
#if !defined INCLUDED_strops_h_
#define INCLUDED_strops_h_

#include 
#include 

#if defined __cplusplus
extern "C" {
#endif	/* __cplusplus */

/* stolen from Klaus Klein/David Laight's strptime() */
/**
 * Convert STR to i32 and point to the end of the string in EP. */
extern int32_t
strtoi_lim(const char *str, const char **ep, int32_t llim, int32_t ulim);

/**
 * Convert STR to i32 and point to the end of the string in EP. */
extern int32_t
strtoi(const char *str, const char **ep);

/**
 * Convert D (padded with at most PAD zeroes) into BUF and return the size. */
extern size_t
ui32tostr(char *restrict buf, size_t bsz, uint32_t d, int pad);

/**
 * Convert D (padded with at most WIDTH PAD chars) into B, return the size. */
extern size_t
ui32topstr(char *restrict b, size_t z, uint32_t d, int width, char pad);

/**
 * Convert roman numeral (string) to i32 and point to its end in EP. */
extern int32_t
romstrtoi_lim(const char *str, const char **ep, int32_t llim, int32_t ulim);

/**
 * Convert D to a roman numeral string and put it into BUF, return the size. */
extern size_t
ui32tostrrom(char *restrict buf, size_t bsz, uint32_t d);

/**
 * Find and skip ordinal suffixes in SUF, point to the end of the suffix. */
extern int __ordinalp(const char *num, size_t off_suf, char **ep);

/**
 * Append ordinal suffix to the most recently printed number in BUF,
 * eating away a leading 0. */
extern size_t __ordtostr(char *buf, size_t bsz);

/**
 * Take a string S, (case-insensitively) compare it to an array of strings ARR
 * of size NARR and return its index if found or -1 if not.
 * If S could be found in the array, point to the end of the string S in EP. */
extern int32_t
strtoarri(const char *s, const char **ep, const char *const *arr, size_t narr);

/**
 * Take a string array ARR (of size NARR) and an index I into the array, print
 * the string ARR[I] into BUF and return the number of bytes copied. */
extern size_t
arritostr(
	char *restrict buf, size_t bsz, size_t i,
	const char *const *arr, size_t narr);

/**
 * Faster strspn(). */
extern size_t
xstrspn(const char *src, const char *set);

/**
 * Faster strcspn(). */
extern size_t
xstrcspn(const char *src, const char *set);

/**
 * Faster strpbrk(). */
extern char*
xstrpbrk(const char *src, const char *set);

/**
 * Like xstrpbrk() but also return the offset to the character in set
 * that caused the match. */
extern char*
xstrpbrkp(const char *src, const char *set, size_t *set_offs);


static inline char*
__c2p(const char *p)
{
	union {
		char *p;
		const char *c;
	} res = {.c = p};
	return res.p;
}

#if defined __cplusplus
}
#endif	/* __cplusplus */

#endif	/* INCLUDED_strops_h_ */
dateutils-0.3.1/lib/testlib.c000066400000000000000000000025731241477753400161160ustar00rootroot00000000000000/* library tester */
#include 
#include 
#include 
#include "date-core.h"

static const char test_ymd[] = "2001-02-03";
static const char test_ybd[] = "2001-Feb-03";

static void __attribute__((unused))
orig_strptime_perf(size_t nruns)
{
	for (size_t i = 0; i < nruns; i++) {
		struct tm tm;
		strptime(test_ymd, "%Y-%m-%d", &tm);
	}
	return;
}

static void __attribute__((unused))
test_strpd(size_t nruns)
{
	struct dt_d_s s;

	for (size_t i = 0; i < nruns; i++) {
		if ((s = dt_strpd(test_ymd, "%F", NULL)).u == 0) {
			break;
		}
	}
	if ((s = dt_strpd(test_ymd, "%F", NULL)).typ) {
		char buf[256];
		dt_strfd(buf, sizeof(buf), "%F %a %A %b %B\n", s);
		fputs(buf, stdout);
	}
	if ((s = dt_strpd(test_ybd, "%Y-%b-%d", NULL)).typ) {
		char buf[256];
		dt_strfd(buf, sizeof(buf), "%F %a %A %b %B\n", s);
		fputs(buf, stdout);
	}
	return;
}

static void __attribute__((unused))
test_date(size_t nruns)
{
	struct dt_d_s s = {{0}};
	char buf[256];

	for (size_t i = 0; i < nruns; i++) {
		if ((s = dt_date(DT_YMCW)).u == 0) {
			break;
		}
	}
	dt_strfd(buf, sizeof(buf), "%Y-%m-%c-%w\n", s);
	fputs(buf, stdout);
	return;
}


int
main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
{
	const size_t nruns = 10000000;
#if 0
	orig_strptime_perf(nruns);
#elif 0
	test_strpd(nruns);
#elif 1
	test_date(nruns);
#endif
	return 0;
}

/* testlib.c ends here */
dateutils-0.3.1/lib/time-core-private.h000066400000000000000000000036461241477753400200130ustar00rootroot00000000000000/*** time-core-private.h -- our universe of times, private bits
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
/* private portion of time-core.h */
#if !defined INCLUDED_time_core_private_h_
#define INCLUDED_time_core_private_h_


/* formatting defaults */
extern const char hms_dflt[];

extern dt_ttyp_t __trans_tfmt(const char **fmt);

#endif	/* INCLUDED_time_core_private_h_ */
dateutils-0.3.1/lib/time-core-strpf.c000066400000000000000000000135401241477753400174640ustar00rootroot00000000000000/*** time-core-strpf.c -- parser and formatter funs for time-core
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
/* implementation part of time-core-strpf.h */
#if !defined INCLUDED_time_core_strpf_c_
#define INCLUDED_time_core_strpf_c_

#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include "strops.h"
#include "token.h"
#include "time-core.h"
#include "time-core-strpf.h"

#if !defined DEFUN
# define DEFUN
#endif	/* !DEFUN */

#if defined __INTEL_COMPILER
/* we MUST return a char* */
# pragma warning (disable:2203)
#elif defined __GNUC__
# pragma GCC diagnostic ignored "-Wcast-qual"
#endif	/* __INTEL_COMPILER */

DEFUN int
__strpt_card(struct strpt_s *d, const char *str, struct dt_spec_s s, char **ep)
{
	const char *sp = str;

	switch (s.spfl) {
	default:
	case DT_SPFL_UNK:
		goto fucked;
	case DT_SPFL_N_TSTD:
		if ((d->h = strtoi_lim(sp, &sp, 0, 23)) < 0 ||
		    *sp++ != ':') {
			goto fucked;
		} else if ((d->m = strtoi_lim(sp, &sp, 0, 59)) < 0 ||
			   *sp++ != ':') {
			goto fucked;
		} else if ((d->s = strtoi_lim(sp, &sp, 0, 60)) < 0) {
			goto fucked;
		}
		break;
	case DT_SPFL_N_HOUR:
		if (!s.sc12) {
			d->h = strtoi_lim(sp, &sp, 0, 23);
		} else {
			d->h = strtoi_lim(sp, &sp, 1, 12);
		}
		if (d->h < 0) {
			goto fucked;
		}
		break;
	case DT_SPFL_N_MIN:
		if ((d->m = strtoi_lim(sp, &sp, 0, 59)) < 0) {
			goto fucked;
		}
		break;
	case DT_SPFL_N_SEC:
		if ((d->s = strtoi_lim(sp, &sp, 0, 60)) < 0) {
			goto fucked;
		}
		break;
	case DT_SPFL_N_NANO: {
		/* nanoseconds */
		const char *on;

		if ((d->ns = strtoi_lim(sp, &on, 0, 999999999)) < 0) {
			goto fucked;
		}
		switch (on - sp) {
		case 0:
			goto fucked;
		case 1:
			d->ns *= 10;
		case 2:
			d->ns *= 10;
		case 3:
			d->ns *= 10;
		case 4:
			d->ns *= 10;
		case 5:
			d->ns *= 10;
		case 6:
			d->ns *= 10;
		case 7:
			d->ns *= 10;
		case 8:
			d->ns *= 10;
		default:
		case 9:
			break;
		}
		sp = on;
		break;
	}
	case DT_SPFL_S_AMPM: {
		const unsigned int casebit = 0x20;

		if ((sp[0] | casebit) == 'a' &&
		    (sp[1] | casebit) == 'm') {
			;
		} else if ((sp[0] | casebit) == 'p' &&
			   (sp[1] | casebit) == 'm') {
			d->flags.am_pm_bit = 1;
		} else {
			goto fucked;
		}
		sp += 2;
		break;
	}
	case DT_SPFL_LIT_PERCENT:
		if (*sp++ != '%') {
			goto fucked;
		}
		break;
	case DT_SPFL_LIT_TAB:
		if (*sp++ != '\t') {
			goto fucked;
		}
		break;
	case DT_SPFL_LIT_NL:
		if (*sp++ != '\n') {
			goto fucked;
		}
		break;
	}

	/* check if components got set */
	switch (s.spfl) {
	case DT_SPFL_N_TSTD:
		d->flags.h_set = 1;
		d->flags.m_set = 1;
		d->flags.s_set = 1;
		break;
	case DT_SPFL_N_HOUR:
		d->flags.h_set = 1;
		break;
	case DT_SPFL_N_MIN:
		d->flags.m_set = 1;
		break;
	case DT_SPFL_N_SEC:
		d->flags.s_set = 1;
		break;
	case DT_SPFL_N_NANO:
		d->flags.ns_set = 1;
		break;
	default:
		break;
	}

	/* assign end pointer */
	if (ep != NULL) {
		*ep = (char*)sp;
	}
	return 0;
fucked:
	if (ep != NULL) {
		*ep = (char*)str;
	}
	return -1;
}

DEFUN size_t
__strft_card(
	char *buf, size_t bsz, struct dt_spec_s s,
	struct strpt_s *d, struct dt_t_s UNUSED(that))
{
	size_t res = 0;

	switch (s.spfl) {
	default:
	case DT_SPFL_UNK:
		break;
	case DT_SPFL_N_TSTD:
		if (LIKELY(bsz >= 8)) {
			ui32tostr(buf + 0, bsz, d->h, 2);
			buf[2] = ':';
			ui32tostr(buf + 3, bsz, d->m, 2);
			buf[5] = ':';
			ui32tostr(buf + 6, bsz, d->s, 2);
			res = 8;
		}
		break;
	case DT_SPFL_N_HOUR:
		if (!s.sc12 || (d->h >= 1 && d->h <= 12)) {
			res = ui32tostr(buf, bsz, d->h, 2);
		} else {
			unsigned int h = d->h ? d->h - 12 : 12;
			res = ui32tostr(buf, bsz, h, 2);
		}
		break;
	case DT_SPFL_N_MIN:
		res = ui32tostr(buf, bsz, d->m, 2);
		break;
	case DT_SPFL_N_SEC:
		res = ui32tostr(buf, bsz, d->s, 2);
		break;
	case DT_SPFL_S_AMPM: {
		unsigned int casebit = 0;

		if (UNLIKELY(!s.cap)) {
			casebit = 0x20;
		}
		if (d->h >= 12) {
			buf[res++] = (char)('P' | casebit);
			buf[res++] = (char)('M' | casebit);
		} else {
			buf[res++] = (char)('A' | casebit);
			buf[res++] = (char)('M' | casebit);
		}
		break;
	}
	case DT_SPFL_N_NANO:
		res = ui32tostr(buf, bsz, d->ns, 9);
		break;

	case DT_SPFL_LIT_PERCENT:
		/* literal % */
		buf[res++] = '%';
		break;
	case DT_SPFL_LIT_TAB:
		/* literal tab */
		buf[res++] = '\t';
		break;
	case DT_SPFL_LIT_NL:
		/* literal \n */
		buf[res++] = '\n';
		break;
	}
	return res;
}

#endif	/* INCLUDED_time_core_strpf_c_ */
dateutils-0.3.1/lib/time-core-strpf.h000066400000000000000000000053311241477753400174700ustar00rootroot00000000000000/*** time-core-strpf.h -- parser and formatter funs for time-core
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/

#if !defined INCLUDED_time_core_strpf_h_
#define INCLUDED_time_core_strpf_h_

#if defined __cplusplus
extern "C" {
#endif	/* __cplusplus */

struct strpt_s {
	signed int h;
	signed int m;
	signed int s;
	signed int ns;
	union {
		unsigned int u;
		struct {
			/* 0 for am, 1 for pm */
			unsigned int am_pm_bit:1;

			unsigned int h_set:1;
			unsigned int m_set:1;
			unsigned int s_set:1;
			unsigned int ns_set:1;
		};
	} flags;
};

extern struct dt_t_s __guess_ttyp(struct strpt_s t);


/* helpers */
static inline __attribute__((pure, const)) struct strpt_s
strpt_initialiser(void)
{
#if defined HAVE_SLOPPY_STRUCTS_INIT
	static const struct strpt_s res = {};
#else
	static const struct strpt_s res;
#endif	/* HAVE_SLOPPY_STRUCTS_INIT */
	return res;
}

/* self-explanatory funs */
extern int
__strpt_card(struct strpt_s *d, const char *str, struct dt_spec_s s, char **ep);

extern size_t
__strft_card(
	char *buf, size_t bsz, struct dt_spec_s s,
	struct strpt_s *d, struct dt_t_s that);

#if defined __cplusplus
}
#endif	/* __cplusplus */

#endif	/* INCLUDED_time_core_strpf_h_ */
dateutils-0.3.1/lib/time-core.c000066400000000000000000000174051241477753400163340ustar00rootroot00000000000000/*** time-core.c -- our universe of times
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
/* implementation part of time-core.h */
#if !defined INCLUDED_time_core_c_
#define INCLUDED_time_core_c_

#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include 
#include 

#include "time-core.h"
#include "time-core-private.h"
#include "nifty.h"

#if !defined DEFUN
# define DEFUN
#endif	/* !DEFUN */
#if !defined DEFVAR
# define DEFVAR
#endif	/* !DEFVAR */

#if defined __INTEL_COMPILER
/* we MUST return a char* */
# pragma warning (disable:2203)
#elif defined __GNUC__
# pragma GCC diagnostic ignored "-Wcast-qual"
#endif	/* __INTEL_COMPILER */


/* guessing parsers */
#include "strops.h"
#include "token.h"
#include "time-core-strpf.c"

DEFVAR const char hms_dflt[] = "%H:%M:%S";

DEFUN struct dt_t_s
__guess_ttyp(struct strpt_s t)
{
	struct dt_t_s res;

	if (UNLIKELY(!(t.flags.h_set || t.flags.m_set ||
		       t.flags.s_set || t.flags.ns_set))) {
		goto fucked;
	}
	if (UNLIKELY(t.h < 0)) {
		goto fucked;
	}
	if (UNLIKELY(t.m < 0)) {
		goto fucked;
	}
	if (UNLIKELY(t.s < 0)) {
		goto fucked;
	}
	if (UNLIKELY(t.ns < 0)) {
		goto fucked;
	}

	res.typ = DT_HMS;
	res.dur = res.neg = 0;
	res.hms.s = t.s;
	res.hms.m = t.m;
	res.hms.h = t.h;
	res.hms.ns = t.ns;

	if (t.flags.am_pm_bit) {
		/* pm */
		res.hms.h += 12;
		res.hms.h %= HOURS_PER_DAY;
	}
	return res;
fucked:
	return dt_t_initialiser();
}

DEFUN dt_ttyp_t
__trans_tfmt(const char **fmt)
{
	if (UNLIKELY(*fmt == NULL)) {
		/* don't worry about it */
		*fmt = hms_dflt;
	} if (LIKELY(**fmt == '%')) {
		/* don't worry about it */
		;
	} else if (strcasecmp(*fmt, "hms") == 0) {
		*fmt = hms_dflt;
		return DT_HMS;
	}
	return DT_TUNK;
}


/* parser implementations */
DEFUN struct dt_t_s
dt_strpt(const char *str, const char *fmt, char **ep)
{
	struct dt_t_s res = dt_t_initialiser();
	struct strpt_s d = strpt_initialiser();
	const char *sp = str;
	const char *fp;

	/* translate high-level format names */
	__trans_tfmt(&fmt);

	fp = fmt;
	while (*fp && *sp) {
		const char *fp_sav = fp;
		struct dt_spec_s spec = __tok_spec(fp_sav, &fp);

		if (spec.spfl == DT_SPFL_UNK) {
			/* must be literal */
			if (*fp_sav != *sp++) {
				sp = str;
				goto out;
			}
		} else if (__strpt_card(&d, sp, spec, (char**)&sp) < 0) {
			sp = str;
			goto out;
		}
	}
		
	/* set the end pointer */
	res = __guess_ttyp(d);
out:
	if (ep != NULL) {
		*ep = (char*)sp;
	}
	return res;
}

DEFUN size_t
dt_strft(char *restrict buf, size_t bsz, const char *fmt, struct dt_t_s that)
{
	struct strpt_s d;
	const char *fp;
	char *bp;

	if (UNLIKELY(buf == NULL || bsz == 0)) {
		return 0;
	}

	d = strpt_initialiser();
	d.h = that.hms.h;
	d.m = that.hms.m;
	d.s = that.hms.s;
	d.ns = that.hms.ns;
	if (fmt == NULL) {
		fmt = hms_dflt;
	}
	/* translate high-level format names */
	__trans_tfmt(&fmt);

	/* assign and go */
	bp = buf;
	fp = fmt;
	for (char *const eo = buf + bsz; *fp && bp < eo;) {
		const char *fp_sav = fp;
		struct dt_spec_s spec = __tok_spec(fp_sav, &fp);

		if (spec.spfl == DT_SPFL_UNK) {
			/* must be literal then */
			*bp++ = *fp_sav;
		} else {
			bp += __strft_card(bp, eo - bp, spec, &d, that);
		}
	}
	if (bp < buf + bsz) {
		*bp = '\0';
	}
	return bp - buf;
}

/* arithmetics helpers */
struct divrem_s {
	signed int div;
	unsigned int rem;
};

static struct divrem_s
divrem(signed int n, unsigned int mod)
{
	register signed int _div;
	register signed int _rem;

	_div = n / (signed int)mod;
	if ((_rem = n % (signed int)mod) < 0) {
		_div--;
		_rem += mod;
	}
	return (struct divrem_s){_div, (unsigned int)_rem};
}


/* arith */
DEFUN struct dt_t_s
dt_tadd(struct dt_t_s t, struct dt_t_s dur, int corr)
{
	unsigned int ns;
	signed int sec;
	struct divrem_s tmp;

	/* get both result in seconds since midnight */
	sec = (t.hms.h * MINS_PER_HOUR + t.hms.m) * SECS_PER_MIN + t.hms.s;
	sec = sec + dur.sdur;

	/* nanoseconds next */
	if (UNLIKELY((ns = t.hms.ns + dur.nsdur) >= NANOS_PER_SEC)) {
		ns -= NANOS_PER_SEC;
		sec++;
	}

	if (LIKELY(corr == 0)) {
		tmp = divrem(sec, SECS_PER_DAY);

		/* fill up biggest first */
		t.hms.h = tmp.rem / SECS_PER_HOUR;
		tmp.rem %= SECS_PER_HOUR;
		t.hms.m = tmp.rem / SECS_PER_MIN;
		tmp.rem %= SECS_PER_MIN;
		t.hms.s = tmp.rem;
	} else {
		/* doesn't work if we span more than 1 day */
		tmp = divrem(sec, SECS_PER_DAY + corr);

		/* fill up biggest first */
		if (LIKELY(tmp.rem < SECS_PER_DAY)) {
			t.hms.h = tmp.rem / SECS_PER_HOUR;
			tmp.rem %= SECS_PER_HOUR;
			t.hms.m = tmp.rem / SECS_PER_MIN;
			tmp.rem %= SECS_PER_MIN;
			t.hms.s = tmp.rem;
		} else {
			/* leap-second day case
			 * corr < 0 will always end up in the above case */
			t.hms.h = 23;
			t.hms.m = 59;
			t.hms.s = 59 + corr;
		}
	}

	/* nanoseconds are never affected by leaps,
	 * until we implement smear-seconds or the like */
	t.hms.ns = ns;

	/* set up the return type */
	t.typ = DT_HMS;
	t.dur = 0;
	t.neg = 0;
	t.carry = tmp.div;
	return t;
}

DEFUN struct dt_t_s
dt_tdiff(struct dt_t_s t1, struct dt_t_s t2)
{
/* compute t2 - t1 */
#if defined HAVE_ANON_STRUCTS_INIT
	struct dt_t_s dur = {.u = 0};
#else
	struct dt_t_s dur;
#endif

#if !defined HAVE_ANON_STRUCTS_INIT
/* thanks gcc */
	dur.u = 0;
#endif
	dur.sdur = (t2.hms.h - t1.hms.h) * SECS_PER_HOUR;
	dur.sdur += (t2.hms.m - t1.hms.m) * SECS_PER_MIN;
	dur.sdur += (t2.hms.s - t1.hms.s);
	return dur;
}

DEFUN int
dt_tcmp(struct dt_t_s t1, struct dt_t_s t2)
{
	if (t1.u < t2.u) {
		return -1;
	} else if (t1.u > t2.u) {
		return 1;
	} else {
		return 0;
	}
}

DEFUN struct dt_t_s
dt_time(void)
{
#if defined HAVE_ANON_STRUCTS_INIT
	struct dt_t_s res = {.u = 0};
#else
	struct dt_t_s res;
#endif
	struct timeval tv;
	unsigned int tonly;

#if !defined HAVE_ANON_STRUCTS_INIT
/* thanks gcc */
	res.u = 0;
#endif
	if (gettimeofday(&tv, NULL) < 0) {
		return res;
	}

	tonly = tv.tv_sec % 86400U;
	res.hms.h = tonly / SECS_PER_HOUR;
	tonly %= SECS_PER_HOUR;
	res.hms.m = tonly / SECS_PER_MIN;
	tonly %= SECS_PER_MIN;
	res.hms.s = tonly;
	res.hms.ns = tv.tv_usec * 1000;
	return res;
}

#if defined __INTEL_COMPILER
# pragma warning (default:2203)
#elif defined __GNUC__
# pragma GCC diagnostic warning "-Wcast-qual"
#endif	/* __INTEL_COMPILER */

#endif	/* INCLUDED_time_core_c_ */
/* time-core.c ends here */
dateutils-0.3.1/lib/time-core.h000066400000000000000000000123011241477753400163270ustar00rootroot00000000000000/*** time-core.h -- our universe of times
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/

#if !defined INCLUDED_time_core_h_
#define INCLUDED_time_core_h_

#include 
#include 
#include 

#include "token.h"

#if defined __cplusplus
extern "C" {
#endif	/* __cplusplus */

typedef enum {
	DT_TUNK,
#define DT_TUNK		(dt_ttyp_t)(DT_TUNK)
	DT_HMS,
#define DT_HMS		(dt_ttyp_t)(DT_HMS)
	DT_NTTYP,
} dt_ttyp_t;

/** hms
 * hms times are just bog-standard hour, minute, second times */
typedef union {
	uint64_t u:56;
	struct {
#if defined WORDS_BIGENDIAN
		uint32_t u24:24;
		uint32_t:32;
#else  /* !WORDS_BIGENDIAN */
		uint32_t:32;
		uint32_t u24:24;
#endif	/* WORDS_BIGENDIAN */
	} __attribute__((packed));
	struct {
#if defined WORDS_BIGENDIAN
		uint64_t h:8;
		uint64_t m:8;
		uint64_t s:8;
		uint64_t ns:32;
#else  /* !WORDS_BIGENDIAN */
		uint64_t ns:32;
		uint64_t s:8;
		uint64_t m:8;
		uint64_t h:8;
#endif	/* WORDS_BIGENDIAN */
	} __attribute__((packed));
} __attribute__((packed)) dt_hms_t;

/**
 * Collection of all time types. */
struct dt_t_s {
	struct {
		dt_ttyp_t typ:2;
		uint64_t dur:1;
		uint64_t neg:1;
		/* used for tadd operations and whatnot, range [-7,7] */
		int64_t carry:4;
	} __attribute__((packed));
	union {
		uint64_t u:56;
		struct {
			signed int sdur;
			unsigned int nsdur:10;
		} __attribute__((packed));
		dt_hms_t hms;
	} __attribute__((packed));
};


/* helpers */
#if !defined NANOS_PER_SEC
# define NANOS_PER_SEC		(1000U * 1000U * 1000U)
#endif	/* !SECS_PER_MIN */
#if !defined SECS_PER_MIN
# define SECS_PER_MIN		(60U)
#endif	/* !SECS_PER_MIN */
#if !defined MINS_PER_HOUR
# define MINS_PER_HOUR		(60U)
#endif	/* !MINS_PER_HOUR */
#if !defined HOURS_PER_DAY
# define HOURS_PER_DAY		(24U)
#endif	/* !HOURS_PER_DAY */
#if !defined SECS_PER_HOUR
# define SECS_PER_HOUR		(SECS_PER_MIN * MINS_PER_HOUR)
#endif	/* !SECS_PER_HOUR */
#if !defined SECS_PER_DAY
# define SECS_PER_DAY		(SECS_PER_HOUR * HOURS_PER_DAY)
#endif	/* !SECS_PER_DAY */


/* decls */
/**
 * Like strptime() for our times.
 * The format characters are _NOT_ compatible with strptime().
 * If FMT is NULL the standard format for each calendric system is used,
 * see format.texi or dateutils info page.
 *
 * If optional EP is non-NULL it will point to the end of the parsed
 * date string. */
extern struct dt_t_s
dt_strpt(const char *str, const char *fmt, char **ep);

/**
 * Like strftime() for our times. */
extern size_t
dt_strft(char *restrict buf, size_t bsz, const char *fmt, struct dt_t_s);

/**
 * Add DUR to T and return its result.
 * Optional argument CORR is the number of leap-seconds to insert at
 * the end of the day (or remove if negative). */
extern struct dt_t_s dt_tadd(struct dt_t_s t, struct dt_t_s dur, int corr);

/**
 * Compute the duration between T1 and T2 (as in T2 - T1) and return the
 * result in the .sdur slot. */
extern struct dt_t_s dt_tdiff(struct dt_t_s t1, struct dt_t_s t2);

/**
 * Compare two time values, yielding 0 if they are equal, -1 if T1 is older,
 * 1 if T1 is younger than the T2. */
extern int dt_tcmp(struct dt_t_s t1, struct dt_t_s t2);

/**
 * Like time() but always return the current UTC time. */
extern struct dt_t_s dt_time(void);


/* some useful gimmicks, sort of */
static inline __attribute__((pure, const)) struct dt_t_s
dt_t_initialiser(void)
{
#if defined HAVE_SLOPPY_STRUCTS_INIT
	static const struct dt_t_s res = {};
#else
	static const struct dt_t_s res;
#endif	/* HAVE_SLOPPY_STRUCTS_INIT */
	return res;
}

static inline unsigned int
__secs_since_midnight(struct dt_t_s t)
{
	return (t.hms.h * MINS_PER_HOUR + t.hms.m) * SECS_PER_MIN + t.hms.s;
}

#if defined __cplusplus
}
#endif	/* __cplusplus */

#endif	/* INCLUDED_time_core_h_ */
dateutils-0.3.1/lib/token.c000066400000000000000000000120341241477753400155610ustar00rootroot00000000000000/*** token.c -- tokeniser specs and stuff
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
/* implementation part of token.h */
#if !defined INCLUDED_token_c_
#define INCLUDED_token_c_

#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include "token.h"
/* for YWD_*WK_CNT */
#include "date-core.h"

#if defined __INTEL_COMPILER
/* we MUST return a char* */
# pragma warning (disable:2203)
#elif defined __GNUC__
# pragma GCC diagnostic ignored "-Wcast-qual"
#endif	/* __INTEL_COMPILER */

struct dt_spec_s
__tok_spec(const char *fp, const char **ep)
{
	struct dt_spec_s res = spec_initialiser();

	if (*fp != '%') {
		goto out;
	}

next:
	switch (*++fp) {
	default:
		goto out;
	case 'F':
		res.spfl = DT_SPFL_N_DSTD;
		break;
	case 'T':
		res.spfl = DT_SPFL_N_TSTD;
		break;
	case 'y':
		res.abbr = DT_SPMOD_ABBR;
	case 'Y':
		res.spfl = DT_SPFL_N_YEAR;
		break;
	case 'm':
		res.spfl = DT_SPFL_N_MON;
		break;
	case 'd':
		res.spfl = DT_SPFL_N_DCNT_MON;
		break;
	case 'u':
		res.wk_cnt = YWD_MONWK_CNT;
	case 'w':
		res.spfl = DT_SPFL_N_DCNT_WEEK;
		break;
	case 'D':
	case 'j':
		res.spfl = DT_SPFL_N_DCNT_YEAR;
		break;
	case 'c':
		res.spfl = DT_SPFL_N_WCNT_MON;
		break;
	case 'U':
		res.wk_cnt = YWD_SUNWK_CNT;
		res.spfl = DT_SPFL_N_WCNT_YEAR;
		break;
	case 'V':
		res.wk_cnt = YWD_ISOWK_CNT;
		res.spfl = DT_SPFL_N_WCNT_YEAR;
		break;
	case 'C':
		res.wk_cnt = YWD_ABSWK_CNT;
		res.spfl = DT_SPFL_N_WCNT_YEAR;
		break;
	case 'W':
		res.wk_cnt = YWD_MONWK_CNT;
		res.spfl = DT_SPFL_N_WCNT_YEAR;
		break;
	case 'A':
		res.abbr = DT_SPMOD_LONG;
	case 'a':
		res.spfl = DT_SPFL_S_WDAY;
		break;
	case 'B':
		res.abbr = DT_SPMOD_LONG;
	case 'b':
	case 'h':
		res.spfl = DT_SPFL_S_MON;
		break;

		/* time specs */
	case 'I':
		res.sc12 = 1;
	case 'H':
		res.spfl = DT_SPFL_N_HOUR;
		break;
	case 'M':
		res.spfl = DT_SPFL_N_MIN;
		break;
	case 'S':
		res.spfl = DT_SPFL_N_SEC;
		break;
	case 'N':
		res.spfl = DT_SPFL_N_NANO;
		break;
		/* am/pm indicator */
	case 'p':
		res.cap = 1;
	case 'P':
		res.spfl = DT_SPFL_S_AMPM;
		break;
	case 's':
		res.spfl = DT_SPFL_N_EPOCH;
		break;
	case 'Z':
		res.spfl = DT_SPFL_N_ZDIFF;
		break;

	case '_':
		/* abbrev modifier */
		res.abbr = DT_SPMOD_ABBR;
		goto next;
	case '%':
		res.spfl = DT_SPFL_LIT_PERCENT;
		break;
	case 't':
		res.spfl = DT_SPFL_LIT_TAB;
		break;
	case 'n':
		res.spfl = DT_SPFL_LIT_NL;
		break;
	case 'Q':
		res.spfl = DT_SPFL_S_QTR;
		break;
	case 'q':
		res.spfl = DT_SPFL_N_QTR;
		break;
	case 'O':
		/* roman numerals modifier */
		res.rom = 1;
		goto next;
	case '0':
		/* 0 padding modifier */
		res.pad = DT_SPPAD_ZERO;
		goto next;
	case ' ':
		/* SPC padding modifier */
		res.pad = DT_SPPAD_SPC;
		goto next;
	case 'r':
		/* real modifier */
		res.tai = 1;
		goto next;
	case 'G':
		/* for compatibility with posix */
		res.tai = 1U;
		res.spfl = DT_SPFL_N_YEAR;
		break;
	}
	/* check for ordinals */
	if (res.spfl > DT_SPFL_UNK && res.spfl <= DT_SPFL_N_LAST &&
	    fp[1] == 't' && fp[2] == 'h' &&
	    !res.rom) {
		res.ord = 1;
		fp += 2;
	}
	/* check for bizda suffix */
	if (res.spfl == DT_SPFL_N_DCNT_MON || res.spfl == DT_SPFL_N_DCNT_YEAR) {
		switch (*++fp) {
		case 'B':
			res.ab = BIZDA_BEFORE;
		case 'b':
			res.bizda = 1;
			break;
		default:
			fp--;
			break;
		}
	}
out:
	if (ep != NULL) {
		*ep = (char*)(fp + 1);
	}
	return res;
}

#if defined __INTEL_COMPILER
# pragma warning (default:2203)
#elif defined __GNUC__
# pragma GCC diagnostic warning "-Wcast-qual"
#endif	/* __INTEL_COMPILER */

#endif	/* INCLUDED_token_c_ */
dateutils-0.3.1/lib/token.h000066400000000000000000000111221241477753400155630ustar00rootroot00000000000000/*** token.h -- tokeniser specs and stuff
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
#if !defined INCLUDED_token_h_
#define INCLUDED_token_h_

#if defined __cplusplus
extern "C" {
#endif	/* __cplusplus */

/* spec tokeniser, spec flags plus modifiers and stuff */
typedef enum {
	DT_SPFL_UNK,

	/* generic dt standard */
	DT_SPFL_N_STD,

	/* date specs */
	/* %F, but generally stands for calendar's standard format */
	DT_SPFL_N_DSTD,
	DT_SPFL_N_DFIRST = DT_SPFL_N_DSTD,
	/* year count, consecutive, %Y */
	DT_SPFL_N_YEAR,
	/* month count within the year, recurring, %m */
	DT_SPFL_N_MON,
	/* day count within the week, for 4-level calendars (%w) */
	DT_SPFL_N_DCNT_WEEK,
	/* day count within the month, %d */
	DT_SPFL_N_DCNT_MON,
	/* day count within the year, %D */
	DT_SPFL_N_DCNT_YEAR,
	/* week count within the month, %c */
	DT_SPFL_N_WCNT_MON,
	/* week count within the year, %C */
	DT_SPFL_N_WCNT_YEAR,
	DT_SPFL_N_QTR,
	DT_SPFL_N_LAST = DT_SPFL_N_QTR,

	DT_SPFL_S_WDAY,
	DT_SPFL_S_DFIRST = DT_SPFL_S_WDAY,
	DT_SPFL_S_MON,
	DT_SPFL_S_QTR,
	DT_SPFL_S_DLAST = DT_SPFL_S_QTR,

	/* time specs */
	DT_SPFL_N_SEC,
	DT_SPFL_N_TFIRST = DT_SPFL_N_SEC,
	DT_SPFL_N_MIN,
	DT_SPFL_N_HOUR,
	/* %T, but generally stands for calendar's standard format */
	DT_SPFL_N_TSTD,
	/* %N nanoseconds, non-standard */
	DT_SPFL_N_NANO,
	DT_SPFL_N_TLAST = DT_SPFL_N_NANO,

	/* date/time specs */
	/* %s epoch spec, non-standard */
	DT_SPFL_N_EPOCH,
	/* %Z zone difference */
	DT_SPFL_N_ZDIFF,
	DT_SPFL_N_DTLAST = DT_SPFL_N_ZDIFF,

	DT_SPFL_S_AMPM,
	DT_SPFL_S_TFIRST = DT_SPFL_S_AMPM,
	DT_SPFL_S_TLAST = DT_SPFL_S_AMPM,

	DT_SPFL_LIT_PERCENT,
	DT_SPFL_LIT_TAB,
	DT_SPFL_LIT_NL,
} dt_spfl_t;

struct dt_spec_s {
	struct {
		/* ordinal flag, 01, 02, 03 -> 1st 2nd 3rd */
		unsigned int ord:1U;
		/* roman numeral flag */
		unsigned int rom:1U;
		/* want real seconds/minutes/etc. */
		unsigned int tai:1U;

		/* for directions a(fter 0)/b(efore 1) */
		unsigned int ab:1U;
		/* bizda */
		unsigned int bizda:1U;

		/* pad to next octet */
		unsigned int:3U;

		/* controls abbreviation */
		enum {
			DT_SPMOD_NORM,
			DT_SPMOD_ABBR,
			DT_SPMOD_LONG,
			DT_SPMOD_ILL,
		} abbr:2U;

		/* control padding */
		enum {
			DT_SPPAD_NONE,
			DT_SPPAD_ZERO,
			DT_SPPAD_SPC,
		} pad:2U;

		/** time specs */
		/* long/short 24h v 12h scale */
		unsigned int sc12:1U;
		/* capitalise am/pm indicator */
		unsigned int cap:1U;

		/* week-count conventions */
		unsigned int wk_cnt:2U;

		/* pad to the next word */
		unsigned int:0U;
	};
	dt_spfl_t spfl:8;
};

#if !defined BIZDA_AFTER
# define BIZDA_AFTER	(0U)/*>*/
#endif	/* !BIZDA_AFTER */
#if !defined BIZDA_BEFORE
# define BIZDA_BEFORE	(1U)/*<*/
#endif	/* !BIZDA_BEFORE */
extern struct dt_spec_s __tok_spec(const char *fp, const char **ep);


static inline __attribute__((pure, const)) struct dt_spec_s
spec_initialiser(void)
{
#if defined HAVE_SLOPPY_STRUCTS_INIT
	static const struct dt_spec_s res = {};
#else
	static const struct dt_spec_s res;
#endif	/* HAVE_SLOPPY_STRUCTS_INIT */
	return res;
}

#if defined __cplusplus
}
#endif	/* __cplusplus */

#endif	/* INCLUDED_token_h_ */
dateutils-0.3.1/lib/tzmap.c000066400000000000000000000410761241477753400156040ustar00rootroot00000000000000/*** tzmap.c -- zonename maps
 *
 * Copyright (C) 2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/
#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
/* for fgetln() */
#define _NETBSD_SOURCE
#define _DARWIN_SOURCE
#define _ALL_SOURCE
#include 
#include 
#include 
#include 
#include 
#if defined HAVE_SYS_STDINT_H
# include 
#endif	/* HAVE_SYS_STDINT_H */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "tzmap.h"
#include "boops.h"

#if !defined LIKELY
# define LIKELY(_x)     __builtin_expect((_x), 1)
#endif  /* !LIKELY */
#if !defined UNLIKELY
# define UNLIKELY(_x)   __builtin_expect((_x), 0)
#endif  /* UNLIKELY */
#if !defined UNUSED
# define UNUSED(_x)     _x __attribute__((unused))
#endif  /* !UNUSED */

#if !defined countof
# define countof(x)     (sizeof(x) / sizeof(*x))
#endif  /* !countof */

#define _paste(x, y)    x ## y
#define paste(x, y)     _paste(x, y)
#if !defined with
# define with(args...)                                                  \
        for (args, *paste(__ep, __LINE__) = (void*)1;                   \
             paste(__ep, __LINE__); paste(__ep, __LINE__) = 0)
#endif  /* !with */

#if !defined HAVE_GETLINE && !defined HAVE_FGETLN
/* as a service to people including this file in their project
 * but who might not necessarily run the corresponding AC_CHECK_FUNS
 * we assume that a getline() is available. */
# define HAVE_GETLINE   1
#endif  /* !HAVE_GETLINE && !HAVE_FGETLN */

#if !defined DEFUN
# define DEFUN
#endif	/* !DEFUN */

#if defined STANDALONE
# if defined TZDIR
static const char tzdir[] = TZDIR;
# else  /* !TZDIR */
static const char tzdir[] = "/usr/share/zoneinfo";
# endif	/* TZDIR */
#endif	/* STANDALONE */


#if defined STANDALONE
static __attribute__((format(printf, 1, 2))) void
error(const char *fmt, ...)
{
        va_list vap;
        va_start(vap, fmt);
        vfprintf(stderr, fmt, vap);
        va_end(vap);
        fputc('\n', stderr);
        return;
}

static __attribute__((format(printf, 1, 2))) void
serror(const char *fmt, ...)
{
        va_list vap;
        va_start(vap, fmt);
        vfprintf(stderr, fmt, vap);
        va_end(vap);
        if (errno) {
                fputc(':', stderr);
                fputc(' ', stderr);
                fputs(strerror(errno), stderr);
        }
        fputc('\n', stderr);
        return;
}

static size_t
xstrlncpy(char *restrict dst, size_t dsz, const char *src, size_t ssz)
{
	if (ssz >= dsz) {
		ssz = dsz - 1U;
	}
	memcpy(dst, src, ssz);
	dst[ssz] = '\0';
	return ssz;
}
#endif	/* STANDALONE */

static void*
deconst(const void *ptr)
{
	return (char*)1 + ((const char*)ptr - (char*)1U);
}

static const void*
align_to(size_t tz, const void *p)
{
	uintptr_t x = (uintptr_t)p;

	if (x % tz) {
		x -= x % tz;
	}
	return (const void*)x;
}
#define ALIGN_TO(tz, p)	align_to(sizeof(tz), p)


/* public API */
static inline size_t
tzm_file_size(tzmap_t m)
{
	return m->flags[1U];
}

static inline int
tzm_fd(tzmap_t m)
{
	return m->flags[0U];
}

static inline const char*
tzm_znames(tzmap_t m)
{
	return m->data;
}

static inline size_t
tzm_zname_size(tzmap_t m)
{
	return m->off;
}

static inline const char*
tzm_mnames(tzmap_t m)
{
	return m->data + tzm_zname_size(m);
}

static inline size_t
tzm_mname_size(tzmap_t m)
{
	size_t fz = tzm_file_size(m);
	return fz - tzm_zname_size(m) - sizeof(*m);
}

DEFUN tzmap_t
tzm_open(const char *fn)
{
#define FAIL	(tzmap_t)MAP_FAILED
#define TZMP	(PROT_READ | PROT_WRITE)
	struct stat st[1U];
	size_t fz;
	struct tzmap_s *m;
	int fd;

	if ((fd = open(fn, O_RDONLY)) < 0) {
		return NULL;
	} else if (fstat(fd, st) < 0) {
		goto clo;
	} else if ((fz = st->st_size) < sizeof(*m)) {
		goto clo;
	} else if ((m = mmap(0, fz, TZMP, MAP_PRIVATE, fd, 0)) == FAIL) {
		goto clo;
	} else if (memcmp(m->magic, TZM_MAGIC, sizeof(m->magic))) {
		goto mun;
	}
	/* turn offset into native endianness */
	m->off = be32toh(m->off);
	/* also put fd and map size into m */
	m->flags[0U] = (znoff_t)fd;
	m->flags[1U] = (znoff_t)st->st_size;
	/* and here we go */
	return m;

#undef FAIL
#undef TZMP
	/* failure cases, clean up and return NULL */
mun:
	munmap(m, st->st_size);
clo:
	close(fd);
	return NULL;
}

DEFUN void
tzm_close(tzmap_t m)
{
	size_t fz = tzm_file_size(m);
	int fd = tzm_fd(m);

	/* hopefully privately mapped */
	munmap(deconst(m), fz);
	close(fd);
	return;
}

DEFUN const char*
tzm_find(tzmap_t m, const char *mname)
{
/* lookup zname for MNAME */
	const znoff_t *sp = (const void*)tzm_mnames(m);
	const znoff_t *ep = sp + tzm_mname_size(m) / sizeof(*sp) - 1U;
	const char *zns = tzm_znames(m);

	/* do a bisection now */
	do {
		const char *mp = mname;
		const char *tp;
		const char *p;

		tp = (const char*)(sp + (ep - sp) / 2U);
		if (!*tp) {
			/* fast forward to the next entry */
			tp += sizeof(*sp);
		} else {
			while (tp[-1] != '\0') {
				/* rewind to beginning */
				tp--;
			}
		}
		/* store tp again */
		p = tp;
		/* now unroll a strcmp */
		for (; *mp && *mp == *tp; mp++, tp++);
		if (*mp - *tp < 0) {
			/* use lower half */
			ep = (const znoff_t*)p - 1U;
		} else {
			/* forward to the next znoff_t alignment */
			const znoff_t *op =
				(const znoff_t*)ALIGN_TO(znoff_t, tp - 1U) + 1U;

			if (*mp - *tp > 0) {
				/* use upper half */
				sp = op + 1U;
			} else {
				/* found it */
				return zns + (be32toh(*op) >> 8U);
			}
		}
	} while (sp < ep);
	return NULL;
}


#if defined STANDALONE
/* array of all zone names */
static char *zns;
static size_t znz;
static ptrdiff_t zni;
/* array for all mappee strings */
static znoff_t *mns;
static size_t mnz;
static ptrdiff_t mni;

static void
init_tzm(void)
{
	zns = calloc(znz = 64U, sizeof(*zns));
	mns = calloc(mnz = 64U, sizeof(*mns));
	return;
}

static void
free_tzm(void)
{
	free(zns);
	free(mns);
	return;
}

static znoff_t
tzm_find_zn(const char *zn, size_t zz)
{
	char *restrict p = zns;
	const char *const ep = zns + znz;

	for (; p < ep && *p && strncmp(p, zn, zz); p += strlen(p), p++);
	if (*p) {
		/* found it, yay */
		return p - zns;
	}
	/* otherwise append, first check if there's room */
	if (p + zz + 4U >= ep) {
		/* compute new p */
		ptrdiff_t d = p - zns;
		/* resize, double the size */
		p = (zns = realloc(zns, znz *= 2U)) + d;
		memset(p, 0, (znz - (p - zns)) * sizeof(*zns));
	}
	/* really append now */
	memcpy(p, zn, zz);
	zni = (p - zns) + zz + 1U;
	return p - zns;
}

static void
tzm_add_mn(const char *mn, size_t mz, znoff_t off)
{
	znoff_t *restrict p = mns + mni;

	if (UNLIKELY(mz == 0U)) {
		/* useless */
		return;
	}
	/* first check if there's room */
	if (p + 1U + (mz + 4U/*alignment*/) / sizeof(off) >= mns + mnz) {
		/* resize, double the size */
		p = (mns = realloc(mns, (mnz *= 2U) * sizeof(*mns))) + mni;
		memset((char*)p, 0, (mnz - (p - mns)) * sizeof(*mns));
	}
	/* really append now */
	memcpy(p, mn, mz);
	p += (mz - 1U) / sizeof(off) + 1U;
	*p++ = htobe32((off & 0xffffU)<< 8U);
	mni = p - mns;
	return;
}


static unsigned int exst_only_p;
static const char *check_fn;

static bool
tzdir_zone_p(const char *zn, size_t zz)
{
	struct stat st[1U];
	char fullzn[256U] = {0};

	if (*zn == '/') {
		/* absolute zonename? */
		;
	} else if (*zn) {
		/* relative zonename */
		char *zp = fullzn;
		const char *const ep = fullzn + sizeof(fullzn);

		zp += xstrlncpy(zp, ep - zp, tzdir, sizeof(tzdir) - 1U);
		*zp++ = '/';
		zp += xstrlncpy(zp, ep - zp, zn, zz);
		*zp = '\0';
	}
	/* finally the actual check */
	if (stat(fullzn, st) < 0) {
		return false;
	}
	return true;
}

static znoff_t
parse_line(char *ln, size_t lz)
{
	/* find the separator */
	char *lp;
	znoff_t znp;

	if (UNLIKELY(ln == NULL || lz == 0U)) {
		/* finalise */
		return NUL_ZNOFF;
	}
	if ((lp = memchr(ln, '\t', lz)) == NULL) {
		/* buggered line */
		return NUL_ZNOFF;
	} else if (lp == ln) {
		return NUL_ZNOFF;
	} else if (*lp++ = '\0', *lp == '\0') {
		/* huh? no zone name, cunt off */
		return NUL_ZNOFF;
	} else if (lp - ln > 256) {
		/* too long */
		return NUL_ZNOFF;
	} else if (exst_only_p && !tzdir_zone_p(lp, ln + lz - lp)) {
		error("\
Warning: zone `%.*s' skipped: not present in global zone database",
		      (int)(ln + lz - lp), lp);
		return NUL_ZNOFF;
	} else if ((znp = tzm_find_zn(lp, ln + lz - lp)) == -1U) {
		/* brilliant, can't add anything */
		return NUL_ZNOFF;
	}
	tzm_add_mn(ln, lp - ln - 1U, znp);
	return znp;
}

static int
check_line(char *ln, size_t lz)
{
	static char last[256U];
	static unsigned int lno;
	size_t cz;
	char *lp;
	int rc = 0;

	if (UNLIKELY(ln == NULL || lz == 0U)) {
		/* finalise */
		lno = 0U;
		*last = '\0';
		return 0;
	}
	/* advance line number */
	lno++;

#define CHECK_ERROR(fmt, args...)		\
	error("Error in %s:%u: " fmt, check_fn, lno, ## args)

	/* the actual checks here */
	if ((lp = memchr(ln, '\t', lz)) == NULL) {
		/* buggered line */
		CHECK_ERROR("no separator");
		return -1;
	} else if (lp == ln) {
		CHECK_ERROR("no code");
		return -1;
	} else if (*lp++ = '\0', *lp == '\0') {
		/* huh? no zone name, cunt off */
		CHECK_ERROR("no zone name");
		rc = -1;
	}
	if ((cz = lp - ln - 1U) >= sizeof(last)) {
		CHECK_ERROR("code too long (%zu chars, max is 255)", cz);
		rc = -1;
	} else if (strncmp(last, ln, cz) >= 0) {
		CHECK_ERROR("non-ascending order `%s' (after `%s')", ln, last);
		rc = -1;
	}
	/* make sure to memorise ln for the next run */
	xstrlncpy(last, sizeof(last), ln, cz);

	/* it's none of our business really, but go through the zonenames
	 * and check for their existence now */
	if (!*lp) {
		/* already warned about this */
		;
	} else if (!tzdir_zone_p(lp, lz - (lp - ln))) {
		lp[lz - (lp - ln)] = '\0';
		CHECK_ERROR("cannot find zone `%s' in TZDIR", lp);
		rc = -1;
	}
#undef CHECK_ERROR
	return rc;
}

static int
parse_file(const char *file)
{
	char *line = NULL;
	size_t llen = 0U;
	FILE *fp;

	if (file == NULL) {
		fp = stdin;
	} else if ((fp = fopen(file, "r")) == NULL) {
		return -1;
	}

#if defined HAVE_GETLINE
	for (ssize_t nrd; (nrd = getline(&line, &llen, fp)) > 0;) {
		parse_line(line, nrd - 1);
	}
#elif defined HAVE_FGETLN
	while ((line = fgetln(fp, &llen)) != NULL && llen > 0U) {
		parse_line(line, llen - 1);
	}
#else
# error neither getline() nor fgetln() available, cannot read file line by line
#endif	/* GETLINE/FGETLN */

#if defined HAVE_GETLINE
	/* free line buffer resources */
	free(line);
#endif	/* HAVE_GETLINE */

	fclose(fp);
	return 0;
}

static bool
tzmccp(FILE *fp)
{
	static char buf[4U];

	if (fread(buf, sizeof(*buf), countof(buf), fp) < sizeof(buf)) {
		/* definitely buggered */
		;
	} else if (!memcmp(buf, TZM_MAGIC, sizeof(buf))) {
		return true;
	}
	/* otherwise, good try, seek back to the beginning */
	fseek(fp, 0, SEEK_SET);
	return false;
}

static int
tzm_check(const char *fn)
{
	tzmap_t m;
	int rc = 0;

	if ((m = tzm_open(fn)) == NULL) {
		serror("cannot open input file `%s'", fn);
		return -1;
	}

	{
		/* traverse them all */
		const znoff_t *p = (const void*)tzm_mnames(m);
		const znoff_t *const ep =
			(const void*)((const char*)p + tzm_mname_size(m));

		while (p < ep) {
			const char *mn = (const void*)p;
			size_t mz = strlen(mn);
			znoff_t off;
			const char *zn;
			size_t zz;

			p += (mz - 1U) / sizeof(*p) + 1U;
			off = be32toh(*p++) >> 8U;

			zn = m->data + off;
			zz = strlen(zn);
			if (!tzdir_zone_p(zn, zz)) {
				error("cannot find zone `%s' in TZDIR", zn);
				rc = -1;
			}
		}
	}

	tzm_close(m);
	return rc;
}

static int
check_file(const char *file)
{
	char *line = NULL;
	size_t llen = 0U;
	FILE *fp;
	int rc = 0;

	if (file == NULL) {
		fp = stdin;
		check_fn = "-";
	} else if ((fp = fopen(check_fn = file, "r")) == NULL) {
		serror("Cannot open file `%s'", file);
		return -1;
	} else if (tzmccp(fp)) {
		/* oh yikes, can't use the line reader can we */
		fclose(fp);
		return tzm_check(file);
	}

#if defined HAVE_GETLINE
	for (ssize_t nrd; (nrd = getline(&line, &llen, fp)) > 0;) {
		rc |= check_line(line, nrd - 1);
	}
#elif defined HAVE_FGETLN
	while ((line = fgetln(fp, &llen)) != NULL && llen > 0U) {
		rc |= check_line(line, llen - 1);
	}
#else
# error neither getline() nor fgetln() available, cannot read file line by line
#endif	/* GETLINE/FGETLN */

#if defined HAVE_GETLINE
	/* free line buffer resources */
	free(line);
#endif	/* HAVE_GETLINE */

	/* reset line checker */
	check_line(NULL, 0U);
	/* and clear resources */
	fclose(fp);
	return rc;
}
#endif	/* STANDALONE */


#if defined STANDALONE
#include "tzmap.yucc"

static int
cmd_cc(const struct yuck_cmd_cc_s argi[static 1U])
{
	const char *outf;
	int rc = 0;
	int ofd;

	/* reserve some space */
	init_tzm();
	/* establish environment */
	exst_only_p = argi->existing_only_flag;

	if (parse_file(argi->args[0U]) < 0) {
		error("cannot read file `%s'", *argi->args ?: "stdin");
		rc = 1;
		goto out;
	} else if ((outf = argi->output_arg ?: "tzcc.tzm", false)) {
		/* we used to make -o|--output mandatory */
		;
	} else if ((ofd = open(outf, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0) {
		serror("cannot open output file `%s'", outf);
		rc = 1;
		goto out;
	}

	/* generate a disk version now */
	with (znoff_t off = zni) {
		static struct tzmap_s r = {TZM_MAGIC};
		ssize_t sz;

		off = (off + sizeof(off) - 1U) / sizeof(off) * sizeof(off);
		r.off = htobe32(off);
		if (sz = sizeof(r), write(ofd, &r, sz) < sz) {
			goto trunc;
		} else if (sz = off, write(ofd, zns, sz) < sz) {
			goto trunc;
		} else if (sz = mni * sizeof(*mns), write(ofd, mns, sz) < sz) {
			goto trunc;
		}
		close(ofd);
		break;

	trunc:
		/* some write failed, leave a 0 byte file around */
		close(ofd);
		unlink(outf);
		rc = 1;
	}

out:
	free_tzm();
	return rc;
}

static int
cmd_show(const struct yuck_cmd_show_s argi[static 1U])
{
	const char *fn;
	tzmap_t m;
	int rc = 0;

	if ((fn = argi->tzmap_arg ?: "tzcc.tzm", false)) {
		/* we used to make -f|--tzmap mandatory */
		;
	} else if ((m = tzm_open(fn)) == NULL) {
		serror("cannot open input file `%s'", fn);
		return 1;
	}

	if (!argi->nargs) {
		/* dump mode */
		const znoff_t *p = (const void*)tzm_mnames(m);
		const znoff_t *const ep =
			(const void*)((const char*)p + tzm_mname_size(m));

		while (p < ep) {
			const char *mn = (const void*)p;
			size_t mz = strlen(mn);
			znoff_t off;

			p += (mz - 1U) / sizeof(*p) + 1U;
			off = be32toh(*p++) >> 8U;

			/* actually print the strings */
			fputs(mn, stdout);
			fputc('\t', stdout);
			fputs(m->data + off, stdout);
			fputc('\n', stdout);
		}
	}
	/* otherwise */
	for (size_t i = 0U; i < argi->nargs; i++) {
		const char *zn;

		if ((zn = tzm_find(m, argi->args[i])) != NULL) {
			puts(zn);
		}
	}

	/* and off we go */
	tzm_close(m);
	return rc;
}

static int
cmd_check(const struct yuck_cmd_check_s argi[static 1U])
{
	int rc = 0;

	for (size_t i = 0U; i < argi->nargs || i == 0U; i++) {
		rc |= check_file(argi->args[i]);
	}
	return -rc;
}

int
main(int argc, char *argv[])
{
	yuck_t argi[1U];
	int rc = 0;

	if (yuck_parse(argi, argc, argv) < 0) {
		rc = 1;
		goto out;
	}

	switch (argi->cmd) {
	case TZMAP_CMD_CC:
		rc = cmd_cc((void*)argi);
		break;
	case TZMAP_CMD_SHOW:
		rc = cmd_show((void*)argi);
		break;
	case TZMAP_CMD_CHECK:
		rc = cmd_check((void*)argi);
		break;
	default:
		rc = 1;
		break;
	}

out:
	yuck_free(argi);
	return rc;
}
#endif	/* STANDALONE */

/* tzmap.c ends here */
dateutils-0.3.1/lib/tzmap.h000066400000000000000000000045641241477753400156120ustar00rootroot00000000000000/*** tzmap.h -- zonename maps
 *
 * Copyright (C) 2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of uterus and dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/
#if !defined INCLUDED_tzmap_h_
#define INCLUDED_tzmap_h_

#include 

/*
** Each file begins with. . .
*/
#define	TZM_MAGIC	"TZm1"

typedef const struct tzmap_s *tzmap_t;

typedef uint32_t znoff_t;

#define NUL_ZNOFF	((uint32_t)-1)

/** disk representation of tzm files */
struct tzmap_s {
	/* magic cookie, should be TZM_MAGIC */
	const char magic[4U];
	/* offset of mapped names, relative to data */
	znoff_t off;
	/* just to round to 16 bytes boundary */
	znoff_t flags[2U];
	/* \nul term'd list of zonenames followed by mapped names */
	const char data[];
};


/* public API */
extern tzmap_t tzm_open(const char *file);

extern void tzm_close(tzmap_t);

extern const char *tzm_find(tzmap_t m, const char *mname);

#endif	/* INCLUDED_tzmap_h_ */
dateutils-0.3.1/lib/tzmap.yuck000066400000000000000000000007661241477753400163360ustar00rootroot00000000000000Usage: tzmap COMMAND [ARG]...

Generate or inspect zoneinfo name map files.


Usage: tzmap cc [FILE]...

Generate a map to zoneinfo names suitable for dateutils.

  -o, --output=FILE     Output compiled map into FILE.
  -e, --existing-only   Only map currently existing zones.


Usage: tzmap show [MNAME]...

Show mapped zonename for MNAMEs, if omitted show all entries
from the specified tzmap file.

  -f, --tzmap=FILE      Use FILE.


Usage: tzmap check [FILE]...

Check IANA zonenames in FILEs.
dateutils-0.3.1/lib/tzraw.c000066400000000000000000000414511241477753400156150ustar00rootroot00000000000000/*** tzraw.c -- reader for olson database zoneinfo files
 *
 * Copyright (C) 2009-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of uterus and dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/
/* implementation part of tzraw.h */
#if !defined INCLUDED_tzraw_c_
#define INCLUDED_tzraw_c_

#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#if defined MAP_ANON_NEEDS_DARWIN_SOURCE
# define _DARWIN_C_SOURCE
#endif	/* MAP_ANON_NEEDS_DARWIN_SOURCE */
#if defined MAP_ANON_NEEDS_ALL_SOURCE
# define _ALL_SOURCE
#endif	/* MAP_ANON_NEEDS_ALL_SOURCE */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#if defined HAVE_TZFILE_H
# include 
#endif	/* HAVE_TZFILE_H */

/* for be/le conversions */
#include "boops.h"
/* for LIKELY/UNLIKELY/etc. */
#include "nifty.h"
/* me own header, innit */
#include "tzraw.h"
/* for leap corrections */
#include "leapseconds.h"

#if !defined DEFUN
# define DEFUN
#endif	/* !DEFUN */

#if !defined MAP_ANONYMOUS && defined MAP_ANON
# define MAP_ANONYMOUS	(MAP_ANON)
#elif !defined MAP_ANON
# define MAP_ANON	(0x1000U)
#endif	/* MAP_ANON->MAP_ANONYMOUS */

typedef struct zih_s *zih_t;
typedef int32_t *ztr_t;
typedef uint8_t *zty_t;
typedef struct ztrdtl_s *ztrdtl_t;
typedef char *znam_t;

/* this is tzhead but better */
struct zih_s {
	/* magic */
	char tzh_magic[4];
	/* must be '2' now, as of 2005 */
	char tzh_version[1];
	/* reserved--must be zero */
	char tzh_reserved[15];
	/* number of transition time flags in gmt */
	uint32_t tzh_ttisgmtcnt;
	/* number of transition time flags in local time */
	uint32_t tzh_ttisstdcnt;
	/* number of recorded leap seconds */
	uint32_t tzh_leapcnt;
	/* number of recorded transition times */
	uint32_t tzh_timecnt;
	/* number of local time type */
	uint32_t tzh_typecnt;
	/* number of abbreviation chars */
	uint32_t tzh_charcnt;
};

/* this one must be packed to account for the packed file layout */
struct ztrdtl_s {
	int32_t offs;
	uint8_t dstp;
	uint8_t abbr;
} __attribute__((packed));

/* convenience struct where we copy all the good things into one */
struct zspec_s {
	int32_t since;
	unsigned int offs:31;
	unsigned int dstp:1;
	znam_t name;
} __attribute__((packed, aligned(16)));

/* for leap second transitions */
struct zleap_tr_s {
	/* cut-off stamp */
	int32_t t;
	/* cumulative correction since T */
	int32_t corr;
};

/* leap second support missing */
struct zif_s {
	size_t mpsz;
	zih_t hdr;

	/* transitions */
	ztr_t trs;
	/* types */
	zty_t tys;
	/* type array, deser'd, transition details array */
	ztrdtl_t tda;
	/* zonename array */
	znam_t zn;

	/* file descriptor, if >0 this also means all data is in BE */
	int fd;

	/* for special zones */
	coord_zone_t cz;

	/* zone caching, between PREV and NEXT the offset is OFFS */
	struct zrng_s cache;
};


#if defined TZDIR
static const char tzdir[] = TZDIR;
#else  /* !TZDIR */
static const char tzdir[] = "/usr/share/zoneinfo";
#endif

#if defined ZONEINFO_UTC_RIGHT
/* where can we deduce some info for our coordinated zones */
static const char coord_fn[] = ZONEINFO_UTC_RIGHT;
#else  /* !ZONEINFO_UTC_RIGHT */
static const char coord_fn[] = "/usr/share/zoneinfo/right/UTC";
#endif	/* ZONEINFO_UTC_RIGHT */

#define PROT_MEMMAP	PROT_READ | PROT_WRITE
#define MAP_MEMMAP	MAP_PRIVATE | MAP_ANONYMOUS

#define AS_MUT_ZIF(x)	((struct zif_s*)deconst(x))

/* special zone names */
static const char coord_zones[][4] = {
	"",
	"UTC",
	"TAI",
	"GPS",
};

static void*
deconst(const void *ptr)
{
	return (char*)1 + ((const char*)ptr - (char*)1U);
}

/**
 * Return the total number of transitions in zoneinfo file Z. */
DEFUN inline size_t
zif_ntrans(const struct zif_s z[static 1U])
{
	return z->hdr->tzh_timecnt;
}

/**
 * Return the total number of transition types in zoneinfo file Z. */
static inline size_t
zif_ntypes(const struct zif_s z[static 1U])
{
	return z->hdr->tzh_typecnt;
}

/**
 * Return the total number of transitions in zoneinfo file Z. */
static inline size_t
zif_nchars(const struct zif_s z[static 1U])
{
	return z->hdr->tzh_charcnt;
}


/**
 * Return the total number of leap second transitions. */
static __attribute__((unused)) inline size_t
zif_nleaps(const struct zif_s z[static 1U])
{
	return z->hdr->tzh_leapcnt;
}

/**
 * Return the transition time stamp of the N-th transition in Z. */
static inline int32_t
zif_trans(const struct zif_s z[static 1U], int n)
{
	size_t ntr = zif_ntrans(z);

	if (UNLIKELY(!ntr || n < 0)) {
		/* return earliest possible stamp */
		return INT_MIN;
	} else if (UNLIKELY(n >= (ssize_t)ntr)) {
		/* return last known stamp */
		return z->trs[ntr - 1U];
	}
	/* otherwise return n-th stamp */
	return z->trs[n];
}

/**
 * Return the transition type index of the N-th transition in Z. */
static inline uint8_t
zif_type(const struct zif_s z[static 1U], int n)
{
	size_t ntr = zif_ntrans(z);

	if (UNLIKELY(!ntr || n < 0)) {
		/* return unknown type */
		return 0;
	} else if (UNLIKELY(n >= (ssize_t)ntr)) {
		/* return last known type */
		return z->tys[ntr - 1U];
	}
	/* otherwise return n-th type */
	return z->tys[n];
}

/**
 * Return the transition details after the N-th transition in Z. */
inline struct ztrdtl_s
zif_trdtl(const struct zif_s z[static 1U], int n)
{
/* no bound check! */
	struct ztrdtl_s res;
	uint8_t idx = zif_type(z, n);
	res = z->tda[idx];
	return res;
}

/**
 * Return the gmt offset the N-th transition in Z. */
static inline int32_t
zif_troffs(const struct zif_s z[static 1U], int n)
{
/* no bound check! */
	uint8_t idx = zif_type(z, n);
	return z->tda[idx].offs;
}

/**
 * Return the zonename after the N-th transition in Z. */
static __attribute__((unused)) inline znam_t
zif_trname(const struct zif_s z[static 1U], int n)
{
/* no bound check! */
	uint8_t idx = zif_type(z, n);
	uint8_t jdx = z->tda[idx].abbr;
	return z->zn + jdx;
}

/**
 * Return a succinct summary of the situation after transition N in Z. */
static __attribute__((unused)) inline struct zspec_s
zif_spec(const struct zif_s z[static 1U], int n)
{
	struct zspec_s res;
	uint8_t idx = zif_type(z, n);
	uint8_t jdx = z->tda[idx].abbr;

	res.since = zif_trans(z, n);
	res.offs = z->tda[idx].offs;
	res.dstp = z->tda[idx].dstp;
	res.name = z->zn + jdx;
	return res;
}


static coord_zone_t
coord_zone(const char *zone)
{
	for (coord_zone_t i = TZCZ_UTC; i < TZCZ_NZONE; i++) {
		if (strcmp(zone, coord_zones[i]) == 0) {
			return i;
		}
	}
	return TZCZ_UNK;
}

static int
__open_zif(const char *file)
{
	if (file == NULL || file[0] == '\0') {
		return -1;
	} else if (file[0] != '/') {
		/* not an absolute file name */
		size_t len = strlen(file);
		size_t tzd_len = sizeof(tzdir) - 1;
		char new[tzd_len + 1U + len + 1U];
		char *tmp = new + tzd_len;

		memcpy(new, tzdir, tzd_len);
		*tmp++ = '/';
		memcpy(tmp, file, len + 1U);
		return open(new, O_RDONLY, 0644);
	}
	/* absolute file name, just try with that one then */
	return open(file, O_RDONLY, 0644);
}

static void
__init_zif(struct zif_s z[static 1U])
{
	size_t ntr;
	size_t nty;

	if (z->fd > STDIN_FILENO) {
		/* probably in BE then, eh? */
		ntr = be32toh(zif_ntrans(z));
		nty = be32toh(zif_ntypes(z));
	} else {
		ntr = zif_ntrans(z);
		nty = zif_ntypes(z);
	}

	z->trs = (ztr_t)(z->hdr + 1);
	z->tys = (zty_t)(z->trs + ntr);
	z->tda = (ztrdtl_t)(z->tys + ntr);
	z->zn = (char*)(z->tda + nty);
	return;
}

static int
__read_zif(struct zif_s tgt[static 1U], int fd)
{
	struct stat st;

	if (fstat(fd, &st) < 0) {
		return -1;
	} else if (st.st_size <= 4) {
		return -1;
	}
	tgt->mpsz = st.st_size;
	tgt->fd = fd;
	tgt->hdr = mmap(NULL, tgt->mpsz, PROT_READ, MAP_SHARED, fd, 0);
	if (tgt->hdr == MAP_FAILED) {
		return -1;
	}
	/* all clear so far, populate */
	__init_zif(tgt);
	return 0;
}

static void
__conv_hdr(struct zih_s tgt[static 1U], const struct zih_s src[static 1U])
{
/* copy SRC to TGT doing byte-order conversions on the way */
	memcpy(tgt, src, offsetof(struct zih_s, tzh_ttisgmtcnt));
	tgt->tzh_ttisgmtcnt = be32toh(src->tzh_ttisgmtcnt);
	tgt->tzh_ttisstdcnt = be32toh(src->tzh_ttisstdcnt);
	tgt->tzh_leapcnt = be32toh(src->tzh_leapcnt);
	tgt->tzh_timecnt = be32toh(src->tzh_timecnt);
	tgt->tzh_typecnt = be32toh(src->tzh_typecnt);
	tgt->tzh_charcnt = be32toh(src->tzh_charcnt);
	return;
}

static void
__conv_zif(struct zif_s tgt[static 1U], const struct zif_s src[static 1U])
{
	size_t ntr;
	size_t nty;
	size_t nch;

	/* convert header to hbo */
	__conv_hdr(tgt->hdr, src->hdr);

	/* everything in host byte-order already */
	ntr = zif_ntrans(tgt);
	nty = zif_ntypes(tgt);
	nch = zif_nchars(tgt);
	__init_zif(tgt);

	/* transition vector */
	for (size_t i = 0; i < ntr; i++) {
		tgt->trs[i] = be32toh(src->trs[i]);
	}

	/* type vector, nothing to byte-swap here */
	memcpy(tgt->tys, src->tys, ntr * sizeof(*tgt->tys));

	/* transition details vector */
	for (size_t i = 0; i < nty; i++) {
		tgt->tda[i].offs = be32toh(src->tda[i].offs);
		tgt->tda[i].dstp = src->tda[i].dstp;
		tgt->tda[i].abbr = src->tda[i].abbr;
	}

	/* zone name array */
	memcpy(tgt->zn, src->zn, nch * sizeof(*tgt->zn));
	return;
}

static struct zif_s*
__copy_conv(const struct zif_s z[static 1U])
{
/* copy Z and do byte-order conversions */
	size_t mpsz;
	struct zif_s *res = NULL;

	/* compute a size */
	mpsz = z->mpsz + sizeof(*z);

	/* we'll mmap ourselves a slightly larger struct so
	 * res + 1 points to the header, while res + 0 is the zif_t */
	res = mmap(NULL, mpsz, PROT_MEMMAP, MAP_MEMMAP, -1, 0);
	if (UNLIKELY(res == MAP_FAILED)) {
		return NULL;
	}
	/* great, now to some initial assignments */
	res->mpsz = mpsz;
	res->hdr = (void*)(res + 1);
	/* make sure we denote that this isnt connected to a file */
	res->fd = -1;
	/* copy the flags though */
	res->cz = z->cz;

	/* convert the header and payload now */
	__conv_zif(res, z);

	/* that's all :) */
	return res;
}

static struct zif_s*
__copy(const struct zif_s z[static 1U])
{
/* copy Z into a newly allocated zif_t object
 * if applicable also perform byte-order conversions */
	struct zif_s *res;

	if (z->fd > STDIN_FILENO) {
		return __copy_conv(z);
	}
	/* otherwise it's a plain copy */
	res = mmap(NULL, z->mpsz, PROT_MEMMAP, MAP_MEMMAP, -1, 0);
	if (UNLIKELY(res == MAP_FAILED)) {
		return NULL;
	}
	memcpy(res, z, z->mpsz);
	__init_zif(res);
	return res;
}

DEFUN zif_t
zif_copy(zif_t z)
{
/* copy Z into a newly allocated zif_t object
 * if applicable also perform byte-order conversions */
	if (UNLIKELY(z == NULL)) {
		/* no need to bother */
		return NULL;
	}
	return __copy(z);
}

static void
__close(const struct zif_s z[static 1U])
{
	if (z->fd > STDIN_FILENO) {
		close(z->fd);
	}
	/* check if z is in mmap()'d space */
	if (z->hdr == MAP_FAILED) {
		/* not sure what to do */
		;
	} else if ((z + 1) != (void*)z->hdr) {
		/* z->hdr is mmapped, z is not */
		munmap((void*)z->hdr, z->mpsz);
	} else {
		munmap(deconst(z), z->mpsz);
	}
	return;
}

DEFUN void
zif_close(zif_t z)
{
	if (UNLIKELY(z == NULL)) {
		/* nothing to do */
		return;
	}
	__close((const void*)z);
	return;
}

DEFUN zif_t
zif_open(const char *file)
{
	coord_zone_t cz;
	int fd;
	struct zif_s tmp[1];
	struct zif_s *res;

	/* check for special time zones */
	if ((cz = coord_zone(file)) > TZCZ_UNK) {
		file = coord_fn;
	}

	if (UNLIKELY((fd = __open_zif(file)) < STDIN_FILENO)) {
		return NULL;
	} else if (UNLIKELY(__read_zif(tmp, fd) < 0)) {
		return NULL;
	}
	/* otherwise all's fine, it's still BE
	 * assign the coord zone type if any and convert to host byte-order */
	tmp->cz = cz;
	res = __copy(tmp);
	__close(tmp);
	return res;
}


/* for leap corrections */
#include "leapseconds.def"

static inline int
__find_trno(const struct zif_s z[static 1U], int32_t t, int min, int max)
{
/* find the last transition before T, T is expected to be UTC
 * if T is before any known transition return -1 */
	if (UNLIKELY(max == 0)) {
		/* special case */
		return -1;
	} else if (UNLIKELY(t < zif_trans(z, min))) {
		return -1;
	} else if (UNLIKELY(t > zif_trans(z, max))) {
		return max - 1;
	}

	do {
		int32_t tl, tu;
		int this = (min + max) / 2;

		tl = zif_trans(z, this);
		tu = zif_trans(z, this + 1);

		if (t >= tl && t < tu) {
			/* found him */
			return this;
		} else if (t >= tu) {
			min = this;
		} else if (t < tl) {
			max = this;
		}
	} while (true);
	/* not reached */
}

DEFUN inline int
zif_find_trans(zif_t z, int32_t t)
{
/* find the last transition before T, T is expected to be UTC
 * if T is before any known transition return -1 */
	int max = zif_ntrans(z);
	int min = 0;

	return __find_trno(z, t, min, max);
}

static struct zrng_s
__find_zrng(const struct zif_s z[static 1U], int32_t t, int min, int max)
{
	struct zrng_s res;
	int trno;

	trno = __find_trno(z, t, min, max);
	res.prev = zif_trans(z, trno);
	if (UNLIKELY(trno <= 0 && t < res.prev)) {
		res.trno = 0U;
		res.prev = INT_MIN;
		/* assume the first offset has always been there */
		res.next = res.prev;
	} else {
		res.trno = (uint8_t)trno;
		if (LIKELY(trno + 1U < zif_ntrans(z))) {
			res.next = zif_trans(z, trno + 1U);
		} else {
			res.next = INT_MAX;
		}
	}
	res.offs = zif_troffs(z, res.trno);
	return res;
}

DEFUN inline struct zrng_s
zif_find_zrng(zif_t z, int32_t t)
{
/* find the last transition before time, time is expected to be UTC */
	int max = zif_ntrans(z);
	int min = 0;

	return __find_zrng(z, t, min, max);
}

static int32_t
__tai_offs(int32_t t)
{
	/* difference of TAI and UTC at epoch instant */
	const int32_t tai_offs_epoch = 10;
	zidx_t zi = leaps_before_si32(leaps_s, nleaps_corr, t);

	return tai_offs_epoch + leaps_corr[zi];
}

static int32_t
__gps_offs(int32_t t)
{
/* TAI - GPS = 19 on 1980-01-06, so use that identity here */
	const int32_t gps_offs_epoch = 19;
	if (UNLIKELY(t < 315964800)) {
		return 0;
	}
	return __tai_offs(t) - gps_offs_epoch;
}

static int32_t
__offs(struct zif_s z[static 1U], int32_t t)
{
/* return the offset of T in Z and cache the result. */
	int min;
	size_t max;

	switch (z->cz) {
	default:
	case TZCZ_UNK:
		break;
	case TZCZ_UTC:
		return 0;
	case TZCZ_TAI:
		return __tai_offs(t);
	case TZCZ_GPS:
		return __gps_offs(t);
	}

	/* use the classic code */
	if (LIKELY(t >= z->cache.prev && t < z->cache.next)) {
		/* use the cached offset */
		return z->cache.offs;
	} else if (t >= z->cache.next) {
		min = z->cache.trno + 1;
		max = zif_ntrans(z);
	} else if (t < z->cache.prev) {
		max = z->cache.trno;
		min = 0;
	} else {
		/* we shouldn't end up here at all */
		min = 0;
		max = 0;
	}
	return (z->cache = __find_zrng(z, t, min, max)).offs;
}

DEFUN int32_t
zif_utc_time(zif_t z, int32_t t)
{
/* here's the setup, given t in local time, we denote the corresponding
 * UTC time by t' = t - x' where x' is the true offset
 * however, since we do not know the offset in advance, we have to solve
 * for an estimate of the offset x:
 * t - x + x' = t, or equivalently t - x = t' or as a root finding problem
 * x' - x = 0.
 * To make this iterative we just solve:
 * x_{i+1} - x_i = 0, where x_{i+1} = o(t - x_i) and o maps a given
 * time stamp to an offset. */
/* make me use the cache please! */
	/* let's go */
	int32_t xi = 0;
	int32_t xj;
	int32_t old = -1;

	/* jump off the cliff if Z is nought */
	if (UNLIKELY(z == NULL)) {
		return t;
	}

	while ((xj = __offs(AS_MUT_ZIF(z), t - xi)) != xi && xi != old) {
		old = xi = xj;
	}
	return t - xj;
}

/* convert utc to local */
DEFUN int32_t
zif_local_time(zif_t z, int32_t t)
{
	/* jump off the cliff if Z is nought */
	if (UNLIKELY(z == NULL)) {
		return t;
	}
	return t + __offs(AS_MUT_ZIF(z), t);
}

#endif	/* INCLUDED_tzraw_c_ */
/* tzraw.c ends here */
dateutils-0.3.1/lib/tzraw.h000066400000000000000000000122541241477753400156210ustar00rootroot00000000000000/*** tzraw.h -- reader for olson database zoneinfo files
 *
 * Copyright (C) 2009-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of uterus and dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/

#if !defined INCLUDED_tzraw_h_
#define INCLUDED_tzraw_h_

#include 
#include 
#include "leaps.h"

#if defined __cplusplus
extern "C" {
#endif	/* __cplusplus */

/*
** Each file begins with. . .
*/
#define	TZ_MAGIC	"TZif"

#if 0
struct tzhead {
	char	tzh_magic[4];		/* TZ_MAGIC */
	char	tzh_version[1];		/* '\0' or '2' as of 2005 */
	char	tzh_reserved[15];	/* reserved--must be zero */
	char	tzh_ttisgmtcnt[4];	/* coded number of trans. time flags */
	char	tzh_ttisstdcnt[4];	/* coded number of trans. time flags */
	char	tzh_leapcnt[4];		/* coded number of leap seconds */
	char	tzh_timecnt[4];		/* coded number of transition times */
	char	tzh_typecnt[4];		/* coded number of local time types */
	char	tzh_charcnt[4];		/* coded number of abbr. chars */
};

/*
** . . .followed by. . .
**
**	tzh_timecnt (char [4])s		coded transition times a la time(2)
**	tzh_timecnt (unsigned char)s	types of local time starting at above
**	tzh_typecnt repetitions of
**		one (char [4])		coded UTC offset in seconds
**		one (unsigned char)	used to set tm_isdst
**		one (unsigned char)	that's an abbreviation list index
**	tzh_charcnt (char)s		'\0'-terminated zone abbreviations
**	tzh_leapcnt repetitions of
**		one (char [4])		coded leap second transition times
**		one (char [4])		total correction after above
**	tzh_ttisstdcnt (char)s		indexed by type; if TRUE, transition
**					time is standard time, if FALSE,
**					transition time is wall clock time
**					if absent, transition times are
**					assumed to be wall clock time
**	tzh_ttisgmtcnt (char)s		indexed by type; if TRUE, transition
**					time is UTC, if FALSE,
**					transition time is local time
**					if absent, transition times are
**					assumed to be local time
*/

/*
** If tzh_version is '2' or greater, the above is followed by a second instance
** of tzhead and a second instance of the data in which each coded transition
** time uses 8 rather than 4 chars,
** then a POSIX-TZ-environment-variable-style string for use in handling
** instants after the last transition time stored in the file
** (with nothing between the newlines if there is no POSIX representation for
** such instants).
*/
#endif	/* 0 */


/* now our view on things */
typedef const struct zif_s *zif_t;

typedef enum {
	TZCZ_UNK,
	TZCZ_UTC,
	TZCZ_TAI,
	TZCZ_GPS,
	TZCZ_NZONE,
} coord_zone_t;

/* for the one tool that needs raw transitions */
struct zrng_s {
	int32_t prev, next;
	signed int offs:24;
	unsigned int trno:8;
} __attribute__((packed));


/**
 * Open the zoneinfo file FILE.
 * FILE can be absolute or relative to the configured TZDIR path.
 * FILE can also name virtual zones such as GPS or TAI. */
extern zif_t zif_open(const char *file);

/**
 * Close the zoneinfo file reader and free associated resources. */
extern void zif_close(zif_t);

/**
 * Copy the zoneinfo structure. */
extern zif_t zif_copy(zif_t);

/**
 * Find the most recent transition in Z before T. */
extern int zif_find_trans(zif_t z, int32_t t);

/**
 * Find a range of transitions in Z that T belongs to. */
extern struct zrng_s zif_find_zrng(zif_t z, int32_t t);

/**
 * Given T in local time specified by Z, return a T in UTC. */
extern int32_t zif_utc_time(zif_t z, int32_t t);

/**
 * Given T in UTC, return a T in local time specified by Z. */
extern int32_t zif_local_time(zif_t z, int32_t t);


/* exposure for specific zif-inspecting tools (dzone(1) for one) */
extern inline size_t zif_ntrans(zif_t z);

extern inline struct ztrdtl_s zif_trdtl(zif_t z, int n);

#if defined __cplusplus
}
#endif	/* __cplusplus */

#endif	/* INCLUDED_tzraw_h_ */
dateutils-0.3.1/lib/version.c.in000066400000000000000000000001451241477753400165330ustar00rootroot00000000000000/* -*- c -*- */
#include "version.h"

const char dateutils_version_string[] = "YUCK_SCMVER_VERSION";
dateutils-0.3.1/lib/version.h000066400000000000000000000002721241477753400161340ustar00rootroot00000000000000#ifndef INCLUDED_version_h_
#define INCLUDED_version_h_

extern const char dateutils_version_string[];
#define package_version	dateutils_version_string

#endif	/* INCLUDED_version_h_ */
dateutils-0.3.1/lib/yd.c000066400000000000000000000364201241477753400150620ustar00rootroot00000000000000/*** yd.c -- guts for yd dates that consist of a year and a year-day
 *
 * Copyright (C) 2010-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
/* for convenience year related stuff will be collected in here as well */

/* set aspect temporarily */
#define ASPECT_YD
/* permanent aspect, to be read as have we ever seen aspect_yd */
#if !defined ASPECT_YD_
#define ASPECT_YD_
#endif	/* !ASPECT_YD_ */

#include "nifty.h"

#if !defined DEFUN
# define DEFUN
#endif	/* !DEFUN */

/* algo choices for jan01 wd determination */
#if defined GET_JAN01_WDAY_FULL_LOOKUP
#elif defined GET_JAN01_WDAY_28Y_LOOKUP
#elif defined GET_JAN01_WDAY_28Y_SWITCH
#elif defined GET_JAN01_WDAY_SAKAMOTO
#else
# define GET_JAN01_WDAY_28Y_LOOKUP
#endif

/* year + mon-dom -> yd algos */
#if defined YMD_GET_YD_LOOKUP
#elif defined YMD_GET_YD_DIVREM
#else
# define YMD_GET_YD_LOOKUP
#endif

/* yd -> mon-dom algos */
#if defined GET_MD_FREUNDT
#elif defined GET_MD_TRIMESTER
#else
# define GET_MD_FREUNDT
#endif


#if !defined YD_ASPECT_HELPERS_
#define YD_ASPECT_HELPERS_

#if defined GET_JAN01_WDAY_FULL_LOOKUP
# define M	(unsigned int)(DT_MONDAY)
# define T	(unsigned int)(DT_TUESDAY)
# define W	(unsigned int)(DT_WEDNESDAY)
# define R	(unsigned int)(DT_THURSDAY)
# define F	(unsigned int)(DT_FRIDAY)
# define A	(unsigned int)(DT_SATURDAY)
# define S	(unsigned int)(DT_SUNDAY)

static const __jan01_wday_block_t __jan01_wday[] = {
#define __JAN01_WDAY_BEG	(1920)
	{
		/* 1920 - 1929 */
		R, A, S, M, T, R, F, A, S, T, 0,
	}, {
		/* 1930 - 1939 */
		W, R, F, S, M, T, W, F, A, S, 0,
	}, {
		/* 1940 - 1949 */
		M, W, R, F, A, M, T, W, R, A, 0,
	}, {
		/* 1950 - 1959 */
		S, M, T, R, F, A, S, T, W, R, 0,
	}, {
		/* 1960 - 1969 */
		F, S, M, T, W, F, A, S, M, W, 0,
	}, {
		/* 1970 - 1979 */
		R, F, A, M, T, W, R, A, S, M, 0,
	}, {
		/* 1980 - 1989 */
		T, R, F, A, S, T, W, R, F, S, 0,
	}, {
		/* 1990 - 1999 */
		M, T, W, F, A, S, M, W, R, F, 0,
	}, {
		/* 2000 - 2009 */
		A, M, T, W, R, A, S, M, T, R, 0,
	}, {
		/* 2010 - 2019 */
		F, A, S, T, W, R, F, S, M, T, 0,
	}, {
		/* 2020 - 2029 */
		W, F, A, S, M, W, R, F, A, M, 0,
	}, {
		/* 2030 - 2039 */
		T, W, R, A, S, M, T, R, F, A, 0,
	}, {
		/* 2040 - 2049 */
		S, T, W, R, F, S, M, T, W, F, 0,
	}, {
		/* 2050 - 2059 */
		A, S, M, W, R, F, A, M, T, W, 0,
	}
	/* 2060 - 2069 is 1920 - 1929 */
#define __JAN01_WDAY_END	(2059)
};
# undef M
# undef T
# undef W
# undef R
# undef F
# undef A
# undef S

static inline __attribute__((const, pure)) __jan01_wday_block_t
__get_jan01_block(unsigned int year)
{
	return __jan01_wday[(year - __JAN01_WDAY_BEG) / __JAN01_Y_PER_B];
}

static inline __attribute__((const, pure)) dt_dow_t
__get_jan01_wday(unsigned int year)
{
/* get the weekday of jan01 in YEAR */
	unsigned int res;
	__jan01_wday_block_t j01b;

	if (UNLIKELY(year < __JAN01_WDAY_BEG)) {
		/* use the 140y period property */
		while ((year += 140) < __JAN01_WDAY_BEG);
	} else if (year > __JAN01_WDAY_END) {
		/* use the 140y period property */
		while ((year -= 140) > __JAN01_WDAY_END);
	}
	j01b = __get_jan01_block(year);

	switch (year % 10) {
	default:
		res = DT_MIRACLEDAY;
		break;
	case 0:
		res = j01b.y0;
		break;
	case 1:
		res = j01b.y1;
		break;
	case 2:
		res = j01b.y2;
		break;
	case 3:
		res = j01b.y3;
		break;
	case 4:
		res = j01b.y4;
		break;
	case 5:
		res = j01b.y5;
		break;
	case 6:
		res = j01b.y6;
		break;
	case 7:
		res = j01b.y7;
		break;
	case 8:
		res = j01b.y8;
		break;
	case 9:
		res = j01b.y9;
		break;
	}
	return (dt_dow_t)res;
}

#elif defined GET_JAN01_WDAY_28Y_LOOKUP
# define M	(DT_MONDAY)
# define T	(DT_TUESDAY)
# define W	(DT_WEDNESDAY)
# define R	(DT_THURSDAY)
# define F	(DT_FRIDAY)
# define A	(DT_SATURDAY)
# define S	(DT_SUNDAY)

static const dt_dow_t __jan01_28y_wday[] = {
	/* 1904 - 1910 */
	F, S, M, T, W, F, A,
	/* 1911 - 1917 */
	S, M, W, R, F, A, M,
	/* 1918 - 1924 */
	T, W, R, A, S, M, T,
	/* 1925 - 1931 */
	R, F, A, S, T, W, R,
};

# undef M
# undef T
# undef W
# undef R
# undef F
# undef A
# undef S

static __attribute__((const, pure)) unsigned int
__get_28y_year_equiv(unsigned year)
{
/* the 28y cycle works for 1901 to 2100, for other years find an equivalent */
	year = year % 400U;

	if (year > 300U) {
		return year + 1600U;
	} else if (year > 200U) {
		return year + 1724U;
	} else if (year > 100U) {
		return year + 1820U;
	}
	return year + 2000;
}

static inline __attribute__((const, pure)) dt_dow_t
__get_jan01_wday(unsigned int year)
{
/* get the weekday of jan01 in YEAR
 * using the 28y cycle thats valid till the year 2399
 * 1920 = 16 mod 28 */
#if !defined WITH_FAST_ARITH
	if (UNLIKELY(year > 2100U ||
#if DT_MIN_YEAR == 1917
		     0
#elif DT_MIN_YEAR == 1753
		     year < 1901U
#elif DT_MIN_YEAR == 1601
		     year < 1901U
#endif
		    )) {
		year = __get_28y_year_equiv(year);
	}
#endif	/* !WITH_FAST_ARITH */
	return __jan01_28y_wday[year % 28U];
}

#elif defined GET_JAN01_WDAY_28Y_SWITCH

static inline __attribute__((const, pure)) dt_dow_t
__get_jan01_wday(unsigned int year)
{
/* get the weekday of jan01 in YEAR
 * using the 28y cycle thats valid till the year 2399
 * 1920 = 16 mod 28
 * switch variant */
# define M	(DT_MONDAY)
# define T	(DT_TUESDAY)
# define W	(DT_WEDNESDAY)
# define R	(DT_THURSDAY)
# define F	(DT_FRIDAY)
# define A	(DT_SATURDAY)
# define S	(DT_SUNDAY)
	switch (year % 28) {
	case 0:
		return F;
	case 1:
		return S;
	case 2:
		return M;
	case 3:
		return T;
	case 4:
		return W;
	case 5:
		return F;
	case 6:
		return A;
	case 7:
		return S;
	case 8:
		return M;
	case 9:
		return W;
	case 10:
		return R;
	case 11:
		return F;
	case 12:
		return A;
	case 13:
		return M;
	case 14:
		return T;
	case 15:
		return W;
	case 16:
		return R;
	case 17:
		return A;
	case 18:
		return S;
	case 19:
		return M;
	case 20:
		return T;
	case 21:
		return R;
	case 22:
		return F;
	case 23:
		return A;
	case 24:
		return S;
	case 25:
		return T;
	case 26:
		return W;
	case 27:
		return R;
	default:
		return DT_MIRACLEDAY;
	}
# undef M
# undef T
# undef W
# undef R
# undef F
# undef A
# undef S
}

#elif defined GET_JAN01_WDAY_SAKAMOTO

static inline __attribute__((const, pure)) dt_dow_t
__get_jan01_wday(unsigned int year)
{
	unsigned int res;

	year--,
		res = year + year / 4 - year / 100 + year / 400 + 1;
	res %= GREG_DAYS_P_WEEK;
	return (dt_dow_t)(res ?: DT_SUNDAY);
}

#endif	/* GET_JAN01_WDAY_* */

#if defined YMD_GET_YD_LOOKUP
static inline __attribute__((const, pure)) unsigned int
__md_get_yday(unsigned int year, unsigned int mon, unsigned int dom)
{
	static uint16_t __mon_yday[] = {
		/* this is \sum ml,
		 * first element is a bit set of leap days to add */
		0xfff8, 0,
		31, 59, 90, 120, 151, 181,
		212, 243, 273, 304, 334, 365
	};
	return __mon_yday[mon] + dom + UNLIKELY(__leapp(year) && mon >= 3);
}

#elif defined YMD_GET_YD_DIVREM
static inline __attribute__((const, pure)) unsigned int
__md_get_yday(unsigned int year, unsigned int mon, unsigned int dom)
{
#define SL(x)	((x) * 5)
#define GET_REM(x)	((rem >> SL(x)) & 0x1f)
	static const uint64_t rem =
		(19ULL << SL(0)) |
		(18ULL << SL(1)) |
		(14ULL << SL(2)) |
		(13ULL << SL(3)) |
		(11ULL << SL(4)) |
		(10ULL << SL(5)) |
		(8ULL << SL(6)) |
		(7ULL << SL(7)) |
		(6ULL << SL(8)) |
		(4ULL << SL(9)) |
		(3ULL << SL(10)) |
		(1ULL << SL(11)) |
		(0ULL << SL(12));
	return (mon - 1) * 32 + GET_REM(mon - 1) - 19 + dom +
		UNLIKELY(__leapp(year) && mon >= 3);
#undef GET_REM
#undef SL
}
#endif	/* YMD_GET_YD_* */

#if defined GET_MD_FREUNDT
/* Freundt's 32-adic algo */
static __attribute__((const, pure)) struct __md_s
__yday_get_md(unsigned int year, unsigned int doy)
{
/* Given a year and the day of the year, return gregorian month + dom
 * we use some clever maths to invert __mon_yday[] above
 * you see __mon_yday[] + 19 divrem 32 is
 *   F   0  0 19
 *   G  31  1 18
 *   H  59  2 14
 *   J  90  3 13
 *   K 120  4 11
 *   M 151  5 10
 *   N 181  6  8
 *   Q 212  7  7
 *   U 243  8  6
 *   V 273  9  4
 *   X 304 10  3
 *   Z 334 11  1
 *     365 12  0
 *
 * Now the key is to store only the remainders in a clever way.
 *
 * So in total the table we store is 5bit remainders of
 * __mon_yday[] + 19 % 32 */
#define GET_REM(x)	(rem[x])
	static const uint8_t rem[] = {
		19, 19, 18, 14, 13, 11, 10, 8, 7, 6, 4, 3, 1, 0

	};
	unsigned int m;
	unsigned int d;
	unsigned int beef;
	unsigned int cake;

	/* get 32-adic doys */
	m = (doy + 19) / 32U;
	d = (doy + 19) % 32U;
	beef = GET_REM(m);
	cake = GET_REM(m + 1);

	/* put leap years into cake */
	if (UNLIKELY(__leapp(year) && cake < 16U)) {
		/* note how all leap-affected cakes are < 16 */
		beef += beef < 16U;
		cake++;
	}

	if (d <= cake) {
		d = doy - ((m - 1) * 32 - 19 + beef);
	} else {
		d = doy - (m++ * 32 - 19 + cake);
	}
	return (struct __md_s){.m = m, .d = d};
#undef GET_REM
}

#elif defined GET_MD_TRIMESTER
/* Trimester algo, we can't figure out which one's faster */
static __attribute__((const, pure)) struct __md_s
__yday_get_md(unsigned int year, unsigned int yday)
{
/* The idea here is that the year can be divided into trimesters:
 * Mar  31   Aug  31   Jan 31
 * Apr  30   Sep  30   Feb 28/29
 * May  31   Oct  31
 * Jun  30   Nov  30
 * Jul  31   Dec  31
 *
 * The first two trimesters have 153 days each, and given one of those
 * the m/d calculation is simply:
 *   m,d <- yday divrem 30.5
 *
 * where 30.5 is achieved by:
 *   m,d <- 2 * yday divrem 61
 * of course.
 *
 * Normally given the trimester and the m,d within the trimester you
 * could assemble the m,d of a gregorian year as:
 *   m <- 5 * trimstr + m + 3
 *   d <- d
 * given 0-counting.  And wrap around months 13 and 14 to 01 and 02;
 * so from this the subtrahend in the 2nd trimester case should be
 * 153 (as opposed to -30 now).
 *
 * We employ a simpler version here that ``inserts'' 2 days after February,
 * yday 60 is 29 Feb, yday 61 is 30 Feb, then proceed as per usual until
 * the end of July where another (unnamed) 30-day month is inserted that
 * goes seamlessly with the 31,30,31,30... cycle */
	int m;
	int d;

	if ((yday -= 1 + __leapp(year)) < 59) {
		/* 3rd trimester */
		yday += __leapp(year);
	} else if ((yday += 2) < 153 + 61) {
		/* 1st trimester */
		;
	} else {
		/* 2nd trimester */
		yday += 30;
	}

	m = 2 * yday / 61;
	d = 2 * yday % 61;
	return (struct __md_s){.m = m + 1 - (m >= 7), .d = d / 2 + 1};
}
#endif	/* GET_MD_* */

static inline __attribute__((const, pure)) dt_dow_t
__get_jan01_yday_dow(unsigned int yd, dt_dow_t w)
{
	unsigned int res = (yd + 6U - (unsigned int)w) % GREG_DAYS_P_WEEK;
	return (dt_dow_t)(DT_SUNDAY - res);
}

#endif	/* YD_ASPECT_HELPERS_ */


#if defined ASPECT_GETTERS && !defined YD_ASPECT_GETTERS_
#define YD_ASPECT_GETTERS_
static inline __attribute__((const, pure)) int
__get_isowk_wd(unsigned int yd, dt_dow_t f01)
{
/* given the weekday the year starts with, F01, and the year-day YD
 * return the iso week number */
	static const int_fast8_t iso[] = {2, 1, 0, -1, -2, 4, 3, 2};
	return (yd - iso[f01]) / GREG_DAYS_P_WEEK + 1;
}

DEFUN __attribute__((const, pure)) int
__yd_get_wcnt_abs(dt_yd_t d)
{
/* absolutely count the n-th occurrence of WD regardless what WD
 * the year started with */
	int yd = d.d;
	/* express yd as 7k + n relative to jan01 */
	return (yd - 1) / 7 + 1;
}

DEFUN __attribute__((const, pure)) int
__yd_get_wcnt_iso(dt_yd_t d)
{
/* like __yd_get_wcnt() but for iso week conventions
 * the week with the first thursday is the first week,
 * so a year starting on S is the first week,
 * a year starting on M is the first week
 * a year starting on T ... */
	/* iso weeks always start on Mon */
	unsigned int y = d.y;
	int yd = d.d;
	unsigned int y01 = __get_jan01_wday(y);
	int wk;

	/* express yd as 7k + n relative to jan01 */
	if (UNLIKELY((wk = __get_isowk_wd(yd, (dt_dow_t)y01)) < 1)) {
		/* get last years y01
		 * which is basically y01 - (365|366 % 7) */
		if (LIKELY(!__leapp(--y))) {
			/* -= 1 */
			y01 += 6;
			yd += 365;
		} else {
			/* -= 2 */
			y01 += 5;
			yd += 366;
		}
		if (y01 > GREG_DAYS_P_WEEK) {
			y01 -= GREG_DAYS_P_WEEK;
		}
		/* same computation now */
		wk = __get_isowk_wd(yd, (dt_dow_t)y01);
	}
	if (UNLIKELY(wk == 53)) {
		/* check next year's y01 */
		if (LIKELY(!__leapp(y))) {
			y01 += 1;
		} else {
			/* -= 2 */
			y01 += 2;
		}
		if (!(y01 == DT_FRIDAY || y01 == DT_SATURDAY)) {
			/* 53rd week is no more */
			wk = 1;
		}
	}
	return wk;
}

DEFUN __attribute__((const, pure)) int
__yd_get_wcnt(dt_yd_t d, dt_dow_t _1st_wd)
{
/* absolutely count the n-th occurrence of WD regardless what WD
 * the year started with */
	unsigned int y = d.y;
	int yd = d.d;
	dt_dow_t y01 = __get_jan01_wday(y);
	int wk;

	/* yd of the FIRST week of the year */
	if ((wk = 8 - (int)y01 + (int)_1st_wd) > 7) {
		wk -= 7;
	}
	/* and now express yd as 7k + n relative to jan01 */
	return (yd - wk + 7) / 7;
}
#endif	/* YD_ASPECT_GETTERS_ */


#if defined ASPECT_DIFF && !defined YD_ASPECT_DIFF_
#define YD_ASPECT_DIFF_
static __attribute__((const, pure)) struct dt_d_s
__yd_diff(dt_yd_t d1, dt_yd_t d2)
{
/* compute d2 - d1 entirely in terms of ymd but express the result as yd */
	struct dt_d_s res = {.typ = DT_YD, .dur = 1};
	signed int tgtd;
	signed int tgty;

	if (d1.u > d2.u) {
		/* swap d1 and d2 */
		dt_yd_t tmp = d1;
		res.neg = 1;
		d1 = d2;
		d2 = tmp;
	}

	/* first compute the difference in years */
	tgty = (d2.y - d1.y);
	/* ... and days */
	tgtd = (d2.d - d1.d);
	/* add leap corrections, this is actually a matrix
	 * ({L,N}x{B,A})^2, Leap/Non-leap, Before/After leap day */
	if (UNLIKELY(__leapp(d1.y)) && LIKELY(d1.d >= 60)) {
		/* LA?? */
		if (UNLIKELY(d1.d == 60)) {
			/* corner case, treat 29 Feb as 01 Mar */
			;
		} else if (!__leapp(d2.y)) {
			/* LAN? */
			tgtd++;
		} else if (d2.d < 60) {
			/* LALB */
			tgtd++;
		}
	} else if (d1.d >= 60 && UNLIKELY(__leapp(d2.y)) && d2.d >= 60) {
		/* NALA */
		tgtd--;
	}
	/* add carry */
	if (tgtd < 0) {
		tgty--;
		tgtd += 365 + ((__leapp(d2.y)) && d2.d >= 60);
	}

	/* fill in the results */
	res.yd.y = tgty;
	res.yd.d = tgtd;
	return res;
}
#endif	/* ASPECT_DIFF */

#undef ASPECT_YD

/* yd.c ends here */
dateutils-0.3.1/lib/ymcw.c000066400000000000000000000332271241477753400154270ustar00rootroot00000000000000/*** ymcw.c -- guts for ymcw dates
 *
 * Copyright (C) 2010-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
#define ASPECT_YMCW

#if !defined DEFUN
# define DEFUN
#endif	/* !DEFUN */


#if !defined YMCW_ASPECT_HELPERS_
#define YMCW_ASPECT_HELPERS_

static __attribute__((pure)) unsigned int
__get_mcnt(unsigned int y, unsigned int m, dt_dow_t w)
{
/* get the number of weekdays W in Y-M, which is the max count
 * for a weekday W in ymcw dates in year Y and month M */
	dt_dow_t wd01 = __get_m01_wday(y, m);
	unsigned int md = __get_mdays(y, m);
	/* the maximum number of WD01s in Y-M */
	unsigned int wd01cnt = (md - 1) / GREG_DAYS_P_WEEK + 1;
	/* modulus */
	unsigned int wd01mod = (md - 1) % GREG_DAYS_P_WEEK;

	/* now the next WD01MOD days also have WD01CNT occurrences
	 * if wd01 + wd01mod exceeds the DAYS_PER_WEEK barrier wrap
	 * around by extending W to W + DAYS_PER_WEEK */
	if ((w >= wd01 && w <= wd01 + wd01mod) ||
	    (w + GREG_DAYS_P_WEEK) <= wd01 + wd01mod) {
		return wd01cnt;
	} else {
		return wd01cnt - 1;
	}
}

static dt_ymcw_t
__ymcw_fixup(dt_ymcw_t d)
{
/* given dates like 2012-02-05-01 this returns 2012-02-04-01 */
	int mc;

	if (LIKELY(d.c <= 4)) {
		/* every month has 4 occurrences of any weekday */
		;
	} else if (d.m == 0 || d.w == DT_MIRACLEDAY) {
		/* um */
		;
	} else if (d.c > (mc = __get_mcnt(d.y, d.m, (dt_dow_t)d.w))) {
		d.c = mc;
	}
	return d;
}
#endif	/* YMCW_ASPECT_HELPERS_ */


#if defined ASPECT_GETTERS && !defined YMCW_ASPECT_GETTERS_
#define YMCW_ASPECT_GETTERS_
static dt_dow_t
__ymcw_get_wday(dt_ymcw_t that)
{
	return (dt_dow_t)(that.w ?: DT_SUNDAY);
}

DEFUN unsigned int
__ymcw_get_yday(dt_ymcw_t that)
{
/* return the N-th W-day in Y, this is equivalent with 8601's Y-W-D calendar
 * where W is the week of the year and D the day in the week */
/* if a year starts on W, then it's
 * 5 Ws in jan
 * 4 Ws in feb
 * 4 Ws in mar
 * 5 Ws in apr
 * 4 Ws in may
 * 4 Ws in jun
 * 5 Ws in jul
 * 4 Ws in aug
 * 4 + leap Ws in sep
 * 5 - leap Ws in oct
 * 4 Ws in nov
 * 5 Ws in dec,
 * so go back to the last W, and compute its number instead
 *
 * Here's the full schema:
 * For W+0
 * 5 4 4 5 4 4  5 4 4 5 4 5  non-leap
 * 5 4 4 5 4 4  5 4 5 4 4 5  leap  flip9
 *
 * For W+1
 * 5 4 4 4 5 4  5 4 4 5 4 4  non-leap
 * 5 4 4 5 4 4  5 4 4 5 4 5  leap  flip4  flip12
 *
 * For W+2
 * 5 4 4 4 5 4  4 5 4 5 4 4  non-leap
 * 5 4 4 4 5 4  5 4 4 5 4 4  leap  flip7
 *
 * For W+3
 * 4 4 5 4 5 4  4 5 4 4 5 4  non-leap
 * 4 5 4 4 5 4  4 5 4 5 4 4  leap  flip2  flip10
 *
 * For W+4
 * 4 4 5 4 4 5  4 5 4 4 5 4  non-leap
 * 4 4 5 4 5 4  4 5 4 4 5 4  leap  flip5
 *
 * For W+5
 * 4 4 5 4 4 5  4 4 5 4 4 5  non-leap
 * 4 4 5 4 4 5  4 5 4 4 5 4  leap  flip8  flip11
 *
 * For W+6
 * 4 4 4 5 4 4  5 4 5 4 4 5  non-leap
 * 4 4 5 4 4 5  4 4 5 4 4 5  leap  flip3  flip6
 *
 * flipN denotes which month in a leap year becomes 5 where the
 * month in the non-leap year equivalent has value 4.
 *
 * The flips for W+1 W+2, W+4, W+5, W+6 can be presented through
 * non-leap rules:
 *
 * 544544544545544544544545
 * 544544545445544544545445
 *
 * 544454544544544454544544
 * 544544544545544544544545 = non-leap W+0
 *
 * 544454454544544454454544
 * 544454544544544454544544 = non-leap W+1
 *
 * 445454454454445454454454
 * 454454454544454454454544
 *
 * 445445454454445445454454
 * 445454454454445454454454 = non-leap W+3
 *
 * 445445445445445445445445
 * 445445454454445445454454 = non-leap W+4
 *
 * 444544545445444544545445
 * 445445445445445445445445 = non-leap W+5
 */
	static uint8_t ycum[][12] = {
		{
			/* W+0 */
			0, 5, 9, 13, 18, 22, 26,  31, 35, 39, 44, 48, /*53*/
		}, {
			/* W+1 */
			0, 5, 9, 13, 17, 22, 26,  31, 35, 39, 44, 48, /*52*/
		}, {
			/* W+2 */
			0, 5, 9, 13, 17, 22, 26,  30, 35, 39, 44, 48, /*52*/
		}, {
			/* W+3 */
			0, 4, 8, 13, 17, 22, 26,  30, 35, 39, 43, 48, /*52*/
		}, {
			/* W+4 */
			0, 4, 8, 13, 17, 21, 26,  30, 35, 39, 43, 48, /*52*/
		}, {
			/* W+5 */
			0, 4, 8, 13, 17, 21, 26,  30, 34, 39, 43, 47, /*52*/
		}, {
			/* W+6 */
			0, 4, 8, 12, 17, 21, 25,  30, 34, 39, 43, 47, /*52*/
		}, {
			/* leap-year rule W+0 */
			0, 5, 9, 13, 18, 22, 26,  31, 35, 40, 44, 48, /*53*/
			/* leap-year rule W+3 = W+0 + 1mo + 4 */
		},
	};
	dt_dow_t j01w = __get_jan01_wday(that.y);
	unsigned int diff = j01w <= that.w ? that.w - j01w : that.w + 7 - j01w;

	if (UNLIKELY(__leapp(that.y))) {
		switch (diff) {
		case 3:
			if (UNLIKELY(that.m < 2)) {
				return that.c;
			}
			return that.c + (ycum[7])[that.m - 2] + 4;
		case 0:
			return that.c + (ycum[7])[that.m - 1];
		default:
		case 1:
		case 2:
		case 4:
		case 5:
		case 6:
			diff--;
			break;
		}
	}
	return that.c + (ycum[diff])[that.m - 1];
}

static unsigned int
__ymcw_get_mday(dt_ymcw_t that)
{
	unsigned int wd01;
	unsigned int res;

	/* see what weekday the first of the month was*/
	wd01 = __get_m01_wday(that.y, that.m);

	/* first WD1 is 1, second WD1 is 8, third WD1 is 15, etc.
	 * so the first WDx with WDx > WD1 is on (WDx - WD1) + 1 */
	res = (that.w + GREG_DAYS_P_WEEK - wd01) % GREG_DAYS_P_WEEK + 1;
	res += GREG_DAYS_P_WEEK * (that.c - 1);
	/* not all months have a 5th X, so check for this */
	if (res > __get_mdays(that.y, that.m)) {
		 /* 5th = 4th in that case */
		res -= GREG_DAYS_P_WEEK;
	}
	return res;
}

static int
__ymcw_get_bday(dt_ymcw_t that, dt_bizda_param_t bp)
{
	dt_dow_t wd01;
	int res;

	switch (that.w) {
	case DT_SUNDAY:
	case DT_SATURDAY:
		return -1;
	default:
		break;
	}
	if (bp.ab != BIZDA_AFTER || bp.ref != BIZDA_ULTIMO) {
		/* no support yet */
		return -1;
	}

	/* weekday the month started with */
	wd01 = __get_m01_wday(that.y, that.m);
	res = (signed int)(that.w - wd01) + DUWW_BDAYS_P_WEEK * (that.c) + 1;
	return res;
}
#endif	/* YMCW_ASPECT_GETTERS_ */


#if defined ASPECT_CONV && !defined YMCW_ASPECT_CONV_
#define YMCW_ASPECT_CONV_
/* we need some getter stuff, so get it */
#define ASPECT_GETTERS
#include "ymcw.c"
#undef ASPECT_GETTERS

static dt_ymd_t
__ymcw_to_ymd(dt_ymcw_t d)
{
	unsigned int md = __ymcw_get_mday(d);
#if defined HAVE_ANON_STRUCTS_INIT
	return (dt_ymd_t){.y = d.y, .m = d.m, .d = md};
#else  /* !HAVE_ANON_STRUCTS_INIT */
	dt_ymd_t res;
	res.y = d.y;
	res.m = d.m;
	res.d = md;
	return res;
#endif	/* HAVE_ANON_STRUCTS_INIT */
}

static dt_ywd_t
__ymcw_to_ywd(dt_ymcw_t d)
{
	unsigned int y = d.y;
	dt_dow_t w = (dt_dow_t)d.w;
	unsigned int c = __ymcw_get_yday(d);
	return __make_ywd_c(y, c, w, YWD_ABSWK_CNT);
}

static dt_daisy_t
__ymcw_to_daisy(dt_ymcw_t d)
{
	dt_daisy_t res;
	unsigned int sy = d.y;
	unsigned int sm = d.m;
	unsigned int sd;

	if (UNLIKELY((signed int)TO_BASE(sy) < 0)) {
		return 0;
	}

	sd = __ymcw_get_mday(d);
	res = __jan00_daisy(sy);
	res += __md_get_yday(sy, sm, sd);
	return res;
}

static dt_yd_t
__ymcw_to_yd(dt_ymcw_t d)
{
	unsigned int sd = __ymcw_get_mday(d);
	unsigned int sm = d.m;
	unsigned int sy = d.y;

#if defined HAVE_ANON_STRUCTS_INIT
	return (dt_yd_t){.y = sy, .d = __md_get_yday(sy, sm, sd)};
#else
	dt_yd_t res;
	res.y = sy;
	res.d = __md_get_yday(sy, sm, sd);
	return res;
#endif
}
#endif	/* ASPECT_CONV */


#if defined ASPECT_ADD && !defined YMCW_ASPECT_ADD_
#define YMCW_ASPECT_ADD_

static dt_ymcw_t
__ymcw_fixup_c(unsigned int y, signed int m, signed int c, dt_dow_t w)
{
	dt_ymcw_t res = {0};

	/* fixup q */
	if (LIKELY(c >= 1 && c <= 4)) {
		/* all months in our design range have 4 occurrences of
		 * any weekday, so YAAAY*/
		;
	} else if (c < 1) {
		int mc;

		do {
			if (UNLIKELY(--m < 1)) {
				--y;
				m = GREG_MONTHS_P_YEAR;
			}
			mc = __get_mcnt(y, m, w);
			c += mc;
		} while (c < 1);
	} else {
		int mc;

		while (c > (mc = __get_mcnt(y, m, w))) {
			c -= mc;
			if (UNLIKELY(++m > (signed int)GREG_MONTHS_P_YEAR)) {
				++y;
				m = 1;
			}
		}
	}

	/* final assignment */
	res.y = y;
	res.m = m;
	res.c = c;
	res.w = w;
	return res;
}

static dt_ymcw_t
__ymcw_add_w(dt_ymcw_t d, int n)
{
/* add N weeks to D */
	signed int tgtc = d.c + n;

	return __ymcw_fixup_c(d.y, d.m, tgtc, (dt_dow_t)d.w);
}

static dt_ymcw_t
__ymcw_add_d(dt_ymcw_t d, int n)
{
/* add N days to D
 * we reduce this to __ymcw_add_w() */
	signed int aw = n / (signed int)GREG_DAYS_P_WEEK;
	signed int ad = n % (signed int)GREG_DAYS_P_WEEK;

	if ((ad += d.w) >= (signed int)GREG_DAYS_P_WEEK) {
		ad -= GREG_DAYS_P_WEEK;
		aw++;
	} else if (ad < 0) {
		ad += GREG_DAYS_P_WEEK;
		aw--;
	}

	/* fixup for abswk count, m01 may be any wd */
	{
		dt_dow_t m01 = __get_m01_wday(d.y, d.m);

		if ((dt_dow_t)d.w < m01 && (dt_dow_t)ad >= m01) {
			aw++;
		} else if ((dt_dow_t)d.w >= m01 && (dt_dow_t)ad < m01) {
			aw--;
		}
	}

	d.w = (dt_dow_t)ad;
	return __ymcw_add_w(d, aw);
}

static dt_ymcw_t
__ymcw_add_b(dt_ymcw_t d, int n)
{
/* add N business days to D */
#if 0
/* trivial trait, reduce to _add_d() problem and dispatch */
	dt_dow_t wd = __ymcw_get_wday(d);
	return __ymcw_add_d(d, __get_d_equiv(wd, n));
#else
	signed int aw = n / (signed int)DUWW_BDAYS_P_WEEK;
	signed int ad = n % (signed int)DUWW_BDAYS_P_WEEK;

	if ((ad += d.w) > (signed int)DUWW_BDAYS_P_WEEK) {
		ad -= DUWW_BDAYS_P_WEEK;
		aw++;
	} else if (ad <= 0) {
		ad += DUWW_BDAYS_P_WEEK;
		aw--;
	}

	/* fixup for abswk count, m01 may be any wd */
	{
		dt_dow_t m01 = __get_m01_wday(d.y, d.m);

		if ((dt_dow_t)d.w < m01 && (dt_dow_t)ad >= m01) {
			aw++;
		} else if ((dt_dow_t)d.w >= m01 && (dt_dow_t)ad < m01) {
			aw--;
		}
	}

	d.w = (dt_dow_t)ad;
	return __ymcw_add_w(d, aw);
#endif
}

static dt_ymcw_t
__ymcw_add_m(dt_ymcw_t d, int n)
{
/* add N months to D */
	signed int tgtm = d.m + n;

	while (tgtm > (signed int)GREG_MONTHS_P_YEAR) {
		tgtm -= GREG_MONTHS_P_YEAR;
		++d.y;
	}
	while (tgtm < 1) {
		tgtm += GREG_MONTHS_P_YEAR;
		--d.y;
	}
	/* final assignment */
	d.m = tgtm;
	return __ymcw_fixup(d);
}

static dt_ymcw_t
__ymcw_add_y(dt_ymcw_t d, int n)
{
/* add N years to D */
	d.y += n;
	return __ymcw_fixup(d);
}
#endif	/* ASPECT_ADD */


#if defined ASPECT_DIFF && !defined YMCW_ASPECT_DIFF_
#define YMCW_ASPECT_DIFF_

static struct dt_d_s
__ymcw_diff(dt_ymcw_t d1, dt_ymcw_t d2)
{
/* compute d2 - d1 entirely in terms of ymd */
	struct dt_d_s res = {.typ = DT_YMCW, .dur = 1};
	signed int tgtd;
	signed int tgtm;
	dt_dow_t wd01, wd02;

	if (__ymcw_cmp(d1, d2) > 0) {
		dt_ymcw_t tmp = d1;
		d1 = d2;
		d2 = tmp;
		res.neg = 1;
	}

	wd01 = __get_m01_wday(d1.y, d1.m);
	if (d2.y != d1.y || d2.m != d1.m) {
		wd02 = __get_m01_wday(d2.y, d2.m);
	} else {
		wd02 = wd01;
	}

	/* first compute the difference in months Y2-M2-01 - Y1-M1-01 */
	tgtm = GREG_MONTHS_P_YEAR * (d2.y - d1.y) + (d2.m - d1.m);
	/* using the firsts of the month WD01, represent d1 and d2 as
	 * the C-th WD01 plus OFF */
	{
		unsigned int off1;
		unsigned int off2;

		off1 = __uimod(d1.w - wd01, GREG_DAYS_P_WEEK);
		off2 = __uimod(d2.w - wd02, GREG_DAYS_P_WEEK);
		tgtd = off2 - off1 + GREG_DAYS_P_WEEK * (d2.c - d1.c);
	}

	/* fixups */
	if (tgtd < (signed int)GREG_DAYS_P_WEEK && tgtm > 0) {
		/* if tgtm is 0 it remains 0 and tgtd remains negative */
		/* get the target month's mdays */
		unsigned int d2m = d2.m;
		unsigned int d2y = d2.y;

		if (--d2m < 1) {
			d2m = GREG_MONTHS_P_YEAR;
			d2y--;
		}
		tgtd += __get_mdays(d2y, d2m);
		tgtm--;
	}

	/* fill in the results */
	res.ymcw.y = tgtm / GREG_MONTHS_P_YEAR;
	res.ymcw.m = tgtm % GREG_MONTHS_P_YEAR;
	res.ymcw.c = tgtd / GREG_DAYS_P_WEEK;
	res.ymcw.w = tgtd % GREG_DAYS_P_WEEK;
	return res;
}
#endif	/* ASPECT_DIFF */


#if defined ASPECT_CMP && !defined YMCW_ASPECT_CMP_
#define YMCW_ASPECT_CMP_
DEFUN int
__ymcw_cmp(dt_ymcw_t d1, dt_ymcw_t d2)
{
	if (d1.y < d2.y) {
		return -1;
	} else if (d1.y > d2.y) {
		return 1;
	} else if (d1.m < d2.m) {
		return -1;
	} else if (d1.m > d2.m) {
		return 1;
	}

	/* we're down to counts, however, the last W of a month is always
	 * count 5, even though counting forward it would be 4 */
	if (d1.c < d2.c) {
		return -1;
	} else if (d1.c > d2.c) {
		return 1;
	}
	/* now it's up to the first of the month */
	{
		dt_dow_t wd01;
		unsigned int off1;
		unsigned int off2;

		wd01 = __get_m01_wday(d1.y, d1.m);
		/* represent cw as C-th WD01 + OFF */
		off1 = __uimod(d1.w - wd01, GREG_DAYS_P_WEEK);
		off2 = __uimod(d2.w - wd01, GREG_DAYS_P_WEEK);

		if (off1 < off2) {
			return -1;
		} else if (off1 > off2) {
			return 1;
		} else {
			return 0;
		}
	}
}
#endif	/* ASPECT_CMP */


#if defined ASPECT_STRF && !defined YMCW_ASPECT_STRF_
#define YMCW_ASPECT_STRF_

#endif	/* ASPECT_STRF */

/* ymcw.c ends here */
dateutils-0.3.1/lib/ymd.c000066400000000000000000000402501241477753400152330ustar00rootroot00000000000000/*** ymd.c -- guts for ymd dates
 *
 * Copyright (C) 2010-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
/* set aspect temporarily */
#define ASPECT_YMD
/* permanent aspect, to be read as have we ever seen aspect_ymd */
#if !defined ASPECT_YMD_
#define ASPECT_YMD_
#endif	/* !ASPECT_YMD_ */

#include "nifty.h"

/* some algorithmic choices */
#if defined YMD_GET_WDAY_LOOKUP
#elif defined YMD_GET_WDAY_ZELLER
#elif defined YMD_GET_WDAY_SAKAMOTO
#elif defined YMD_GET_WDAY_7YM_ALL
#elif defined YMD_GET_WDAY_7YM_REP
#else
/* default algo */
# define YMD_GET_WDAY_LOOKUP
#endif

#if !defined DEFUN
# define DEFUN
#endif	/* !DEFUN */


#if !defined YMD_ASPECT_HELPERS_
#define YMD_ASPECT_HELPERS_
DEFUN __attribute__((pure)) inline unsigned int
__get_mdays(unsigned int y, unsigned int m)
{
/* get the number of days in Y-M */
	unsigned int res;

	if (UNLIKELY(m < 1 || m > GREG_MONTHS_P_YEAR)) {
		return 0;
	}

	/* use our cumulative yday array */
	res = __md_get_yday(y, m + 1, 0);
	return res - __md_get_yday(y, m, 0);
}

static __attribute__((pure)) dt_ymd_t
__ymd_fixup(dt_ymd_t d)
{
/* given dates like 2012-02-32 this returns 2012-02-29 */
	int mdays;

	if (LIKELY(d.d <= 28)) {
		/* every month has 28 days in our range */
		;
	} else if (UNLIKELY(d.m == 0 || d.m > GREG_MONTHS_P_YEAR)) {
		;
	} else if (d.d > (mdays = __get_mdays(d.y, d.m))) {
		d.d = mdays;
	}
	return d;
}

static dt_dow_t
__get_m01_wday(unsigned int year, unsigned int mon)
{
/* get the weekday of the first of MONTH in YEAR */
	unsigned int off;
	dt_dow_t cand;

	if (UNLIKELY(mon < 1 || mon > GREG_MONTHS_P_YEAR)) {
		return DT_MIRACLEDAY;
	}
	cand = __get_jan01_wday(year);
	off = __md_get_yday(year, mon, 0);
	off = (cand + off) % GREG_DAYS_P_WEEK;
	return (dt_dow_t)(off ?: DT_SUNDAY);
}

#if defined YMD_GET_WDAY_LOOKUP
/* lookup version */
static dt_dow_t
__get_dom_wday(unsigned int year, unsigned int mon, unsigned int dom)
{
	unsigned int yd;
	unsigned int j01_wd;

	if ((yd = __md_get_yday(year, mon, dom)) > 0 &&
	    (j01_wd = __get_jan01_wday(year)) != DT_MIRACLEDAY) {
		unsigned int wd = (yd - 1 + j01_wd) % GREG_DAYS_P_WEEK;
		return (dt_dow_t)(wd ?: DT_SUNDAY);
	}
	return DT_MIRACLEDAY;
}

#elif defined YMD_GET_WDAY_ZELLER
/* Zeller algorithm */
static dt_dow_t
__get_dom_wday(int year, int mon, int dom)
{
/* this is Zeller's method, but there's a problem when we use this for
 * the bizda calendar. */
	int w;
	int c, x;
	int d, y;
	unsigned int wd;

	if ((mon -= 2) <= 0) {
		mon += 12;
		year--;
	}

	d = year / 100;
	c = year % 100;
	x = c / 4;
	y = d / 4;

	w = (13 * mon - 1) / 5;
	wd = (w + x + y + dom + c - 2 * d) % GREG_DAYS_P_WEEK;
	return (dt_dow_t)(wd ?: DT_SUNDAY);
}
#elif defined YMD_GET_WDAY_SAKAMOTO
/* Sakamoto method */
static dt_dow_t
__get_dom_wday(int year, int mon, int dom)
{
	static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
	int res;
	unsigned int wd;

	year -= mon < 3;
	res = year + year / 4 - year / 100 + year / 400;
	res += t[mon - 1] + dom;
	wd = (unsigned int)res % GREG_DAYS_P_WEEK;
	return (dt_dow_t)(wd ?: DT_SUNDAY);
}

#elif defined YMD_GET_WDAY_7YM_ALL || defined YMD_GET_WDAY_7YM_REP
/* this one's work in progress
 * first observe the 7 patterns in months FG and H..Z and how leap years
 * correspond to ordinary years.
 *
 * Use:
 *   dseq 1917-01-01 1mo 2417-12-01 -f '%Y %m %_a' |           \
 *     awk 'BEGIN{FS=" "}                                      \
 *          {a[$1] = "" a[$1] "" ($2=="03" ? " " : "") "" $3;} \
 *          END{for (i in a) print(i "\t" a[i]);}' |           \
 *     sort | sort -k3 -k2 -u
 *
 * for instance to get this table (months FG and months H..Z):
 *   1924	TF ATRSTFMWAM
 *   1919	WA ATRSTFMWAM
 *   1940	MR FMWAMRSTFS
 *   1918	TF FMWAMRSTFS
 *   1926	FM MRATRSWFMW
 *   1920	RS MRATRSWFMW
 *   1917	MR RSTFSWAMRA
 *   1928	SW RSTFSWAMRA
 *   1925	RS SWFMWATRST
 *   1936	WA SWFMWATRST
 *   1921	AT TFSWFMRATR
 *   1932	FM TFSWFMRATR
 *   1944	AT WAMRATFSWF
 *   1922	SW WAMRATFSWF
 *
 * and note how leap years and ordinary years pair up.
 *
 * After a bit of number crunching (consider all years mod 28) we'll find:
 *           H..Z
 *  0 -> 6 -> 17 -> 23
 *  4 -> 10 -> 21 -> 27
 *  8 -> 14 -> 25 -> 3
 * 12 -> 18 -> 1 -> 7
 * 16 -> 22 -> 5 -> 11
 * 20 -> 26 -> 9 -> 15
 * 24 -> 2 -> 13 -> 19
 *
 * where obviously the FG years are a permutation (13 14 15 21 22 17 18)^-1
 * of the H..Z years.
 *
 * It's quite easy to see how this system forms an orbit through C28 via:
 *
 *   [0]C4 + 0 = [4]C4 + 1 = [1]C4 + 2 = [5]C4 + 3
 *   [1]C4 + 0 = [5]C4 + 1 = [2]C4 + 2 = [6]C4 + 3
 *   [2]C4 + 0 = [6]C4 + 1 = [3]C4 + 2 = [0]C4 + 3
 *   [3]C4 + 0 = [0]C4 + 1 = [4]C4 + 2 = [1]C4 + 3
 *   [4]C4 + 0 = [1]C4 + 1 = [5]C4 + 2 = [2]C4 + 3
 *   [5]C4 + 0 = [2]C4 + 1 = [6]C4 + 2 = [3]C4 + 3
 *   [6]C4 + 0 = [3]C4 + 1 = [0]C4 + 2 = [4]C4 + 3
 *
 * and so by decomposing a year mod 28 and into C7*C4 we can map it to the
 * weekday.
 *
 * Here's the algo:
 * input: year
 * output: idx, weekday series index for H..
 *
 * year <- year mod 28
 * x,y  <- decompose year as [x]C4 + y
 * idx  <- x - 0, if y = 0
 *         x - 4, if y = 1
 *         x - 1, if y = 2
 *         x - 5, if y = 3
 *
 * Proceed similar for FG series.
 * That's how the formulas below came into being.
 *
 * For the shortened version (REP for representant) you have observe
 * that from leap year to leap year the weekday difference for each
 * respective month is 5. */
static unsigned int
__get_widx_H(unsigned int y)
{
/* return the equivalence class number for H.. weekdays for year Y. */
	static unsigned int add[] = {0, 3, 6, 2};
	unsigned int idx, res;

	y = y % 28U;
	idx = y / 4U;
	res = y % 4U;
	return (idx + add[res]) % GREG_DAYS_P_WEEK;
}

static unsigned int
__get_widx_FG(unsigned int y)
{
/* return the equivalence class number for FG weekdays for year Y. */
	static unsigned int add[] = {0, 6, 2, 5};
	unsigned int idx, res;

	y = y % 28U;
	idx = y / 4U;
	res = y % 4U;
	return (idx + add[res]) % GREG_DAYS_P_WEEK;
}

#if !defined WITH_FAST_ARITH
static inline __attribute__((pure)) unsigned int
__get_28y_year_equiv_H(unsigned year)
{
/* like __get_28y_year_equiv() but for months H..Z
 * needed for 7YM algo */
	year = year % 400U;

	if (year >= 300U) {
		return year + 1600U;
	} else if (year >= 200U) {
		return year + 1724U;
	} else if (year >= 100U) {
		return year + 1820U;
	}
	return year + 2000;
}
#endif	/* !WITH_FAST_ARITH */

#if defined YMD_GET_WDAY_7YM_ALL
static inline __attribute__((pure)) unsigned int
__get_ser(unsigned int class, unsigned int mon)
{
# define M	(DT_MONDAY)
# define T	(DT_TUESDAY)
# define W	(DT_WEDNESDAY)
# define R	(DT_THURSDAY)
# define F	(DT_FRIDAY)
# define A	(DT_SATURDAY)
# define S	(DT_SUNDAY)
	static uint8_t ser[][12] = {
		{
			/* 1932 = [[0]C4 + 0]C28 */
			F, M,  T, F, S, W, F, M, R, A, T, R,
		}, {
			/* 1936 = [[1]C4 + 0]C28 */
			W, A,  S, W, F, M, W, A, T, R, S, T,
		}, {
			/* 1940 = [[2]C4 + 0]C28 */
			M, R,  F, M, W, A, M, R, S, T, F, S,
		}, {
			/* 1944 = [[3]C4 + 0]C28 */
			A, T,  W, A, M, R, A, T, F, S, W, F,
		}, {
			/* 1920 = [[4]C4 + 0]C28 */
			R, S,  M, R, A, T, R, S, W, F, M, W,
		}, {
			/* 1924 = [[5]C4 + 0]C28 */
			T, F,  A, T, R, S, T, F, M, W, A, M,
		}, {
			/* 1928 = [[6]C4 + 0]C28 */
			S, W,  R, S, T, F, S, W, A, M, R, A,
		},
	};
# undef M
# undef T
# undef W
# undef R
# undef F
# undef A
# undef S
	return ser[class][mon];
}
#elif defined YMD_GET_WDAY_7YM_REP
static inline __attribute__((pure)) unsigned int
__get_ser(unsigned int class, unsigned int mon)
{
# define M	(DT_MONDAY)
# define T	(DT_TUESDAY)
# define W	(DT_WEDNESDAY)
# define R	(DT_THURSDAY)
# define F	(DT_FRIDAY)
# define A	(DT_SATURDAY)
# define S	(DT_SUNDAY)
	static unsigned int ser[12] = {
		/* 1932 = [[0]C4 + 0]C28 */
		F, M,  T, F, S, W, F, M, R, A, T, R,
	};
# undef M
# undef T
# undef W
# undef R
# undef F
# undef A
# undef S
	return ser[mon] + 5 * class;
}
#endif	/* 7YM_ALL | 7YM_RES */

static dt_dow_t
__get_dom_wday(unsigned int year, unsigned int mon, unsigned int dom)
{
	unsigned int bm = mon - 1;
	unsigned int bd = dom - 1;
	unsigned int idx;
	unsigned int wd;

	if (bm < 2U) {
		/* FG */
#if defined WITH_FAST_ARITH
		unsigned int by = year;
#else  /* !WITH_FAST_ARITH */
		unsigned int by = __get_28y_year_equiv(year);
#endif	/* !WITH_FAST_ARITH */
		idx = __get_widx_FG(by);
	} else {
#if defined WITH_FAST_ARITH
		unsigned int by = year;
#else  /* !WITH_FAST_ARITH */
		unsigned int by = __get_28y_year_equiv_H(year);
#endif  /* !WITH_FAST_ARITH */
		idx = __get_widx_H(by);
	}

	wd = (__get_ser(idx, bm) + bd) % GREG_DAYS_P_WEEK;
	return (dt_dow_t)(wd ?: DT_SUNDAY);
}

#endif	/* 0 */

/* try to get helpers like __get_d_equiv() et al */
#include "bizda.c"
#endif	/* YMD_ASPECT_HELPERS_ */


#if defined ASPECT_GETTERS && !defined YMD_ASPECT_GETTERS_
#define YMD_ASPECT_GETTERS_
static unsigned int
__ymd_get_yday(dt_ymd_t that)
{
	unsigned int res;

	if (UNLIKELY(that.y == 0 ||
		     that.m == 0 || that.m > GREG_MONTHS_P_YEAR)) {
		return 0;
	}
	/* process */
	res = __md_get_yday(that.y, that.m, that.d);
	return res;
}

static dt_dow_t
__ymd_get_wday(dt_ymd_t that)
{
	return __get_dom_wday(that.y, that.m, that.d);
}

DEFUN unsigned int
__ymd_get_count(dt_ymd_t that)
{
/* get N where N is the N-th occurrence of wday in the month of that year */
#if 0
/* this proves to be a disaster when comparing ymcw dates */
	if (UNLIKELY(that.d + GREG_DAYS_P_WEEK > __get_mdays(that.y, that.m))) {
		return 5;
	}
#endif
	return (that.d - 1U) / GREG_DAYS_P_WEEK + 1U;
}

static int
__ymd_get_wcnt_abs(dt_ymd_t d)
{
/* absolutely count the n-th occurrence of WD regardless what WD
 * the year started with
 * generally the path ymd->yd->get_wcnt_abs() is preferred */
	int yd = __ymd_get_yday(d);

	/* and now express yd as 7k + n relative to jan01 */
	return (yd - 1) / 7 + 1;
}

static int
__ymd_get_bday(dt_ymd_t that, dt_bizda_param_t bp)
{
	dt_dow_t wdd;

	if (bp.ab != BIZDA_AFTER || bp.ref != BIZDA_ULTIMO) {
		/* no support yet */
		return -1;
	}

	/* weekday the month started with */
	switch ((wdd = __ymd_get_wday(that))) {
	case DT_SUNDAY:
	case DT_SATURDAY:
		return -1;
	case DT_MONDAY:
	case DT_TUESDAY:
	case DT_WEDNESDAY:
	case DT_THURSDAY:
	case DT_FRIDAY:
	case DT_MIRACLEDAY:
	default:
		break;
	}
	/* get the number of business days between 1 and that.d */
	return __get_nbdays(that.d, wdd);
}
#endif	/* YMD_ASPECT_GETTERS_ */


#if defined ASPECT_CONV && !defined YMD_ASPECT_CONV_
#define YMD_ASPECT_CONV_
/* we need some getter stuff, so get it */
#define ASPECT_GETTERS
#include "ymd.c"
#undef ASPECT_GETTERS

static dt_ymcw_t
__ymd_to_ymcw(dt_ymd_t d)
{
	unsigned int c = __ymd_get_count(d);
	unsigned int w = __ymd_get_wday(d);
#if defined HAVE_ANON_STRUCTS_INIT
	return (dt_ymcw_t){.y = d.y, .m = d.m, .c = c, .w = w};
#else
	dt_ymcw_t res;
	res.y = d.y;
	res.m = d.m;
	res.c = c;
	res.w = w;
	return res;
#endif
}

static dt_ywd_t
__ymd_to_ywd(dt_ymd_t d)
{
	dt_dow_t w = __ymd_get_wday(d);
	unsigned int c = __ymd_get_wcnt_abs(d);
	return __make_ywd_c(d.y, c, w, YWD_ABSWK_CNT);
}

static dt_daisy_t
__ymd_to_daisy(dt_ymd_t d)
{
	dt_daisy_t res;
	unsigned int sy = d.y;
	unsigned int sm = d.m;
	unsigned int sd;

	if (UNLIKELY((signed int)TO_BASE(sy) < 0)) {
		return 0;
	}

#if !defined WITH_FAST_ARITH || defined OMIT_FIXUPS
	/* the non-fast arith has done the fixup already */
	sd = d.d;
#else  /* WITH_FAST_ARITH && !OMIT_FIXUPS */
	{
		unsigned int tmp = __get_mdays(sy, sm);
		if (UNLIKELY((sd = d.m) > tmp)) {
			sd = tmp;
		}
	}
#endif	/* !WITH_FAST_ARITH || OMIT_FIXUPS */

	res = __jan00_daisy(sy);
	res += __md_get_yday(sy, sm, sd);
	return res;
}

static dt_yd_t
__ymd_to_yd(dt_ymd_t d)
{
	int yd = __ymd_get_yday(d);
#if defined HAVE_ANON_STRUCTS_INIT
	return (dt_yd_t){.y = d.y, .d = yd};
#else
	dt_yd_t res;
	res.y = d.y;
	res.d = yd;
	return res;
#endif
}
#endif	/* ASPECT_CONV */


#if defined ASPECT_ADD && !defined YMD_ASPECT_ADD_
#define YMD_ASPECT_ADD_
static __attribute__((pure)) dt_ymd_t
__ymd_fixup_d(unsigned int y, signed int m, signed int d)
{
	dt_ymd_t res = {0};

	if (LIKELY(d >= 1 && d <= 28)) {
		/* all months in our design range have at least 28 days */
		;
	} else if (d < 1) {
		int mdays;

		do {
			if (UNLIKELY(--m < 1)) {
				--y;
				m = GREG_MONTHS_P_YEAR;
			}
			mdays = __get_mdays(y, m);
			d += mdays;
		} while (d < 1);

	} else {
		int mdays;

		while (d > (mdays = __get_mdays(y, m))) {
			d -= mdays;
			if (UNLIKELY(++m > (signed int)GREG_MONTHS_P_YEAR)) {
				++y;
				m = 1;
			}
		}
	}

	res.y = y;
	res.m = m;
	res.d = d;
	return res;
}

static dt_ymd_t
__ymd_add_d(dt_ymd_t d, int n)
{
/* add N days to D */
	signed int tgtd = d.d + n;

	/* fixup the day */
	return __ymd_fixup_d(d.y, d.m, tgtd);
}

static dt_ymd_t
__ymd_add_b(dt_ymd_t d, int n)
{
/* add N business days to D */
	dt_dow_t wd = __ymd_get_wday(d);
	int tgtd = d.d + __get_d_equiv(wd, n);

	/* fixup the day, i.e. 2012-01-34 -> 2012-02-03 */
	return __ymd_fixup_d(d.y, d.m, tgtd);
}

static dt_ymd_t
__ymd_add_w(dt_ymd_t d, int n)
{
/* add N weeks to D */
	return __ymd_add_d(d, GREG_DAYS_P_WEEK * n);
}

static dt_ymd_t
__ymd_add_m(dt_ymd_t d, int n)
{
/* add N months to D */
	signed int tgtm = d.m + n;

	while (tgtm > (signed int)GREG_MONTHS_P_YEAR) {
		tgtm -= GREG_MONTHS_P_YEAR;
		++d.y;
	}
	while (tgtm < 1) {
		tgtm += GREG_MONTHS_P_YEAR;
		--d.y;
	}
	/* final assignment */
	d.m = tgtm;
	return __ymd_fixup(d);
}

static dt_ymd_t
__ymd_add_y(dt_ymd_t d, int n)
{
/* add N years to D */
	d.y += n;
	return __ymd_fixup(d);
}
#endif	/* ASPECT_ADD */


#if defined ASPECT_DIFF && !defined YMD_ASPECT_DIFF_
#define YMD_ASPECT_DIFF_
static struct dt_d_s
__ymd_diff(dt_ymd_t d1, dt_ymd_t d2)
{
/* compute d2 - d1 entirely in terms of ymd */
	struct dt_d_s res = {.typ = DT_YMD, .dur = 1};
	signed int tgtd;
	signed int tgtm;

	if (d1.u > d2.u) {
		/* swap d1 and d2 */
		dt_ymd_t tmp = d1;
		res.neg = 1;
		d1 = d2;
		d2 = tmp;
	}

	/* first compute the difference in months Y2-M2-01 - Y1-M1-01 */
	tgtm = GREG_MONTHS_P_YEAR * (d2.y - d1.y) + (d2.m - d1.m);
	if ((tgtd = d2.d - d1.d) < 0 && tgtm != 0) {
		/* if tgtm is 0 it remains 0 and tgtd remains negative */
		/* get the target month's mdays */
		unsigned int d2m = d2.m;
		unsigned int d2y = d2.y;

		if (--d2m < 1) {
			d2m = GREG_MONTHS_P_YEAR;
			d2y--;
		}
		tgtd += __get_mdays(d2y, d2m);
		tgtm--;
#if !defined WITH_FAST_ARITH || defined OMIT_FIXUPS
		/* the non-fast arith has done the fixup already */
#else  /* WITH_FAST_ARITH && !defined OMIT_FIXUPS */
	} else if (tgtm == 0) {
		/* check if we're not diffing two lazy representations
		 * e.g. 2010-02-28 and 2010-02-31 */
		;
#endif	/* !OMIT_FIXUPS */
	}
	/* fill in the results */
	res.ymd.y = tgtm / GREG_MONTHS_P_YEAR;
	res.ymd.m = tgtm % GREG_MONTHS_P_YEAR;
	res.ymd.d = tgtd;
	return res;
}
#endif	/* ASPECT_DIFF */


#if defined ASPECT_STRF && !defined YMD_ASPECT_STRF_
#define YMD_ASPECT_STRF_

#endif	/* ASPECT_STRF */

#undef ASPECT_YMD

/* ymd.c ends here */
dateutils-0.3.1/lib/ywd.c000066400000000000000000000423351241477753400152530ustar00rootroot00000000000000/*** ywd.c -- guts for ywd dates
 *
 * Copyright (C) 2012-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
/* this is an attempt to code aspect-oriented */
#define ASPECT_YWD

#include "nifty.h"

#if !defined DEFUN
# define DEFUN
#endif	/* !DEFUN */

/* table of 53-week years (years % 400)

  {4, 9, 15, 20, 26, 32, 37, 43, 48, 54, 60, 65, 71, 76, 82, 88, 93, 99, 105,
  111, 116, 122, 128, 133, 139, 144, 150, 156, 161, 167, 172, 178, 184, 189,
  195, 201, 207, 212, 218, 224, 229, 235, 240, 246, 252, 257, 263, 268, 274,
  280, 285, 291, 296, 303, 308, 314, 320, 325, 331, 336, 342, 348, 353, 359,
  364, 370, 376, 381, 387, 392, 398};

  we could use gperf to get a perfect hash, thank god the list is fixed, but
  at the moment we let the compiler work it out
 */

#if defined GET_ISOWK_FULL_SWITCH
#elif defined GET_ISOWK_28Y_SWITCH
#else
# define GET_ISOWK_FULL_SWITCH
#endif


#if !defined YWD_ASPECT_HELPERS_
#define YWD_ASPECT_HELPERS_
static dt_dow_t
__ywd_get_jan01_wday(dt_ywd_t d)
{
/* hang of 0 means Mon, -1 Tue, -2 Wed, -3 Thu, 3 Fri, 2 Sat, 1 Sun */
	int res;

	assert(d.hang >= -3 && d.hang <= 3);
	if (UNLIKELY((res = 1 - d.hang) <= 0)) {
		res += GREG_DAYS_P_WEEK;
		assert(res > DT_MIRACLEDAY);
	}
	return (dt_dow_t)res;
}

static int
__ywd_get_jan01_hang(dt_dow_t j01)
{
/* Mon means hang of 0, Tue -1, Wed -2, Thu -3, Fri 3, Sat 2, Sun 1 */
	int res;

	if (UNLIKELY((res = 1 - (int)j01) < -3)) {
		assert(res >= -6);
		return (int)GREG_DAYS_P_WEEK + res;
	}
	return res;
}

static __attribute__((unused)) dt_dow_t
__ywd_get_dec31_wday(dt_ywd_t d)
{
/* a year starting on W ends on W if not a leap year */
	dt_dow_t res = __ywd_get_jan01_wday(d);

	if (UNLIKELY(__leapp(d.y))) {
		if (++res > GREG_DAYS_P_WEEK) {
			/* wrap around DT_SUNDAY -> DT_MONDAY */
			res = DT_MONDAY;
		}
	}
	return res;
}

#if defined GET_ISOWK_FULL_SWITCH
static __attribute__((const, pure)) unsigned int
__get_isowk(unsigned int y)
{
/* return the number of iso weeks in Y */
	switch (y % 400) {
	default:
		break;
	case 4:
	case 9:
	case 15:
	case 20:
	case 26:
	case 32:
	case 37:
	case 43:
	case 48:
	case 54:
	case 60:
	case 65:
	case 71:
	case 76:
	case 82:
	case 88:
	case 93:
	case 99:
	case 105:
	case 111:
	case 116:
	case 122:
	case 128:
	case 133:
	case 139:
	case 144:
	case 150:
	case 156:
	case 161:
	case 167:
	case 172:
	case 178:
	case 184:
	case 189:
	case 195:
	case 201:
	case 207:
	case 212:
	case 218:
	case 224:
	case 229:
	case 235:
	case 240:
	case 246:
	case 252:
	case 257:
	case 263:
	case 268:
	case 274:
	case 280:
	case 285:
	case 291:
	case 296:
	case 303:
	case 308:
	case 314:
	case 320:
	case 325:
	case 331:
	case 336:
	case 342:
	case 348:
	case 353:
	case 359:
	case 364:
	case 370:
	case 376:
	case 381:
	case 387:
	case 392:
	case 398:
		return 53;
	}
	return 52;
}

static unsigned int
__get_z31wk(unsigned int y)
{
/* return the week number of 31 dec in year Y, where weeks hanging over into
 * the new year are treated as 53
 * In the 400 year cycle, there's 243 years with 53 weeks and
 * 157 years with 52 weeks. */
	switch (y % 400U) {
	default:
		break;
	case 0:
	case 5:
	case 6:
	case 10:
	case 11:
	case 16:
	case 17:
	case 21:
	case 22:
	case 23:
	case 27:
	case 28:
	case 33:
	case 34:
	case 38:
	case 39:
	case 44:
	case 45:
	case 49:
	case 50:
	case 51:
	case 55:
	case 56:
	case 61:
	case 62:
	case 66:
	case 67:
	case 72:
	case 73:
	case 77:
	case 78:
	case 79:
	case 83:
	case 84:
	case 89:
	case 90:
	case 94:
	case 95:
	case 100:
	case 101:
	case 102:
	case 106:
	case 107:
	case 112:
	case 113:
	case 117:
	case 118:
	case 119:
	case 123:
	case 124:
	case 129:
	case 130:
	case 134:
	case 135:
	case 140:
	case 141:
	case 145:
	case 146:
	case 147:
	case 151:
	case 152:
	case 157:
	case 158:
	case 162:
	case 163:
	case 168:
	case 169:
	case 173:
	case 174:
	case 175:
	case 179:
	case 180:
	case 185:
	case 186:
	case 190:
	case 191:
	case 196:
	case 197:
	case 202:
	case 203:
	case 208:
	case 209:
	case 213:
	case 214:
	case 215:
	case 219:
	case 220:
	case 225:
	case 226:
	case 230:
	case 231:
	case 236:
	case 237:
	case 241:
	case 242:
	case 243:
	case 247:
	case 248:
	case 253:
	case 254:
	case 258:
	case 259:
	case 264:
	case 265:
	case 269:
	case 270:
	case 271:
	case 275:
	case 276:
	case 281:
	case 282:
	case 286:
	case 287:
	case 292:
	case 293:
	case 297:
	case 298:
	case 299:
	case 304:
	case 305:
	case 309:
	case 310:
	case 311:
	case 315:
	case 316:
	case 321:
	case 322:
	case 326:
	case 327:
	case 332:
	case 333:
	case 337:
	case 338:
	case 339:
	case 343:
	case 344:
	case 349:
	case 350:
	case 354:
	case 355:
	case 360:
	case 361:
	case 365:
	case 366:
	case 367:
	case 371:
	case 372:
	case 377:
	case 378:
	case 382:
	case 383:
	case 388:
	case 389:
	case 393:
	case 394:
	case 395:
	case 399:
		return 52;
	}
	/* more weeks with 53, so default to that */
	return 53;
}

#elif defined GET_ISOWK_28Y_SWITCH
static inline __attribute__((const, pure)) unsigned int
__get_isowk(unsigned int y)
{
	switch (y % 28U) {
	default:
		break;
	case 16:
		/* 1920, 1948, ... */
	case 21:
		/* 1925, 1953, ... */
	case 27:
		/* 1931, 1959, ... */
	case 4:
		/* 1936, 1964, ... */
	case 10:
		/* 1942, 1970, ... */
		return 53;
	}
	return 52;
}

static unsigned int
__get_z31wk(unsigned int y)
{
/* return the week number of 31 dec in year Y, where weeks hanging over into
 * the new year are treated as 53
 * In the 400 year cycle, there's 243 years with 53 weeks and
 * 157 years with 52 weeks. */
	switch (y % 28U) {
	default:
		break;
		/* pattern in the 28y cycle is: 5 1 4 1 5 1 4 1 1 4 1 */
	case 0:
	case 5:
	case 6:
	case 10:
	case 11:
	case 16:
	case 17:
	case 21:
	case 22:
	case 23:
	case 27:
		return 52;
	}
	/* more weeks with 53, so default to that */
	return 53;
}

#endif	/* GET_ISOWK_* */

static __attribute__((pure)) dt_ywd_t
__ywd_fixup(dt_ywd_t d)
{
/* given dates like 2012-W53-01 this returns 2013-W01-01 */
	int nw;

	if (LIKELY(d.c <= 52)) {
		/* brill all years have 52 weeks */
		;
	} else if (UNLIKELY(d.c > (nw = __get_isowk(d.y)))) {
		d.c = nw;
	}
	return d;
}

#define canon_yc(y, c, hang)				\
	if (LIKELY(c >= 1 && c <= 52)) {		\
		/* all years support this */		\
		;					\
	} else if (UNLIKELY(c < 1)) {			\
		if (UNLIKELY(__leapp(--y))) {		\
			hang++;				\
		}					\
		if (++hang > 3) {			\
			hang -= GREG_DAYS_P_WEEK;	\
		}					\
		c += __get_isowk(y);			\
	} else if (UNLIKELY(c > __get_isowk(y))) {	\
		c -= __get_isowk(y);			\
		if (UNLIKELY(__leapp(y++))) {		\
			hang--;				\
		}					\
		if (--hang < -3) {			\
			hang += GREG_DAYS_P_WEEK;	\
		}					\
	}


#endif	/* !YWD_ASPECT_HELPERS_ */


#if defined ASPECT_GETTERS && !defined YWD_ASPECT_GETTERS_
#define YWD_ASPECT_GETTERS_
static dt_ywd_t
__make_ywd_c(unsigned int y, unsigned int c, dt_dow_t w, unsigned int cc)
{
/* build a 8601 compliant ywd object from year Y, week C and weekday W
 * where C conforms to week-count convention cc */
	dt_ywd_t res = {0};
	dt_dow_t j01;
	int hang;

	/* this one's special as it needs the hang helper slot */
	j01 = __get_jan01_wday(y);
	hang = __ywd_get_jan01_hang(j01);

	assert(w != DT_MIRACLEDAY);

	switch (cc) {
	default:
	case YWD_ISOWK_CNT:
		break;
	case YWD_ABSWK_CNT:
		if (hang == 1 && w < DT_SUNDAY) {
			/* n-th W in the year is n-th week,
			 * year starts on sunday */
			;
		} else if (hang > 0 && w < DT_SUNDAY && w < j01) {
			/* n-th W in the year is n-th week,
			 * in this case the year doesnt start on sunday */
			;
		} else if (hang <= 0 && (w >= j01 || w == DT_SUNDAY)) {
			/* n-th W in the year is n-th week */
			;
		} else if (hang > 0) {
			/* those weekdays that hang over into the last year */
			c--;
		} else if (hang <= 0) {
			/* weekdays missing in the first week of Y */
			c++;
		}

		canon_yc(y, c, hang);
		break;
	case YWD_SUNWK_CNT:
		if (j01 == DT_SUNDAY) {
			;
		} else {
			c++;
		}
		break;
	case YWD_MONWK_CNT:
		if (j01 <= DT_MONDAY) {
			;
		} else {
			c++;
		}
		break;
	}

	/* assign and fuck off */
	res.y = y;
	res.c = c;
	res.w = w;
	res.hang = hang;
#if defined WITH_FAST_ARITH
	return res;
#else  /* !WITH_FAST_ARITH */
	return __ywd_fixup(res);
#endif	/* WITH_FAST_ARITH */
}

static dt_ywd_t
__make_ywd_yd_dow(unsigned int y, int yd, dt_dow_t dow)
{
/* build a 8601 compliant ywd object from year Y, day-of-year YD
 * and weekday DOW */
	dt_ywd_t res = {0};
	dt_dow_t j01;
	unsigned int c;
	int hang;

	/* deduce the weekday of the first, given the weekday
	 * of the yd-th is DOW */
	j01 = __get_jan01_yday_dow(yd, dow);
	hang = __ywd_get_jan01_hang(j01);

	/* compute weekday, decompose yd into 7p + q */
	c = (yd + GREG_DAYS_P_WEEK - 1 - hang) / (signed int)GREG_DAYS_P_WEEK;

	/* fixup c (and y) */
	canon_yc(y, c, hang);

	/* assign and fuck off */
	res.y = y;
	res.c = c;
	res.w = dow;
	res.hang = hang;
	return res;
}

static dt_ywd_t
__make_ywd_ybd(unsigned int y, int yd)
{
/* build a 8601 compliant ywd object from year Y and year-business-day YD */
	dt_ywd_t res = {0};
	dt_dow_t j01;
	unsigned int c;
	int w;
	int hang;

	/* this one's special as it needs the hang helper slot */
	j01 = __get_jan01_wday(y);
	hang = __ywd_get_jan01_hang(j01);

	/* compute weekday, decompose yd into 7p + q */
	c = (yd + DUWW_BDAYS_P_WEEK - 1) / (signed int)DUWW_BDAYS_P_WEEK;
	w = (yd + DUWW_BDAYS_P_WEEK - 1) % (signed int)DUWW_BDAYS_P_WEEK;
	if ((w += j01) > (signed int)DUWW_BDAYS_P_WEEK) {
		w -= DUWW_BDAYS_P_WEEK;
		c++;
	} else if (w < (signed int)DT_MONDAY) {
		w += DUWW_BDAYS_P_WEEK;
		c--;
	}

	/* fixup c (and y) */
	canon_yc(y, c, hang);

	/* assign and fuck off */
	res.y = y;
	res.c = c;
	res.w = w;
	res.hang = hang;
	return res;
}

static unsigned int
__ywd_get_yday(dt_ywd_t d)
{
/* since everything is in ISO 8601 format, getting the doy is a matter of
 * counting how many days there are in a week. */
	return GREG_DAYS_P_WEEK * (d.c - 1) + d.w + d.hang;
}

static dt_dow_t
__ywd_get_wday(dt_ywd_t that)
{
	return (dt_dow_t)that.w;
}

static unsigned int
__ywd_get_wcnt_mon(dt_ywd_t d)
{
/* given a YWD with week-count within the year (ISOWK_CNT convention)
 * return the week-count within the month (ABSWK_CNT convention) */
	unsigned int yd = __ywd_get_yday(d);
	struct __md_s x = __yday_get_md(d.y, yd);
	return (x.d - 1) / 7 + 1;
}

static int
__ywd_get_wcnt_year(dt_ywd_t d, unsigned int tgtcc)
{
	dt_dow_t j01;

	if (tgtcc == YWD_ISOWK_CNT) {
		return d.c;
	}
	/* otherwise we need to shift things */
	j01 = __ywd_get_jan01_wday(d);
	switch (tgtcc) {
	case YWD_ABSWK_CNT:
		if (d.w < j01) {
			return d.c - 1;
		} else if (d.hang < 0) {
			return d.c + 1;
		}
		break;
	case YWD_MONWK_CNT:
		if (j01 >= DT_TUESDAY && j01 < DT_SUNDAY) {
			return d.c - 1;
		}
		break;
	case YWD_SUNWK_CNT:
		if (j01 < DT_SUNDAY) {
			return d.c - 1;
		}
		break;
	default:
		break;
	}
	return d.c;
}

static struct __md_s
__ywd_get_md(dt_ywd_t d)
{
	unsigned int yday = __ywd_get_yday(d);
	struct __md_s res = __yday_get_md(d.y, yday);

	if (UNLIKELY(res.m == 0)) {
		res.m = 12;
		res.d--;
	} else if (UNLIKELY(res.m == 13)) {
		res.m = 1;
	}
	return res;
}

static unsigned int
__ywd_get_mon(dt_ywd_t d)
{
	unsigned int yd = __ywd_get_yday(d);
	return __yday_get_md(d.y, yd).m;
}

static unsigned int
__ywd_get_year(dt_ywd_t d)
{
/* return the true gregorian year */
	unsigned int y = d.y;

	if (d.c == 1) {
		dt_dow_t f01 = __ywd_get_jan01_wday(d);

		if (d.hang <= 0 && d.w < f01) {
			y--;
		}

	} else if (d.c >= __get_z31wk(y)) {
		dt_dow_t z31 = __ywd_get_dec31_wday(d);

		if (z31 < DT_SUNDAY && d.w > z31) {
			y++;
		}
	}
	return y;
}
#endif	/* ASPECT_GETTERS */


#if defined ASPECT_CONV && !defined YWD_ASPECT_CONV_
#define YWD_ASPECT_CONV_
/* we need some of the stuff above, so get it */
#define ASPECT_GETTERS
#include "ywd.c"
#undef ASPECT_GETTERS

static dt_ymd_t
__ywd_to_ymd(dt_ywd_t d)
{
	unsigned int y = __ywd_get_year(d);
	struct __md_s md = __ywd_get_md(d);

#if defined HAVE_ANON_STRUCTS_INIT
	return (dt_ymd_t){.y = y, .m = md.m, .d = md.d};
#else  /* !HAVE_ANON_STRUCTS_INIT */
	{
		dt_ymd_t res;

		res.y = y;
		res.m = md.m;
		res.d = md.d;
		return res;
	}
#endif	/* HAVE_ANON_STRUCTS_INIT */
}

static dt_ymcw_t
__ywd_to_ymcw(dt_ywd_t d)
{
	unsigned int y = __ywd_get_year(d);
	struct __md_s md = __ywd_get_md(d);
	unsigned int c;

	/* we obtain C from weekifying the month */
	c = (md.d - 1U) / GREG_DAYS_P_WEEK + 1U;

#if defined HAVE_ANON_STRUCTS_INIT
	return (dt_ymcw_t){.y = y, .m = md.m, .c = c, .w = d.w};
#else  /* !HAVE_ANON_STRUCTS_INIT */
	{
		dt_ymcw_t res;

		res.y = y;
		res.m = md.m;
		res.c = c;
		res.w = d.w;
		return res;
	}
#endif	/* HAVE_ANON_STRUCTS_INIT */
}

static dt_daisy_t
__ywd_to_daisy(dt_ywd_t d)
{
	dt_daisy_t res;

	res = __jan00_daisy(d.y);
	res += __ywd_get_yday(d);
	return res;
}

static dt_yd_t
__ywd_to_yd(dt_ywd_t d)
{
#if defined HAVE_ANON_STRUCTS_INIT
	return (dt_yd_t){.y = d.y, .d = __ywd_get_yday(d)};
#else
	dt_yd_t res;
	res.y = d.y;
	res.d = __ywd_get_yday(d);
	return res;
#endif
}
#endif	/* ASPECT_CONV */


#if defined ASPECT_ADD && !defined YWD_ASPECT_ADD_
#define YWD_ASPECT_ADD_

static dt_ywd_t
__ywd_fixup_w(unsigned int y, signed int w, dt_dow_t d, int hang)
{
	dt_ywd_t res = {0};

	/* fixup q */
	if (LIKELY(w >= 1 && w <= 52)) {
		/* all years support this */
		;
	} else if (w < 1) {
		do {
			if (UNLIKELY(__leapp(--y))) {
				hang++;
			}
			if (++hang > 3) {
				hang -= GREG_DAYS_P_WEEK;
			}
			w += __get_isowk(y);
		} while (w < 1);

	} else {
		int nw;

		while (w > (nw = __get_isowk(y))) {
			w -= nw;
			if (UNLIKELY(__leapp(y++))) {
				hang--;
			}
			if (--hang < -3) {
				hang += GREG_DAYS_P_WEEK;
			}
		}
	}

	/* final assignment */
	res.y = y;
	res.c = w;
	res.w = d;
	res.hang = hang;
	return res;
}

static dt_ywd_t
__ywd_add_w(dt_ywd_t d, int n)
{
/* add N weeks to D */
	signed int tgtc = d.c + n;

	return __ywd_fixup_w(d.y, tgtc, (dt_dow_t)d.w, d.hang);
}

static dt_ywd_t
__ywd_add_d(dt_ywd_t d, int n)
{
/* add N days to D
 * we reduce this to __ywd_add_w() */
	signed int aw = n / 7;
	signed int ad = n % 7;

	if ((ad += d.w) > (signed int)GREG_DAYS_P_WEEK) {
		ad -= GREG_DAYS_P_WEEK;
		aw++;
	} else if (ad <= 0) {
		ad += GREG_DAYS_P_WEEK;
		aw--;
	}

	d.w = (dt_dow_t)ad;
	return __ywd_add_w(d, aw);
}

static dt_ywd_t
__ywd_add_b(dt_ywd_t d, int UNUSED(n))
{
/* add N business days to D */
	return d;
}

static dt_ywd_t
__ywd_add_y(dt_ywd_t d, int n)
{
/* add N years to D */
	dt_dow_t j01;

	d.y = d.y + n;
	/* recompute hang */
	j01 = __get_jan01_wday(d.y);
	d.hang = __ywd_get_jan01_hang(j01);
	return __ywd_fixup(d);
}
#endif	/* ASPECT_ADD */


#if defined ASPECT_DIFF && !defined YWD_ASPECT_DIFF_
#define YWD_ASPECT_DIFF_

static struct dt_d_s
__ywd_diff(dt_ywd_t d1, dt_ywd_t d2)
{
/* compute d2 - d1 entirely in terms of ymd but express the result as yd */
	struct dt_d_s res = {.typ = DT_YWD, .dur = 1};
	signed int tgtd;
	signed int tgtw;
	signed int tgty;

	if (d1.u > d2.u) {
		/* swap d1 and d2 */
		dt_ywd_t tmp = d1;
		res.neg = 1;
		d1 = d2;
		d2 = tmp;
	}

	/* first compute the difference in years */
	tgty = (d2.y - d1.y);
	/* ... and weeks */
	tgtw = (d2.c - d1.c);
	/* ... oh, and days, too */
	tgtd = (d2.w ?: 7) - (d1.w ?: 7);

	/* add carry */
	if (tgtd < 0) {
		tgtw--;
		tgtd += GREG_DAYS_P_WEEK;
	}
	if (tgtw < 0) {
		tgty--;
		tgtw += __get_isowk(d1.y + tgty);
	}

	/* fill in the results */
	res.ywd.y = tgty;
	res.ywd.c = tgtw;
	res.ywd.w = tgtd;
	return res;
}
#endif	/* ASPECT_DIFF */


#if defined ASPECT_STRF && !defined YWD_ASPECT_STRF_
#define YWD_ASPECT_STRF_
DEFUN void
__prep_strfd_ywd(struct strpd_s *tgt, dt_ywd_t d)
{
/* place ywd data of THIS into D for printing with FMT. */
	if (d.c == 1 && d.w < __ywd_get_jan01_wday(d) && d.w) {
		/* put gregorian year into y and real year into q */
		tgt->y = d.y - 1;
		tgt->q = d.y;
	} else if (d.c >= 53) {
		/* bit of service for the %Y printer */
		tgt->y = d.y + 1;
		tgt->q = d.y;
	} else {
		tgt->y = d.y;
		tgt->q = d.y;
	}
	/* business as usual here */
	tgt->c = d.c;
	tgt->w = d.w;
	tgt->flags.real_y_in_q = 1;
	return;
}
#endif	/* ASPECT_STRF */

/* ywd.c ends here */
dateutils-0.3.1/m4/000077500000000000000000000000001241477753400140475ustar00rootroot00000000000000dateutils-0.3.1/m4/ax_zoneinfo.m4000066400000000000000000000165531241477753400166420ustar00rootroot00000000000000# ===========================================================================
#      http://www.gnu.org/software/autoconf-archive/ax_zoneinfo.html
# ===========================================================================
#
# SYNOPSIS
#
#   AX_ZONEINFO([options...])
#
# DESCRIPTION
#
#   This macro finds compiled zoneinfo files.  If successful it will define
#   HAVE_ZONEINFO per:
#
#     AC_DEFINE([HAVE_ZONEINFO], [1], [...])
#
#   and have the variable TZDIR point to the zoneinfo directory as per
#
#     AC_SUBST([TZDIR])
#     AC_DEFINE_UNQUOTED([TZDIR], [/path/to/zic/files], [...])
#
#   Optionally, OPTIONS can be `right' to trigger further tests that will
#   determine if leap second fix-ups are available.  If so the variables
#   HAVE_ZONEINFO_RIGHT, ZONEINFO_UTC_RIGHT and TZDIR_RIGHT will be populated:
#
#     AC_DEFINE([HAVE_ZONEINFO_RIGHT], [1], [...])
#     AC_SUBST([TZDIR_RIGHT])
#     AC_DEFINE_UNQUOTED([TZDIR_RIGHT], [/path/to/right/zic/files], [...])
#     AC_SUBST([ZONEINFO_UTC_RIGHT])
#     AC_DEFINE_UNQUOTED([ZONEINFO_UTC_RIGHT], [$ZONEINFO_UTC_RIGHT], [...])
#
#
# LICENSE
#
#   Copyright (c) 2012 Sebastian Freundt 
#
#   Copying and distribution of this file, with or without modification, are
#   permitted in any medium without royalty provided the copyright notice
#   and this notice are preserved. This file is offered as-is, without any
#   warranty.

#serial 1

AC_DEFUN([AX_ZONEINFO_TZFILE_H], [dnl
	dnl not totally necessary (yet), as we can simply inspect the tzfiles
	dnl ourselves, but it certainly helps
	AC_CHECK_HEADER([tzfile.h])
])dnl AX_ZONEINFO_TZFILE_H

AC_DEFUN([AX_ZONEINFO_CHECK_TZFILE], [dnl
	dnl AX_ZONEINFO_CHECK_TZFILE([FILE], [ACTION-IF-VALID], [ACTION-IF-NOT])
	dnl secret switch is the 4th argument, which determines the ret code
	dnl of the leapcnt check
	pushdef([probe], [$1])
	pushdef([if_found], [$2])
	pushdef([if_not_found], [$3])

	AC_REQUIRE([AX_ZONEINFO_TZFILE_H])

	if test -z "${ax_tmp_zoneinfo_nested}"; then
		AC_MSG_CHECKING([zoneinfo file ]probe[])
	fi

	AC_LANG_PUSH([C])
	AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include 
#include 
#include 
#include 

]]ifelse([$4], [], [], [[
#define CHECK_LEAPCNT	]]$4[[
]])[[

/* simplified struct */
struct tzhead {
	char	tzh_magic[4];		/* TZ_MAGIC */
	char	tzh_version[1];		/* '\0' or '2' as of 2005 */
	char	tzh_reserved[15];	/* reserved--must be zero */
	char	tzh_ttisgmtcnt[4];	/* coded number of trans. time flags */
	char	tzh_ttisstdcnt[4];	/* coded number of trans. time flags */
	char	tzh_leapcnt[4];		/* coded number of leap seconds */
	char	tzh_timecnt[4];		/* coded number of transition times */
	char	tzh_typecnt[4];		/* coded number of local time types */
	char	tzh_charcnt[4];		/* coded number of abbr. chars */
};

int
main(int argc, char *argv[])
{
	struct tzhead foo;
	int f;

	if (argc <= 1) {
		return 0;
	} else if ((f = open(argv[1], O_RDONLY, 0644)) < 0) {
		return 1;
	} else if (read(f, &foo, sizeof(foo)) != sizeof(foo)) {
		return 1;
	} else if (close(f) < 0) {
		return 1;
	}

	/* inspect the header */
	if (memcmp(foo.tzh_magic, "TZif", sizeof(foo.tzh_magic))) {
		return 1;
	} else if (*foo.tzh_version && *foo.tzh_version != '2') {
		return 1;
#if defined CHECK_LEAPCNT
	} else if (!foo.tzh_leapcnt[0] && !foo.tzh_leapcnt[1] &&
		   !foo.tzh_leapcnt[2] && !foo.tzh_leapcnt[3]) {
		return CHECK_LEAPCNT;
#endif  /* CHECK_LEAPCNT */
	}

	/* otherwise everything's in order */
	return 0;
}
]])], [## call the whole shebang again with the tzfile
		if ./conftest$EXEEXT probe; then
			if test -z "${ax_tmp_zoneinfo_nested}"; then
				AC_MSG_RESULT([looking good])
			fi
			[]if_found[]
		else
			if test -z "${ax_tmp_zoneinfo_nested}"; then
				AC_MSG_RESULT([looking bad ${ax_tmp_rc}])
			fi
			[]if_not_found[]
		fi
], [
		if test -z "${ax_tmp_zoneinfo_nested}"; then
			AC_MSG_RESULT([impossible])
		fi
		[]if_not_found[]])
	AC_LANG_POP([C])

	popdef([probe])
	popdef([if_found])
	popdef([if_not_found])
])dnl AX_ZONEINFO_CHECK_TZFILE

AC_DEFUN([AX_ZONEINFO_TZDIR], [dnl
	dnl we consider a zoneinfo directory properly populated when it
	dnl provides UTC or UCT or Universal or Zulu

	pushdef([check_tzdir], [dnl
		pushdef([dir], $]1[)dnl
		test -n []dir[] && test -d []dir[] dnl
		popdef([dir])dnl
	])dnl check_tzdir

	dnl try /etc/localtime first, sometimes it's a link into TZDIR
	if test -L "/etc/localtime"; then
		TZDIR_cand="`readlink /etc/localtime` ${TZDIR_cand}"
	fi

	dnl oh, how about we try and check if there is a TZDIR already
	if check_tzdir(["${TZDIR}"]); then
		## bingo
		TZDIR_cand="${TZDIR} ${TZDIR_cand}"
	fi

	dnl often there's a tzselect util which contains the TZDIR path
	AC_PATH_PROG([TZSELECT], [tzselect])
	if test -n "${ac_cv_path_TZSELECT}"; then
		dnl snarf the value
		valtmp="`mktemp`"
		strings "${ac_cv_path_TZSELECT}" | \
			grep -F 'TZDIR=' > "${valtmp}"
		. "${valtmp}"
		TZDIR_cand="${TZDIR} ${TZDIR_cand}"
		rm -f -- "${valtmp}"
	fi

	dnl lastly, append the usual suspects
	TZDIR_cand="${TZDIR_cand} \
/usr/share/zoneinfo \
/usr/lib/zoneinfo \
/usr/local/etc/zoneinfo \
/usr/share/lib/zoneinfo \
"

	dnl go through our candidates
	AC_CACHE_CHECK([for TZDIR], [ax_cv_zoneinfo_tzdir], [dnl
		ax_tmp_zoneinfo_nested="yes"
		for c in ${TZDIR_cand}; do
			ax_cv_zoneinfo_utc=""
			for f in "UTC" "UCT" "Universal" "Zulu"; do
				AX_ZONEINFO_CHECK_TZFILE(["${c}/${f}"], [
					dnl ACTION-IF-FOUND
					ax_cv_zoneinfo_utc="${c}/${f}"
					break
				])
			done
			if test -n "${ax_cv_zoneinfo_utc}"; then
				ax_cv_zoneinfo_tzdir="${c}"
				break
			fi
		done
		ax_tmp_zoneinfo_nested=""
	])dnl ax_cv_tzdir

	TZDIR="${ax_cv_zoneinfo_tzdir}"
	AC_SUBST([TZDIR])

	if check_tzdir(["${ax_cv_zoneinfo_tzdir}"]); then
		AC_DEFINE([HAVE_ZONEINFO], [1], [dnl
Define when zoneinfo directory has been present during configuration.])
		AC_DEFINE_UNQUOTED([TZDIR], ["${ax_cv_zoneinfo_tzdir}"], [
Configuration time zoneinfo directory.])
	fi

	popdef([check_tzdir])
])dnl AX_ZONEINFO_TZDIR

AC_DEFUN([AX_ZONEINFO_RIGHT], [dnl
	AC_REQUIRE([AX_ZONEINFO_TZDIR])

	TZDIR_cand="${TZDIR} \
${TZDIR}/leapseconds \
${TZDIR}-leaps \
${TZDIR}/right \
${TZDIR}-posix \
${TZDIR}/posix \
"

	dnl go through our candidates
	AC_CACHE_CHECK([for leap second file], [ax_cv_zoneinfo_utc_right], [dnl
		ax_tmp_zoneinfo_nested="yes"
		if test -n "${ax_cv_zoneinfo_utc}"; then
			__utc_file="`basename "${ax_cv_zoneinfo_utc}"`"
			for c in ${TZDIR_cand}; do
				if test -d "${c}"; then
					c="${c}/${__utc_file}"
				fi
				AX_ZONEINFO_CHECK_TZFILE(["${c}"], [
					dnl ACTION-IF-FOUND
					ax_cv_zoneinfo_utc_right="${c}"
					break
				], [:], [2])
			done
		fi
		ax_tmp_zoneinfo_nested=""
	])dnl ax_cv_tzdir

	ZONEINFO_UTC_RIGHT="${ax_cv_zoneinfo_utc_right}"
	AC_SUBST([ZONEINFO_UTC_RIGHT])
	AC_SUBST([TZDIR_RIGHT])

	if test -n "${ax_cv_zoneinfo_utc_right}"; then
		TZDIR_RIGHT="`dirname ${ax_cv_zoneinfo_utc_right}`"

		AC_DEFINE([HAVE_ZONEINFO_RIGHT], [1], [dnl
Define when zoneinfo directory has been present during configuration.])
		AC_DEFINE_UNQUOTED([TZDIR_RIGHT],
			["${TZDIR_RIGHT}"], [
Configuration time zoneinfo directory.])
		AC_DEFINE_UNQUOTED([ZONEINFO_UTC_RIGHT],
			["${ax_cv_zoneinfo_utc_right}"], [
Leap-second aware UTC zoneinfo file.])
	fi
])dnl AX_ZONEINFO_RIGHT

AC_DEFUN([AX_ZONEINFO], [
	AC_REQUIRE([AX_ZONEINFO_TZDIR])

	ifelse([$1], [right], [
		AC_REQUIRE([AX_ZONEINFO_RIGHT])
	])

	AC_ARG_VAR([TZDIR], [Directory with compiled zoneinfo files.])
])dnl AX_ZONEINFO

dnl ax_zoneinfo.m4 ends here
dateutils-0.3.1/m4/sxe-aux.m4000066400000000000000000000461241241477753400157120ustar00rootroot00000000000000dnl sxe-aux.m4 -- just some auxiliary macros

dnl -------------------------------------------------------------------------
dnl Local macros
dnl -------------------------------------------------------------------------

AC_DEFUN([SXE_USAGE_ERROR], [dnl
(echo "$progbasename: Usage error:"
echo " " $1
echo "  Use \`$progname --help' to show usage.") >&2 && exit 1])

dnl SXE_PRINT_VAR(var var ...)  prints values of shell variables
AC_DEFUN([SXE_PRINT_VAR],[for var in patsubst([$1],[[
]+],[ ]); do eval "echo \"$var = '\$$var'\""; done])

dnl SXE_ADD_RUNPATH_DIR(directory)
AC_DEFUN([SXE_ADD_RUNPATH_DIR], [dnl
{
	xe_runpath_dir=$1
	if test "$xe_runpath_dir" != "/lib" -a \
		"$xe_runpath_dir" != "/usr/lib" -a \
		-n "`ls ${xe_runpath_dir}/*.s[[ol]] 2>/dev/null`"; then
		eval "$xe_add_unique_runpath_dir"
	fi
}
])dnl SXE_ADD_RUNPATH_DIR


AC_DEFUN([SXE_CHECK_USER_SPECIFIED_P], [dnl
	## arg1 var-name to check for
	## generates a variable `arg1'_uspecified_p
	pushdef([VARNAME], [$1])
	pushdef([VARNAME_USPECIFIED_P], [$1_uspecified_p])
	pushdef([USER_VARNAME], [USER_$1])

	AC_MSG_CHECKING([for user specified ]VARNAME)
	if test "${[]VARNAME[]-unset}" != "unset"; then
		VARNAME_USPECIFIED_P[]=yes;
		USER_VARNAME=${[]VARNAME[]}
	else
		VARNAME_USPECIFIED_P[]=no;
		USER_VARNAME=
	fi
	AC_MSG_RESULT([$]VARNAME_USPECIFIED_P)
	popdef([VARNAME])
	popdef([VARNAME_USPECIFIED_P])
	popdef([USER_VARNAME])
])dnl SXE_CHECK_USER_SPECIFIED_P

AC_DEFUN([SXE_CHECK_USER_VARS], [dnl
	## If we don't set CFLAGS here, AC_PROG_CC will set it.
	## But we know better what's good for us, so we do our own
	## computation of real CFLAGS later.
	SXE_CHECK_USER_SPECIFIED_P([CFLAGS])
	SXE_CHECK_USER_SPECIFIED_P([CPPFLAGS])
	SXE_CHECK_USER_SPECIFIED_P([LDFLAGS])
	SXE_CHECK_USER_SPECIFIED_P([XFLAGS])
	SXE_CHECK_USER_SPECIFIED_P([LIBS])
	SXE_CHECK_USER_SPECIFIED_P([CC])
	SXE_CHECK_USER_SPECIFIED_P([CPP])
	SXE_CHECK_USER_SPECIFIED_P([AR])
	SXE_CHECK_USER_SPECIFIED_P([YACC])
	SXE_CHECK_USER_SPECIFIED_P([YFLAGS])
	SXE_CHECK_USER_SPECIFIED_P([XMKMF])
])dnl SXE_CHECK_USER_VARS


dnl A meta defun that can create those nifty SXE_ADD_*_OBJ macros
m4_define([__SXE_MAKE_ADDER], [
	## arg1 is the name to be used throughout m4
	## arg2 is the library sans _la or _a to be used in the Makefiles
	## arg3 are comma-separated additional vars to substitute
	## defines SXE_ADD__OBJ
	## defines SXE_ADD__OBJS
	## defines SXE_SUBST__OBJS

	m4_define([SXE_ADD_]$1[_OBJ], [
		$2_objs="$$2_objs $2_a-]$[1]["
		if test "$extra_verbose" = "yes"; then
			echo "    sxemacs (cat. $1) will be linked with \"]$[1][\""
		fi
	])dnl

	m4_define([SXE_ADD_]$1[_OBJS], [
		for i in ]$[1][; do
			]SXE_ADD_[]$1[]_OBJ([$i])[
		done
	])dnl
	
	m4_define([SXE_SUBST_]$1[_OBJS], [
		AC_SUBST($2_objs)
		## subst additional vars
		m4_foreach_w([var], $3, [AC_SUBST(var)])
		## also define a conditional
		AM_CONDITIONAL([NEED_]translit([$2], [-.a-z], [__A-Z]),
			[test -n "$$2_objs"])
	])dnl

])dnl __SXE_MAKE_ADDER


dnl creates SXE_ADD_CORE_{OBJ,OBJS}
__SXE_MAKE_ADDER([CORE], [libsxecore])

dnl creates SXE_ADD_CRUFT_{OBJ,OBJS}
__SXE_MAKE_ADDER([CRUFT], [libcruft])

dnl creates SXE_ADD_DB_{OBJ,OBJS}
__SXE_MAKE_ADDER([DB], [libsxedb], [DB_CPPFLAGS DB_LDFLAGS DB_LIBS])

dnl creates SXE_ADD_ENT_{OBJ,OBJS}
__SXE_MAKE_ADDER([ENT], [libent])

dnl creates SXE_ADD_EVENTS_{OBJ,OBJS}
__SXE_MAKE_ADDER([EVENTS], [libsxeevents])

dnl creates SXE_ADD_MEMALLOC_{OBJ,OBJS}
__SXE_MAKE_ADDER([MEMALLOC], [libmemalloc])

dnl creates SXE_ADD_MM_{OBJ,OBJS}
__SXE_MAKE_ADDER([MM], [libmm])

dnl creates SXE_ADD_MULE_{OBJ,OBJS}
__SXE_MAKE_ADDER([MULE], [libmule])

dnl creates SXE_ADD_SXEUI_{OBJ,OBJS}
__SXE_MAKE_ADDER([SXEUI], [libsxeui])


dnl SXE_ADD_STATMOD_A(foo.o ...)
AC_DEFUN([SXE_ADD_STATMOD_A], [
	statmod_archives="$statmod_archives [$1]" && \
	if test "$extra_verbose" = "yes"; then
		echo "    sxemacs (cat. static module) will be linked with \"[$1]\""
	fi
])dnl SXE_ADD_STATMOD_A
AC_DEFUN([SXE_SUBST_STATMOD_A], [AC_SUBST(statmod_archives)])

dnl SXE_APPEND(value, varname)
AC_DEFUN([SXE_APPEND],
[[$2]="$[$2] [$1]" && dnl
 if test "$extra_verbose" = "yes"; then echo "    Appending \"[$1]\" to \$[$2]"; fi])

dnl SXE_PREPEND(value, varname)
AC_DEFUN([SXE_PREPEND],
[[$2]="[$1] $[$2]" && dnl
 if test "$extra_verbose" = "yes"; then echo "    Prepending \"[$1]\" to \$[$2]"; fi])

dnl SXE_DIE(message)
AC_DEFUN([SXE_DIE], [{ echo "Error:" $1 >&2; exit 1; }])


dnl some helpers
AC_DEFUN([SXE_INIT_MSG_LEVEL], [
	sxe_msg_level=0
])dnl SXE_INIT_MSG_LEVEL

AC_DEFUN([SXE_MSG_CHECKING], [
	## like AC_MSG_CHECKING but nestable
	if test "$sxe_msg_level" -le 0; then
		AC_MSG_CHECKING([$1])
	fi
	sxe_msg_level=$(($sxe_msg_level + 1))
])dnl SXE_MSG_CHECKING

AC_DEFUN([SXE_MSG_RESULT], [
	## like AC_MSG_RESULT but nestable
	sxe_msg_level=$(($sxe_msg_level - 1))
	if test "$sxe_msg_level" -le 0; then
		AC_MSG_RESULT([$1])
	fi
])dnl SXE_MSG_RESULT

dnl SXE_CHECK_FEATURE_DEPENDENCY(feature1, feature2)
AC_DEFUN([SXE_CHECK_FEATURE_DEPENDENCY],
[if test "$with_$1 $with_$2" = "yes no"; then
	SXE_USAGE_ERROR("--with-$1 requires --with-$2")
elif test "$with_$2" = "no" ; then with_$1=no
elif test "$with_$1" = "yes"; then with_$2=yes
fi
])

dnl SXE_STRIP_4TH_COMPONENT(var)
dnl Changes i986-pc-linux-gnu to i986-pc-linux, as God (not RMS) intended.
AC_DEFUN([SXE_STRIP_4TH_COMPONENT],
[$1=`echo "$$1" | sed '[s/^\([^-][^-]*-[^-][^-]*-[^-][^-]*\)-.*$/\1/]'`])

dnl AC_DEFUN([SXE_DEBUG_AC], [AS_MESSAGE($@)])
AC_DEFUN([SXE_DEBUG_AC], [])

dnl Do our best to deal with automounter brokenness
dnl SXE_CANONICALISE_PATH(varname)
AC_DEFUN([SXE_CANONICALISE_PATH], [dnl
	## arg #1 is the file/path to canonicalise
	pushdef([tmpp], [$1])

	SXE_DEBUG_AC([canonicalising \$]tmpp[: "]$[]tmpp["])

	if test -d "/net"; then
		if test -d "/tmp_mnt/net"; then
			tdir="tmp_mnt/net";
		else
			tdir="tmp_mnt";
		fi
		tmpp[]=$(echo "[$]tmpp[]" | \
			sed -e "s|^${tdir}/|/net/|" \
			    -e "s|^/a/|/net/|" \
			    -e "s|^/amd/|/net/|")
	fi

dnl 	if test -d "[$]tmpp"; then
dnl 		## the easy way ...
dnl 		## just let the filesystem implementation do the hard work
dnl 		tmpp[]=$(cd [$]tmpp[] && echo $(pwd))
dnl 	elif test -f "[$]tmpp"; then
dnl 		## the easy way ...
dnl 		## just let the filesystem implementation do the hard work
dnl 		tmpp[]=$(cd $(dirname [$]tmpp[]) && \
dnl 			echo $(pwd)/$(basename [$]tmpp[]))
dnl 	else
		## simple magic
		canonicalised="no"
		while test "$canonicalised" = "no"; do
			_SXE_CANONICALISE_STEP(tmpp,
				[canonicalised="yes"], [canonicalised="no"])
		done
dnl	fi

	SXE_DEBUG_AC([canonicalised \$]tmpp[: "]$[]tmpp["])
	popdef([tmpp])
])dnl SXE_CANONICALISE_PATH

AC_DEFUN([_SXE_CANONICALISE_STEP], [
	## _SXE_CANONICALISE_STEP( VAR, DO-ON-SUCCESS, DO-ON-FAILURE)
	## arg #1 is the varname to canonicalise
	## arg #2 is the code to execute on success
	## arg #3 is the code to execute on failure
	pushdef([tmpvar], [$1])
	pushdef([dosucc], [$2])
	pushdef([dofail], [$3])

	tmp2=[$]tmpvar
	tmp3=
	tmp4=$(basename "$tmp2")
	## assume we had success
	dosucc
	while test "$tmp4" != "/" -a "$tmp4" != "."; do
		if test "$tmp4" = ".." -a \
			$(basename $(dirname "$tmp2")) = "."; then
			## we prepend and we know the path
			## is still dirty but wont do anything
			## alternative would be to prepend $(pwd) now
			dosucc
			tmp3="$(basename $tmp2)/$tmp3"
		elif test "$tmp4" = ".." -a \
			$(basename $(dirname "$tmp2")) != ".."; then
			tmp2=$(dirname "$tmp2")
		elif test "$tmp4" = ".."; then
			## we prepend, but now we know the path
			## is still dirty
			dofail
			tmp3="$(basename $tmp2)/$tmp3"
		elif test -n "$tmp3"; then
			## ordinary component, just prepend
			tmp3="$(basename $tmp2)/$tmp3"
		else
			## just set
			tmp3="$(basename $tmp2)"
		fi
		tmp2=$(dirname "$tmp2")
		tmp4=$(basename "$tmp2")
	done

	tmp3="$tmp4/$tmp3"
	tmpvar[]=$(echo "$tmp3" | sed -e "s@//@/@g")

	popdef([tmpvar])
	popdef([dosucc])
	popdef([dofail])
])dnl _SXE_CANONICALISE_STEP


dnl SXE_PROTECT_LINKER_FLAGS(shell_var)
AC_DEFUN([SXE_PROTECT_LINKER_FLAGS], [
if test "$GCC" = "yes"; then
  set x $[$1]; shift; [$1]=""
  while test -n "[$]1"; do
    case [$]1 in
      -L  | -l  | -u               ) [$1]="$[$1] [$]1 [$]2"; shift ;;
      -L* | -l* | -u* | -Wl* | -pg ) [$1]="$[$1] [$]1" ;;
      -Xlinker* ) ;;
      * ) [$1]="$[$1] -Xlinker [$]1" ;;
    esac
    shift
  done
fi])dnl


dnl Allow use of either ":" or spaces for lists of directories
AC_DEFUN([SXE_COLON_TO_SPACE],
  [case "$[$1]" in *:* [)] [$1]="`echo '' $[$1] | sed -e 's/^ //' -e 's/:/ /g'`";; esac])dnl


dnl The construct foo=`echo $w1 $w2 $w3` fails on some systems if $w1 = -e or -n
dnl So we use the following instead.
dnl SXE_SPACE(var, words)
AC_DEFUN([SXE_SPACE],[
T=""
for W in $2; do if test -z "$T"; then T="$W"; else T="$T $W"; fi; done
$1="$T"
])dnl SXE_SPACE



AC_DEFUN([SXE_LANG_WERROR], [dnl
	dnl like AC_LANG_WERROR but working
	dnl call goes: SXE_LANG_WERROR([on|off|push|pop|push+off|push+on])

	pushdef([tmppush], [
		if test -n "$ac_c_werror_flag"; then
			sxe_cv_aux_werror_stack="on $sxe_cv_aux_werror_stack"
		else
			sxe_cv_aux_werror_stack="off $sxe_cv_aux_werror_stack"
		fi
		])
	pushdef([tmpon], [ac_c_werror_flag="-Werror"])
	pushdef([tmpoff], [ac_c_werror_flag=""])

	m4_if([$1], [on], [tmpon])

	m4_if([$1], [off], [tmpoff])

	m4_if([$1], [push], [tmppush])
	m4_if([$1], [push+off], [
		tmppush
		tmpoff
		])
	m4_if([$1], [push+on], [
		tmppush
		tmpon
		])

	m4_if([$1], [pop], [
		## thanks for the tip, Aidan
		$(echo $sxe_cv_aux_werror_stack | \
			read sxe_cv_tmp_stackcar sxe_cv_aux_werror_stack)
		if test "$sxe_cv_tmp_stackcar" = "on"; then
			tmpon
		elif test "$sxe_cv_tmp_stackcar" = "off"; then
			tmpoff
		else
			## rather turn it off than on, dont ya think?
			tmpoff
		fi
		])

])dnl SXE_LANG_WERROR


AC_DEFUN([SXE_DUMP_LIBS], [
	save_c_switch_site="$c_switch_site"
	save_LIBS="$LIBS"
	save_ld_switch_site="$ld_switch_site"
	save_ld_switch_machine="$ld_switch_machine"
	save_CC="$CC"
	save_CFLAGS="$CFLAGS"
	save_CPPFLAGS="$CPPFLAGS"
	save_LDFLAGS="$LDFLAGS"

	SXE_LANG_WERROR([push])
])dnl SXE_DUMP_LIBS

AC_DEFUN([SXE_RESTORE_LIBS], [
	LIBS="$save_LIBS"
	c_switch_site="$save_c_switch_site"
	ld_switch_site="$save_ld_switch_site"
	ld_switch_machine="$save_ld_switch_machine"
	CC="$save_CC"
	CFLAGS="$save_CFLAGS"
	CPPFLAGS="$save_CPPFLAGS"
	LDFLAGS="$save_LDFLAGS"

	SXE_LANG_WERROR([pop])
])dnl SXE_RESTORE_LIBS

AC_DEFUN([SXE_SEARCH_CONFIG_PROG], [
	## arg #1 program to search
	pushdef([config_prog], [$1])
	pushdef([have_config_prog], [have_]translit([$1], [-.], [__]))
	pushdef([CONFIG_PROG], translit([$1], [-.a-z], [__A-Z]))
	AC_CHECK_PROG(have_config_prog, config_prog, [yes], [no])
	AC_PATH_PROG(CONFIG_PROG, config_prog, [echo])
	popdef([config_prog])
	popdef([have_config_prog])
	popdef([CONFIG_PROG])
])dnl SXE_SEARCH_CONFIG_PROG


AC_DEFUN([_SXE_CHECK_pkgconfig_based], [
	## assumes $PKG_CONFIG is defined
	## arg #1: MM param name
	## arg #2: lib to check
	## arg #3: version of that lib

	pushdef([IO_LIB], [$1])

	AC_REQUIRE([SXE_CHECK_PKGCONFIG])

	AC_MSG_CHECKING([for ]IO_LIB[ support])
	AC_MSG_RESULT([])

	if test "$have_pkg_config" = "no" -o -z "$PKG_CONFIG"; then
		AS_MESSAGE([*** pkg-config not found. See http://pkgconfig.sourceforge.net])
		AS_MESSAGE([*** Cannot check for ]IO_LIB[.])
		have_pkg_config=no
		PKG_CONFIG=
	fi

	pushdef([IO_MOD], [$2])
	pushdef([IO_MOD_REQUIRED_VERSION], [$3])
	AC_MSG_CHECKING([whether ]IO_MOD[ is at least ]IO_MOD_REQUIRED_VERSION)
	if test -n "$PKG_CONFIG" && \
	     $PKG_CONFIG --atleast-version IO_MOD_REQUIRED_VERSION IO_MOD; then
		IO_LIB[]_version=`$PKG_CONFIG --modversion []IO_MOD[]`
		AC_MSG_RESULT([yes ($]IO_LIB[_version)])
		have_[]IO_LIB[]_pkg="yes"
		## define some useful variables
		IO_LIB[]_libs=`$PKG_CONFIG --libs []IO_MOD[]`
		IO_LIB[]_libs_L=`$PKG_CONFIG --libs-only-L []IO_MOD[]`
		IO_LIB[]_libs_l=`$PKG_CONFIG --libs-only-l []IO_MOD[]`
		IO_LIB[]_libs_other=`$PKG_CONFIG --libs-only-other []IO_MOD[]`
		IO_LIB[]_cflags=`$PKG_CONFIG --cflags []IO_MOD[]`
		IO_LIB[]_cflags_I=`$PKG_CONFIG --cflags-only-I []IO_MOD[]`
		IO_LIB[]_cflags_other=`$PKG_CONFIG --cflags-only-other []IO_MOD[]`
	elif test -n "$PKG_CONFIG"; then
		IO_LIB[]_version=`$PKG_CONFIG --modversion []IO_MOD[]`
		AC_MSG_RESULT([no ($]IO_LIB[_version)])
		have_[]IO_LIB[]_pkg="no"
	else
		have_[]IO_LIB[]_pkg="uncertain"
		AC_MSG_RESULT([$have_]IO_LIB[])
	fi
	popdef([IO_LIB])
	popdef([IO_MOD_REQUIRED_VERSION])
	popdef([IO_MOD])
])dnl _SXE_CHECK_pkgconfig_based

AC_DEFUN([_SXE_MM_CHECK_pkgconfig_based], [
	## assumes $PKG_CONFIG is defined
	## arg #1: MM param name
	## arg #2: lib to check
	## arg #3: version of that lib
	## arg #4: funs to check
	## arg #5: headers to check
	## arg #6: success action
	## arg #7: failure action

	pushdef([MM_LIB], [$1])
	pushdef([MM_SUCC], [$6])
	pushdef([MM_FAIL], [$7])

	AC_REQUIRE([SXE_CHECK_PKGCONFIG])

	AC_MSG_CHECKING([for ]MM_LIB[ support])
	AC_MSG_RESULT([])

	if test "$have_pkg_config" = "no" -o -z "$PKG_CONFIG"; then
		AS_MESSAGE([*** pkg-config not found. See http://pkgconfig.sourceforge.net])
		AS_MESSAGE([*** Cannot check for ]MM_LIB[.])
		have_pkg_config=no
		PKG_CONFIG=
		MM_FAIL
	fi

	pushdef([MM_MOD], [$2])
	pushdef([MM_MOD_REQUIRED_VERSION], [$3])
	pushdef([MM_MOD_FUNS], [$4])
	pushdef([MM_MOD_HDRS], [$5])
	AC_MSG_CHECKING([whether ]MM_MOD[ is at least ]MM_MOD_REQUIRED_VERSION)
	if test -n "$PKG_CONFIG" && \
	     $PKG_CONFIG --atleast-version MM_MOD_REQUIRED_VERSION MM_MOD; then
		actual_version=`$PKG_CONFIG --modversion []MM_MOD[]`
		AC_MSG_RESULT([yes ($actual_version)])
		AC_MSG_CHECKING([for ]mm_lib[ libraries])
		MM_MOD_LIBS_L=`$PKG_CONFIG --libs-only-l []MM_MOD[]`
		MM_MOD_LIBS=`echo $MM_MOD_LIBS_L | sed -e "s/-l//g"`
		MM_MOD_LIB=`echo $MM_MOD_LIBS | sed -e "s/ .*$//"`
		MM_MOD_OTHER_LIBS=`echo $MM_MOD_LIBS_L | sed -e "s/^[^ ]*//"`
		AC_MSG_RESULT([$MM_MOD_LIBS])

		## backup our site flags
		SXE_DUMP_LIBS
		MM_MOD_LIBS_SITE=`$PKG_CONFIG --libs-only-L []MM_MOD[]`
		MM_MOD_HDRS_SITE=`$PKG_CONFIG --cflags-only-I []MM_MOD[]`
		SXE_PREPEND([$MM_MOD_HDRS_SITE], [CPPFLAGS])
		SXE_PREPEND([$MM_MOD_LIBS_SITE], [LDFLAGS])

		MM_SUCC
		SXE_CHECK_HEADERS([]MM_MOD_HDRS[], [:], [MM_FAIL])
		for i in MM_MOD_FUNS; do
			AC_CHECK_LIB([$MM_MOD_LIB], [$i], [:], [MM_FAIL],
				[$MM_MOD_LIBS_L])
		done

		## restore old values
		SXE_RESTORE_LIBS
	elif test -n "$PKG_CONFIG"; then
		actual_version=`$PKG_CONFIG --modversion []MM_MOD[]`
		AC_MSG_RESULT([no ($actual_version)])
	else
		AC_MSG_RESULT([uncertain])
	fi
	popdef([MM_LIB])
	popdef([MM_MOD_FUNS])
	popdef([MM_MOD_HDRS])
	popdef([MM_MOD_REQUIRED_VERSION])
	popdef([MM_MOD])
	popdef([MM_SUCC])
	popdef([MM_FAIL])
])dnl _SXE_MM_CHECK_pkgconfig_based


AC_DEFUN([SXE_CHECK_SUFFICIENCY], [dnl
	## arg #1 is the option to check sufficiency on
	## arg #2 is a description
	## arg #3 are additional actions to perform when support is sufficient
	## arg #4 are additional actions to perform when support is insufficient
	pushdef([og_group], translit([$1], [-], [_]))
	pushdef([og_descr], [$2])
	pushdef([OG_GROUP], translit([$1], [-a-z], [_A-Z]))
	pushdef([IF_YES_DO], [$3])
	pushdef([IF_NO_DO], [$4])

	tmp=${[have_]og_group[]-uncertain}
	if test "$with_[]og_group" != "no"; then
		AC_MSG_CHECKING([for sufficient ]og_descr[ support])
		AC_MSG_RESULT([$tmp])
		if test "$tmp" = "yes"; then
			AC_DEFINE([HAVE_]OG_GROUP, [1],
				[Whether ]og_descr[ is doable])
			:
			IF_YES_DO
		else
			:
			IF_NO_DO
		fi
	else
		:
		IF_NO_DO
	fi
	AM_CONDITIONAL([HAVE_]OG_GROUP,
		[test "$have_[]og_group" = "yes" -a "$with_[]og_group" != "no"])
	popdef([og_group])
	popdef([og_descr])
	popdef([OG_GROUP])
	popdef([IF_YES_DO])
	popdef([IF_NO_DO])
])dnl SXE_CHECK_SUFFICIENCY


AC_DEFUN([SXE_CHECK_HEADERS], [dnl
	dnl One day, this macro will only check for headers if
	dnl their presence is yet unknown
	AC_CHECK_HEADERS($1,$2,$3,$4)
])dnl SXE_CHECK_HEADERS

AC_DEFUN([SXE_CHECK_LIB_FUNCS], [dnl
	pushdef([SXE_LIB], [$1])
	pushdef([SXE_FUNCS], [$2])

	for i in SXE_LIB; do
		for j in SXE_FUNCS; do
			AC_CHECK_LIB([$i], [$j], [:], [:])
		done
	done

	popdef([SXE_LIB])
	popdef([SXE_FUNCS])
])dnl SXE_CHECK_LIB_FUNCS


AC_DEFUN([_SXE_CHECK_PURE_OPT], [dnl
	unq_opt=$(echo $1 | tr -d "'\"")

	case "$unq_opt" in
	## first autoconf's options
	--enable-largefile | --disable-largefile | \
	--enable-dependency-tracking | --disable-dependency-tracking | \
	--enable-option-checking | --disable-option-checking | \
	--with-x | --x-includes | --x-libraries | \
	--build | --host | \
	--program-prefix | --program-suffix | --program-transform-name | \
	--prefix | --exec-prefix | --bindir | --sbindir | \
	--libexecdir | --sysconfdir | \
	--sharedstatedir | --localstatedir | \
	--libdir | --includedir | --oldincludedir | \
	--datarootdir | --datadir | --infodir | --localedir | \
	--mandir | --docdir | --htmldir | --dvidir | --pdfdir | --psdir | \
	-n | --no-create | -C | --config-cache | --cache-file | \
	-q | --quiet | --silent | --version )
		AC_MSG_CHECKING([if option $1 is known])
		AC_MSG_RESULT([yes])
		;;

	## now the hard-coded libtool ones
	--enable-ltdl-install | --disable-ltdl-install | \
	--enable-ltdl-convenience | --disable-ltdl-convenience | \
	--enable-libtool-lock | --disable-libtool-lock | \
	--enable-fast-install | --disable-fast-install | \
	--enable-shared | --disable-shared | \
	--enable-static | --disable-static | \
	--with-gcc-arch | --with-pic | --with-included-ltdl )
		AC_MSG_CHECKING([if option $1 is known])
		AC_MSG_RESULT([yes])
		;;

	## now our own stuff
	--enable-* | --disable-* )
		AC_MSG_CHECKING([if option $1 is known])
		strp_opt=$(echo $unq_opt | \
			sed -e "s/^--enable-//g" -e "s/^--disable-//g")
		OG_CHECK_OPTION([enable], [$strp_opt],
			AC_MSG_RESULT([yes]),
			AC_MSG_RESULT([no])
			[bogus_cmd_opts="$bogus_cmd_opts $unq_opt"])
		;;
	## more of our own
	--with-* | --without-* )
		AC_MSG_CHECKING([if option $1 is known])
		strp_opt=$(echo $unq_opt | \
			sed -e "s/^--with-//g" -e "s/^--without-//g")
		OG_CHECK_OPTION([with], [$strp_opt],
			AC_MSG_RESULT([yes]),
			AC_MSG_RESULT([no])
			[bogus_cmd_opts="$bogus_cmd_opts $unq_opt"])
		;;

	## strange constructions
	-* )
		case "$1" in
		\'-*)
			AC_MSG_CHECKING([if option $1 is known])
			AC_MSG_RESULT([no])
			bogus_cmd_opts="$bogus_cmd_opts $unq_opt"
			;;
		esac
		;;
	## rest goes here
	* )
		## whatever that is
		;;
	esac
])dnl _SXE_CHECK_PURE_OPT

AC_DEFUN([SXE_CHECK_COMMAND_LINE], [dnl
	dnl Check for bogus options
	sxe_with_options="$sxe_with_options x"
	cmd_line_args="$ac_configure_args"

	## make sure our bogus stuff is empty once we get into here
	## this allows us to call this stuff more than once
	## (which never happens of course)
	bogus_cmd_opts=""

	for opt in $cmd_line_args; do
		pure_opt=$(echo $opt | sed -e "s/=.*$//g")
		_SXE_CHECK_PURE_OPT([$pure_opt])
	done

	dnl Final command line argument checks.
	dnl --with-quantify or --with-purify imply --with-system-malloc
	if test "$with_purify" = "yes" -o "$with_quantify" = "yes"; then
		if test "$with_system_malloc" = "default"; then
			with_system_malloc="yes"
		fi
	fi
])dnl SXE_CHECK_COMMAND_LINE


AC_DEFUN([SXE_EXPAND_VAR], [dnl
	## arg #1 the variable to expand
	## arg #2 (optional) the variable to put the result in
	pushdef([VAR], [$1])
	pushdef([RES], ifelse($2,[],[sxe_cv_tmp_expand_var],$2))

	RES=[]VAR[]
	__tmp=
	while test "${RES}" != "${__tmp}"; do
		__tmp=${RES}
		RES=$(eval echo ${__tmp})
	done
	popdef([RES])
	popdef([VAR])
])dnl SXE_EXPAND_VAR


dnl sxe-aux.m4 ends here
dateutils-0.3.1/m4/sxe-compiler.m4000066400000000000000000000521731241477753400167300ustar00rootroot00000000000000dnl compiler.m4 --- compiler magic
dnl
dnl Copyright (C) 2005-2014 Sebastian Freundt
dnl Copyright (c) 2005 Steven G. Johnson
dnl Copyright (c) 2005 Matteo Frigo
dnl
dnl Author: Sebastian Freundt 
dnl
dnl Redistribution and use in source and binary forms, with or without
dnl modification, are permitted provided that the following conditions
dnl are met:
dnl
dnl 1. Redistributions of source code must retain the above copyright
dnl    notice, this list of conditions and the following disclaimer.
dnl
dnl 2. Redistributions in binary form must reproduce the above copyright
dnl    notice, this list of conditions and the following disclaimer in the
dnl    documentation and/or other materials provided with the distribution.
dnl
dnl 3. Neither the name of the author nor the names of any contributors
dnl    may be used to endorse or promote products derived from this
dnl    software without specific prior written permission.
dnl
dnl THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
dnl IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
dnl WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
dnl DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
dnl FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
dnl CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
dnl SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
dnl BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
dnl WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
dnl OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
dnl IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dnl
dnl This file is part of SXEmacs.

##### http://autoconf-archive.cryp.to/ax_check_compiler_flags.html
## renamed the prefix to SXE_
AC_DEFUN([SXE_CHECK_COMPILER_FLAG], [dnl
dnl SXE_CHECK_COMPILER_FLAG([flag], [action-if-accepted], [action-if-not-accepted])
	AC_MSG_CHECKING([whether _AC_LANG compiler accepts $1])

	## store werror status, then turn -Werror on
	save_ac_[]_AC_LANG_ABBREV[]_werror_flag="${ac_[]_AC_LANG_ABBREV[]_werror_flag}"
	AC_LANG_WERROR

	AC_CACHE_VAL(AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flag_$1), [dnl
		sxe_save_FLAGS="${[]_AC_LANG_PREFIX[]FLAGS}"
		_AC_LANG_PREFIX[]FLAGS="$1"
		AC_COMPILE_IFELSE([AC_LANG_PROGRAM($4)],
			eval AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flag_$1)="yes",
			eval AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flag_$1)="no")
		_AC_LANG_PREFIX[]FLAGS="${sxe_save_FLAGS}"
	])
	eval sxe_check_flag=$AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flag_$1)
	ac_[]_AC_LANG_ABBREV[]_werror_flag="${save_ac_[]_AC_LANG_ABBREV[]_werror_flag}"

	AC_MSG_RESULT([${sxe_check_flag}])
	if test "${sxe_check_flag}" = "yes"; then
		:
		$2
	else
		:
		$3
	fi
])dnl SXE_CHECK_COMPILER_FLAG

AC_DEFUN([SXE_CHECK_PREPROC_FLAG], [dnl
dnl SXE_CHECK_CPP_FLAG([flag], [action-if-found], [action-if-not-found])
	AC_MSG_CHECKING([whether _AC_LANG preprocessor accepts $1])

	## store werror status, then turn -Werror on
	save_ac_[]_AC_LANG_ABBREV[]_werror_flag="${ac_[]_AC_LANG_ABBREV[]_werror_flag}"
	AC_LANG_WERROR

	AC_CACHE_VAL(AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]pp_flag_$1), [dnl
		sxe_save_FLAGS="${[]_AC_LANG_PREFIX[]PPFLAGS}"
		_AC_LANG_PREFIX[]PPFLAGS="$1"
		AC_PREPROC_IFELSE([AC_LANG_PROGRAM()],
			eval AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]pp_flag_$1)="yes",
			eval AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]pp_flag_$1)="no")
		_AC_LANG_PREFIX[]PPFLAGS=$sxe_save_FLAGS
	])
	eval sxe_check_flag=$AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]pp_flag_$1)
	ac_[]_AC_LANG_ABBREV[]_werror_flag="${save_ac_[]_AC_LANG_ABBREV[]_werror_flag}"

	AC_MSG_RESULT([${sxe_check_flag}])
	if test "${sxe_check_flag}" = "yes"; then
		:
		$2
	else
		:
		$3
	fi
])dnl SXE_CHECK_PREPROC_FLAG

AC_DEFUN([SXE_CHECK_CCLD_FLAG], [dnl
dnl SXE_CHECK_CCLD_FLAG([flag], [action-if-accepted], [action-if-not-accepted])
	AC_MSG_CHECKING([whether _AC_LANG linker accepts $1])

	## store werror status, then turn -Werror on
	save_ac_[]_AC_LANG_ABBREV[]_werror_flag="${ac_[]_AC_LANG_ABBREV[]_werror_flag}"
	AC_LANG_WERROR

	AC_CACHE_VAL(AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flag_$1), [dnl
		sxe_save_FLAGS="${[]_AC_LANG_PREFIX[]FLAGS}"
		_AC_LANG_PREFIX[]FLAGS="$1"
		AC_LINK_IFELSE([AC_LANG_PROGRAM()],
			eval AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flag_$1)="yes",
			eval AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flag_$1)="no")
		_AC_LANG_PREFIX[]FLAGS="${sxe_save_FLAGS}"
	])
	eval sxe_check_flag=$AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flag_$1)
	ac_[]_AC_LANG_ABBREV[]_werror_flag="${save_ac_[]_AC_LANG_ABBREV[]_werror_flag}"

	AC_MSG_RESULT([${sxe_check_flag}])
	if test "${sxe_check_flag}" = "yes"; then
		:
		$2
	else
		:
		$3
	fi
])dnl SXE_CHECK_CCLD_FLAG


AC_DEFUN([SXE_DEBUGFLAGS], [dnl
	## distinguish between different compilers, no?
	SXE_CHECK_COMPILER_FLAG([-g])
	SXE_CHECK_COMPILER_FLAG([-g3])

	AC_PATH_PROG([DBX], [dbx])
	if test -n "$ac_cv_path_DBX"; then
		SXE_CHECK_COMPILER_FLAG([-gstabs])
		SXE_CHECK_COMPILER_FLAG([-gstabs3])
		SXE_CHECK_COMPILER_FLAG([-gxcoff])
		SXE_CHECK_COMPILER_FLAG([-gxcoff3])
	fi

	AC_PATH_PROG([GDB], [gdb])
	if test -n "$ac_cv_path_GDB"; then
		SXE_CHECK_COMPILER_FLAG([-ggdb])
		SXE_CHECK_COMPILER_FLAG([-ggdb3])
	fi

	AC_PATH_PROG([SDB], [sdb])
	if test -n "$ac_cv_path_SDB"; then
		SXE_CHECK_COMPILER_FLAG([-gcoff])
		SXE_CHECK_COMPILER_FLAG([-gcoff3])
	fi

	## final evaluation
	debugflags=""
	## gdb
	if test "$sxe_cv_c_flag__ggdb3" = "yes"; then
		debugflags="$debugflags -ggdb3"
	elif test "$sxe_cv_c_flag__ggdb" = "yes"; then
		debugflags="$debugflags -ggdb"
	fi
	## stabs
	if test "$sxe_cv_c_flag__gstabs3" = "yes"; then
		debugflags="$debugflags -gstabs3"
	elif test "$sxe_cv_c_flag__gstabs" = "yes"; then
		debugflags="$debugflags -gstabs"
	fi
	## coff
	if test "$sxe_cv_c_flag__gcoff3" = "yes"; then
		debugflags="$debugflags -gcoff3"
	elif test "$sxe_cv_c_flag__gcoff" = "yes"; then
		debugflags="$debugflags -gcoff"
	fi
	## xcoff
	if test "$sxe_cv_c_flag__gxcoff3" = "yes"; then
		debugflags="$debugflags -gxcoff3"
	elif test "$sxe_cv_c_flag__gxcoff" = "yes"; then
		debugflags="$debugflags -gxcoff"
	fi

	if test -z "debugflags" -a \
		"$sxe_cv_c_flag__g" = "yes"; then
		debugflags="$debugflags -g"
	fi

	SXE_CHECK_COMPILER_FLAG([-ftime-report])
	SXE_CHECK_COMPILER_FLAG([-fmem-report])
	SXE_CHECK_COMPILER_FLAG([-fvar-tracking])
	SXE_CHECK_COMPILER_FLAG([-save-temps])

	#if test "$sxe_cv_c_flag__ggdb3" = "yes" -a \
	#	"$sxe_cv_c_flag__fvar_tracking" = "yes"; then
	#	debugflags="$debugflags -fvar-tracking"
	#fi

	AC_MSG_CHECKING([for preferred debugging flags])
	AC_MSG_RESULT([${debugflags}])
])dnl SXE_DEBUGFLAGS

AC_DEFUN([SXE_WARNFLAGS], [dnl
	## Calculate warning flags.  We separate the flags for warnings from
	## the other flags because we want to force the warnings to be seen
	## by everyone who doesn't specifically override them.

	## by default we want the -Wall level
	SXE_CHECK_COMPILER_FLAG([-Wall], [warnflags="-Wall"])

	SXE_CHECK_COMPILER_FLAG([-qinfo], [
		warnflags="${warnflags} -qinfo"])

	SXE_CHECK_COMPILER_FLAG([-Wextra], [
		warnflags="${warnflags} -Wextra"])

	## Yuck, bad compares have been worth at
	## least 3 crashes!
	## Warnings about char subscripts are pretty
	## pointless, though,
	## and we use them in various places.
	SXE_CHECK_COMPILER_FLAG([-Wsign-compare], [
		warnflags="$warnflags -Wsign-compare"])
	SXE_CHECK_COMPILER_FLAG([-Wno-char-subscripts], [
		warnflags="$warnflags -Wno-char-subscripts"])
	SXE_CHECK_COMPILER_FLAG([-Wundef], [
		warnflags="$warnflags -Wundef"])

	## too much at the moment, we rarely define protos
	#warnflags="$warnflags -Wmissing-prototypes -Wstrict-prototypes"

	## somehow clang seems to think -Wpacked is to inform me
	## about how unnecessary the packed attr is, so conditionalise ...
	SXE_CHECK_COMPILER_FLAG([-Wpacked], [
		warnflags="$warnflags -Wpacked"], [:], [[
#if defined __clang__
# error
#endif  /* __clang__ */
]])

	## glibc is intentionally not `-Wpointer-arith'-clean.
	## Ulrich Drepper has rejected patches to fix
	## the glibc header files.
	## we dont care
	SXE_CHECK_COMPILER_FLAG([-Wpointer-arith], [
		warnflags="$warnflags -Wpointer-arith"])

	SXE_CHECK_COMPILER_FLAG([-Wshadow], [
		warnflags="$warnflags -Wshadow"])

	## our code lacks declarations almost all the time
	SXE_CHECK_COMPILER_FLAG([-Wmissing-declarations], [
		warnflags="$warnflags -Wmissing-declarations"])
	SXE_CHECK_COMPILER_FLAG([-Wmissing-prototypes], [
		warnflags="$warnflags -Wmissing-prototypes"])

	## gcc can't practically inline anything, so exclude this
	case "${CC}" in
	dnl (
	*"gcc"*)
		;;
	dnl (
	*)
		SXE_CHECK_COMPILER_FLAG([-Winline], [
			warnflags="$warnflags -Winline"])
		;;
	esac

	SXE_CHECK_COMPILER_FLAG([-Wbad-function-cast], [
		warnflags="$warnflags -Wbad-function-cast"])
	SXE_CHECK_COMPILER_FLAG([-Wcast-qual], [
		warnflags="$warnflags -Wcast-qual"])
	SXE_CHECK_COMPILER_FLAG([-Wcast-align], [
		warnflags="$warnflags -Wcast-align"])

	## warn about incomplete switches
	## for gcc, see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50422
	## we used to have -Wswitch-default and -Wswitch-enum but that
	## set gcc off quite badly in the nested switch case
	SXE_CHECK_COMPILER_FLAG([-Wno-switch], [
		warnflags="$warnflags -Wno-switch"])

	SXE_CHECK_COMPILER_FLAG([-Wunused-function], [
		warnflags="$warnflags -Wunused-function"])
	SXE_CHECK_COMPILER_FLAG([-Wunused-variable], [
		warnflags="$warnflags -Wunused-variable"])
	SXE_CHECK_COMPILER_FLAG([-Wunused-parameter], [
		warnflags="$warnflags -Wunused-parameter"])
	SXE_CHECK_COMPILER_FLAG([-Wunused-value], [
		warnflags="$warnflags -Wunused-value"])
	SXE_CHECK_COMPILER_FLAG([-Wunused], [
		warnflags="$warnflags -Wunused"])
	SXE_CHECK_COMPILER_FLAG([-Wmaybe-uninitialized], [
		warnflags="${warnflags} -Wmaybe-uninitialized"])

	SXE_CHECK_COMPILER_FLAG([-Wnopragma], [
		warnflags="$warnflags -Wnopragma"])

	SXE_CHECK_COMPILER_FLAG([-fdiagnostics-show-option], [
		warnflags="${warnflags} -fdiagnostics-show-option"])

	SXE_CHECK_COMPILER_FLAG([-Wunknown-pragmas], [
		warnflags="$warnflags -Wunknown-pragmas"])
	SXE_CHECK_COMPILER_FLAG([-Wuninitialized], [
		warnflags="$warnflags -Wuninitialized"])
	SXE_CHECK_COMPILER_FLAG([-Wreorder], [
		warnflags="$warnflags -Wreorder"])
	SXE_CHECK_COMPILER_FLAG([-Wdeprecated], [
		warnflags="$warnflags -Wdeprecated"])

	SXE_CHECK_COMPILER_FLAG([-Wno-parentheses], [
		warnflags="${warnflags} -Wno-parentheses"])

	## icc specific
	SXE_CHECK_COMPILER_FLAG([-Wcheck], [
		warnflags="$warnflags -Wcheck"])

	dnl SXE_CHECK_COMPILER_FLAG([-Wp64], [
	dnl 	warnflags="$warnflags -Wp64"])

	SXE_CHECK_COMPILER_FLAG([-Wstrict-aliasing], [
		warnflags="$warnflags -Wstrict-aliasing"])

	SXE_CHECK_COMPILER_FLAG([-w3], [
		warnflags="$warnflags -w3"])

	SXE_CHECK_COMPILER_FLAG([-diag-disable 10237], [dnl
		warnflags="${warnflags} -diag-disable 10237"], [
		SXE_CHECK_COMPILER_FLAG([-wd 10237], [dnl
			warnflags="${warnflags} -wd 10237"])])

	SXE_CHECK_COMPILER_FLAG([-debug inline-debug-info], [
		warnflags="${warnflags} -debug inline-debug-info"])

	SXE_CHECK_COMPILER_FLAG([-diag-enable remark,vec,par], [
		warnflags="${warnflags} -diag-enable remark,vec,par"])

	## for dfp754
	SXE_CHECK_COMPILER_FLAG([-Wunsuffixed-float-constants], [
		warnflags="$warnflags -Wunsuffixed-float-constants"])

	AC_MSG_CHECKING([for preferred warning flags])
	AC_MSG_RESULT([${warnflags}])
])dnl SXE_WARNFLAGS

AC_DEFUN([SXE_OPTIFLAGS], [dnl
	AC_REQUIRE([SXE_USER_CFLAGS])

	case " ${CFLAGS} ${EXTRA_CFLAGS}" in
	(*" -O"[0-9])
		;;
	(*)
		SXE_CHECK_COMPILER_FLAG([-O3], [
			optiflags="${optiflags} -O3"])
		;;
	esac

	SXE_CHECK_COMPILER_FLAG([-ipo256], [
		optiflags="${optiflags} -ipo256"])

	SXE_CHECK_COMPILER_FLAG([-ipo-jobs256], [
		optiflags="${optiflags} -ipo-jobs256"])

	SXE_CHECK_COMPILER_FLAG([-no-prec-div], [
		optiflags="${optiflags} -no-prec-div"])

	## -fast implies -static which is a dream but
	## packager prefer dynamic binaries
	dnl SXE_CHECK_COMPILER_FLAG([-fast], [
	dnl 	optiflags="${optiflags} -fast"])

	## auto-vectorisation
	dnl SXE_CHECK_COMPILER_FLAG([-axMIC-AVX512,CORE-AVX2,CORE-AVX-I,AVX,SSSE3], [
	dnl 	optiflags="${optiflags} -axMIC-AVX512,CORE-AVX2,CORE-AVX-I,AVX,SSSE3"])

	case " ${CFLAGS} ${EXTRA_CFLAGS}" in
	(*" -mtune"*)
		## don't tune
		;;
	(*" -march"*)
		## don't set march
		;;
	(*" -m32 "*)
		## don't bother
		;;
	(*" -m64 "*)
		## don't bother
		;;
	(*)
		SXE_CHECK_COMPILER_FLAG([-xHost], [
			optiflags="${optiflags} -xHost"], [
			## non-icc
			SXE_CHECK_COMPILER_FLAG([-mtune=native -march=native], [
				optiflags="${optiflags} -mtune=native -march=native"])
		])
		;;
	esac
])dnl SXE_OPTIFLAGS

AC_DEFUN([SXE_FEATFLAGS], [dnl
	## default flags for needed features
	AC_REQUIRE([SXE_CHECK_COMPILER_XFLAG])
	XCCFLAG="${XFLAG}"

	## recent gentoos went ballistic again, they compile PIE gcc's
	## but there's no way to turn that misconduct off ...
	## however I've got one report about a working PIE build
	## we'll just check for -nopie here, if it works, we turn it on
	## (and hence PIE off) and hope bug 16 remains fixed
	SXE_CHECK_COMPILER_FLAG([-nopie],
		[featflags="$featflags -nopie"])

	## icc and gcc related
	## check if some stuff can be staticalised
	## actually requires SXE_WARNFLAGS so warnings would be disabled
	## that affect the outcome of the following tests
	SXE_CHECK_COMPILER_FLAG([-static-intel], [
		featflags="${featflags} -static-intel"
		XCCLDFLAGS="${XCCLDFLAGS} \${XCCFLAG} -static-intel"], [:])
	SXE_CHECK_COMPILER_FLAG([-static-libgcc], [
		featflags="${featflags} -static-libgcc"
		XCCLDFLAGS="${XCCLDFLAGS} \${XCCFLAG} -static-libgcc"], [:])

	SXE_CHECK_COMPILER_FLAG([-intel-extensions], [dnl
		featflags="${featflags} -intel-extensions"])

	AC_SUBST([XCCLDFLAGS])
	AC_SUBST([XCCFLAG])
])dnl SXE_FEATFLAGS

AC_DEFUN([SXE_CHECK_COMPILER_XFLAG], [dnl
	if test "${XFLAG}" = ""; then
		SXE_CHECK_CCLD_FLAG([-XCClinker -foo], [XFLAG="-XCClinker"])
	fi
	if test "${XFLAG}" = ""; then
		SXE_CHECK_CCLD_FLAG([-Xlinker -foo], [XFLAG="-Xlinker"])
	fi

	AC_SUBST([XFLAG])
])dnl SXE_CHECK_COMPILER_XFLAG

AC_DEFUN([SXE_USER_CFLAGS], [dnl
	AC_MSG_CHECKING([for user provided CFLAGS/EXTRA_CFLAGS])

	CFLAGS="${ac_cv_env_CFLAGS_value}"
	AC_MSG_RESULT([${CFLAGS} ${EXTRA_CFLAGS}])
])dnl SXE_USER_CFLAGS


AC_DEFUN([SXE_CHECK_CFLAGS], [dnl
	dnl #### This may need to be overhauled so that all of SXEMACS_CC's flags
	dnl are handled separately, not just the xe_cflags_warning stuff.
	AC_ARG_VAR([EXTRA_CFLAGS], [C compiler flags to be APPENDED.])

	## check for user provided flags
	AC_REQUIRE([SXE_USER_CFLAGS])
	## Use either command line flag, environment var, or autodetection
	SXE_DEBUGFLAGS
	SXE_WARNFLAGS
	SXE_OPTIFLAGS
	SXE_CFLAGS="${SXE_CFLAGS} ${debugflags} ${optiflags} ${warnflags}"

	SXE_FEATFLAGS
	SXE_CFLAGS="${SXE_CFLAGS} ${featflags}"

	save_ac_c_werror_flag="${ac_c_werror_flag}"

	CFLAGS="${CFLAGS} ${SXE_CFLAGS} ${EXTRA_CFLAGS}"
	AC_MSG_CHECKING([for preferred CFLAGS])
	AC_MSG_RESULT([${CFLAGS}])

	AC_MSG_NOTICE([
If you wish to APPEND your own flags you want to stop here and rerun the
configure script like so:
  configure EXTRA_CFLAGS=

If you wish to OVERRIDE these flags you want to stop here too and rerun
the configure script like this:
  configure CFLAGS=

You can always override the determined CFLAGS, partially or totally,
using
  make -C  CFLAGS= [target]
or
  make CFLAGS= [target]
respectively
		])

	ac_c_werror_flag="${save_ac_c_werror_flag}"
])dnl SXE_CHECK_CFLAGS

AC_DEFUN([SXE_CHECK_CC], [dnl
dnl SXE_CHECK_CC([STANDARDS])
dnl standards are flavours supported by the compiler chosen with AC_PROG_CC
	pushdef([stds], m4_default([$1], [gnu11 c11 gnu99 c99]))

	AC_REQUIRE([AC_CANONICAL_HOST])
	AC_REQUIRE([AC_CANONICAL_BUILD])
	AC_REQUIRE([AC_PROG_CPP])
	AC_REQUIRE([AC_PROG_CC])

	AC_HEADER_STDC

	case "${CC}" in dnl (
	*"-std="*)
		## user specified a std value already
		;;
		dnl (
	*)
		for i in []stds[]; do
			SXE_CHECK_COMPILER_FLAG([-std="${i}"], [
				std="-std=${i}"
				save_CC="${CC}"
				CC="${CC} ${std}"
				SXE_CHECK_ANON_STRUCTS_DECL
				CC="${save_CC}"
				if test "${sxe_cv_have_anon_structs_decl}" \
					= "yes"; then
					break
				fi
			])
		done

		AC_MSG_CHECKING([for preferred CC std])
		AC_MSG_RESULT([${std}])
		CC="${CC} ${std}"

		## while we're at it, check for anon initialising too
		SXE_CHECK_ANON_STRUCTS_INIT
		## oh and sloppy sloppy init
		SXE_CHECK_SLOPPY_STRUCTS_INIT
		;;
	esac

	popdef([stds])
])dnl SXE_CHECK_CC

AC_DEFUN([SXE_CHECK_ANON_STRUCTS_INIT], [
	AC_MSG_CHECKING([dnl
whether C compiler can initialise anonymous structs and unions])
	AC_LANG_PUSH([C])

	## backup our CFLAGS and unset it
	save_CFLAGS="${CFLAGS}"
	CFLAGS=""

	AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
union __test_u {
	int i;
	struct {
		char c;
		char padc;
		short int pads;
	};
};
	]], [[
	union __test_u tmp = {.c = '4'};
	]])], [
		sxe_cv_have_anon_structs_init="yes"
	], [
		sxe_cv_have_anon_structs_init="no"
	])
	AC_MSG_RESULT([${sxe_cv_have_anon_structs_init}])

	## restore CFLAGS
	CFLAGS="${save_CFLAGS}"

	if test "${sxe_cv_have_anon_structs_init}" = "yes"; then
		AC_DEFINE([HAVE_ANON_STRUCTS_INIT], [1], [dnl
Whether c11 anon struct initialising works])
		$1
		:
	else
		$2
		:
	fi
	AC_LANG_POP()
])dnl SXE_CHECK_ANON_STRUCTS_INIT

AC_DEFUN([SXE_CHECK_ANON_STRUCTS_DECL], [
	AC_MSG_CHECKING([dnl
whether C compiler can understand anonymous structs and unions])
	AC_LANG_PUSH([C])

	## backup our CFLAGS and unset it
	save_CFLAGS="${CFLAGS}"
	CFLAGS=""

	AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
union __test_u {
	int i;
	struct {
		char c;
		char padc;
		short int pads;
	};
};
	]], [[
	/* nothing to do really*/
	union __test_u foo;
	foo.c = 0;
	]])], [
		sxe_cv_have_anon_structs_decl="yes"
	], [
		sxe_cv_have_anon_structs_decl="no"
	])
	AC_MSG_RESULT([${sxe_cv_have_anon_structs_decl}])

	## restore CFLAGS
	CFLAGS="${save_CFLAGS}"

	if test "${sxe_cv_have_anon_structs_decl}" = "yes"; then
		AC_DEFINE([HAVE_ANON_STRUCTS_DECL], [1], [dnl
Whether c11 anon structs declaring works])
		$1
		:
	else
		$2
		:
	fi
	AC_LANG_POP()
])dnl SXE_CHECK_ANON_STRUCTS_DECL

AC_DEFUN([SXE_CHECK_SLOPPY_STRUCTS_INIT], [
	AC_LANG_PUSH([C])

	## backup our CFLAGS and unset it
	save_CFLAGS="${CFLAGS}"
	CFLAGS="-Werror"

	SXE_CHECK_COMPILER_FLAG([-Wmissing-field-initializers], [
		CFLAGS="${CFLAGS} -Wmissing-field-initializers"])

	AC_MSG_CHECKING([dnl
whether C compiler can initialise structs and unions in a sloppy way])

	AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
struct __test_s {
	int i;
	int j;
};
	]], [[
	struct __test_s tmp = {};
	]])], [
		sxe_cv_have_sloppy_structs_init="yes"
	], [
		sxe_cv_have_sloppy_structs_init="no"
	])
	AC_MSG_RESULT([${sxe_cv_have_sloppy_structs_init}])

	## restore CFLAGS
	CFLAGS="${save_CFLAGS}"

	if test "${sxe_cv_have_sloppy_structs_init}" = "yes"; then
		AC_DEFINE([HAVE_SLOPPY_STRUCTS_INIT], [1], [dnl
Whether sloppy struct initialising works])
		$1
		:
	else
		$2
		:
	fi
	AC_LANG_POP()
])dnl SXE_CHECK_SLOPPY_STRUCTS_INIT

AC_DEFUN([SXE_CHECK_INTRINS], [dnl
	AC_CHECK_HEADERS([immintrin.h])
	AC_CHECK_HEADERS([x86intrin.h])
	AC_CHECK_HEADERS([ia32intrin.h])
	AC_CHECK_HEADERS([popcntintrin.h])
	AC_CHECK_TYPES([__m128i], [], [], [[
#if defined HAVE_X86INTRIN_H
# include 
#elif defined HAVE_IMMINTRIN_H
# include 
#endif
]])
	AC_CHECK_TYPES([__m256i], [], [], [[
#if defined HAVE_X86INTRIN_H
# include 
#elif defined HAVE_IMMINTRIN_H
# include 
#endif
]])
	AC_CHECK_TYPES([__m512i], [], [], [[
#if defined HAVE_X86INTRIN_H
# include 
#elif defined HAVE_IMMINTRIN_H
# include 
#endif
]])
])dnl SXE_CHECK_INTRINS

AC_DEFUN([SXE_CHECK_SIMD], [dnl
dnl Usage: SXE_CHECK_SIMD([INTRIN], [[SNIPPET], [IF-FOUND], [IF-NOT-FOUND]])
	AC_REQUIRE([SXE_CHECK_INTRINS])

	AC_MSG_CHECKING([for SIMD routine $1])
	AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#if defined HAVE_IA32INTRIN_H
# include 
#endif
#if defined HAVE_X86INTRIN_H
# include 
#endif
#if defined HAVE_IMMINTRIN_H
# include 
#endif
#if defined HAVE_POPCNTINTRIN_H
# include 
#endif
]], [ifelse([$2],[],[$1(0U)],[$2]);])], [
	eval AS_TR_SH(ac_cv_func_$1)="yes"
	AC_DEFINE(AS_TR_CPP([HAVE_$1]), [1], [dnl
Define to 1 if you have the `$1' simd routine])
	$3
], [
	eval AS_TR_SH(ac_cv_func_$1)="no"
	$4
])
	AC_MSG_RESULT([${ac_cv_func_$1}])
])dnl SXE_CHECK_SIMD

AC_DEFUN([SXE_CHECK_CILK], [dnl
dnl Usage: SXE_CHECK_CILK([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl defines sxe_cv_feat_cilk to "yes" if applicable, "no" otherwise
dnl also AC_DEFINEs HAVE_CILK
	AC_CHECK_HEADERS([cilk/cilk.h])

	SXE_CHECK_COMPILER_FLAG([-fcilkplus], [CFLAGS="${CFLAGS} -fcilkplus"])

	AC_MSG_CHECKING([whether Cilk+ keywords work])
	AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include 
#if defined HAVE_CILK_CILK_H
# include 
#else  /* !HAVE_CILK_CILK_H */
# define cilk_spawn	_Cilk_spawn
# define cilk_sync	_Cilk_sync
# define cilk_for	_Cilk_for
#endif /* HAVE_CILK_CILK_H */

static char *trick;

static int pcmp(const void *x, const void *y)
{
	return (const char*)x - (const char*)y;
}
]], [
int x = 0;
int j;

cilk_spawn qsort(trick, 1, 2, pcmp);
qsort(trick + 4, 1, 2, pcmp);
cilk_sync;

cilk_for(j = 0; j < 8; j++) {
	x++;
}
])], [
	AC_DEFINE([HAVE_CILK], [1], [define when compiler supports Cilk+ keywords])
	sxe_cv_feat_cilk="yes"
	$1
], [
	sxe_cv_feat_cilk="no"
	$2
])
	AC_MSG_RESULT([${sxe_cv_feat_cilk}])
])dnl SXE_CHECK_CILK

dnl sxe-compiler.m4 ends here
dateutils-0.3.1/m4/sxe-libtool.m4000066400000000000000000000031061241477753400165520ustar00rootroot00000000000000dnl sxe-libtool.m4 -- just a quick libtoolish macros
dnl
dnl Copyright (C) 2007-2014 Sebastian Freundt.
dnl
dnl This file is part of unserding

AC_DEFUN([SXE_CHECK_LIBTOOL], [dnl
	AC_MSG_RESULT([starting libtool investigation...])

	## turn off -Werror'ing
	ac_[]_AC_LANG_ABBREV[]_werror_flag=

	LT_PREREQ([2.1])
	LT_INIT([dlopen])

	LT_LIB_DLLOAD
	LT_LIB_M
	LT_SYS_DLOPEN_DEPLIBS
	LT_SYS_SYMBOL_USCORE
	LT_FUNC_DLSYM_USCORE

	## cope with libtool's convenience lib/bin concept
	if test -n "$lt_cv_objdir"; then
		## this variable is a #define, too
		LT_OBJDIR="$lt_cv_objdir"
	else
		## hm, probably not the best idea but let's try
		LT_OBJDIR="."
	fi
	## definitely subst that though
	AC_SUBST([LT_OBJDIR])

	## currently there's no official variable for that, but `lt-'
	## seems to be a consistent choice throughout all libtools
	LT_CONVENIENCE_PREFIX="lt-"
	AC_SUBST([LT_CONVENIENCE_PREFIX])

	## reset XCCFLAG, we KNOW it's XCClinker in libtool
	XCCFLAG="-XCClinker"
])dnl SXE_CHECK_LIBTOOL

AC_DEFUN([SXE_CHECK_LIBLTDL], [dnl
	## make sure the libtool stuff has been run before
	AC_REQUIRE([SXE_CHECK_LIBTOOL])

	## This can't be here because older versions of libtool
	## seem to overlook the argument to LTDL_INIT
	## put the next two lines into c.ac instead and then call this macro
	dnl LT_CONFIG_LTDL_DIR([libltdl])
	dnl LTDL_INIT([recursive])

	# workaround libtool LT_CONFIG_H bug #12262
	AC_CONFIG_COMMANDS_PRE([LT_CONFIG_H=`expr "$LT_CONFIG_H" : '.*/\(.*\)'`])
	AM_CONDITIONAL([DESCEND_LIBLTDL], [test "${with_included_ltdl}" = "yes"])
])dnl SXE_CHECK_LIBLTDL

dnl sxe-libtool.m4 ends here
dateutils-0.3.1/m4/sxe-linker.m4000066400000000000000000000132421241477753400163740ustar00rootroot00000000000000dnl linker.m4 --- linker magic
dnl
dnl Copyright (C) 2005 - 2012 Sebastian Freundt
dnl Copyright (c) 2005 Steven G. Johnson
dnl Copyright (c) 2005 Matteo Frigo
dnl
dnl Author: Sebastian Freundt 
dnl
dnl Redistribution and use in source and binary forms, with or without
dnl modification, are permitted provided that the following conditions
dnl are met:
dnl
dnl 1. Redistributions of source code must retain the above copyright
dnl    notice, this list of conditions and the following disclaimer.
dnl
dnl 2. Redistributions in binary form must reproduce the above copyright
dnl    notice, this list of conditions and the following disclaimer in the
dnl    documentation and/or other materials provided with the distribution.
dnl
dnl 3. Neither the name of the author nor the names of any contributors
dnl    may be used to endorse or promote products derived from this
dnl    software without specific prior written permission.
dnl
dnl THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
dnl IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
dnl WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
dnl DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
dnl FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
dnl CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
dnl SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
dnl BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
dnl WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
dnl OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
dnl IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dnl
dnl This file is part of SXEmacs.

AC_DEFUN([SXE_CHECK_LINKER_FLAGS], [dnl
dnl just like SXE_CHECK_COMPILER_FLAGS but calls the linker
dnl SXE_CHECK_LINKER_FLAGS(, , ,
dnl     )
	AC_REQUIRE([SXE_CHECK_COMPILER_XFLAG])

	AC_MSG_CHECKING([whether linker accepts $1])

	dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname:
	AC_LANG_WERROR([on])
	AS_LITERAL_IF([$1], [
		AC_CACHE_VAL(AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flags_$1), [
			sxe_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
			_AC_LANG_PREFIX[]FLAGS="$4 ${XFLAG} $1"
			AC_LINK_IFELSE([AC_LANG_PROGRAM()],
				AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flags_$1)="yes",
				AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flags_$1)="no")
			_AC_LANG_PREFIX[]FLAGS=$sxe_save_FLAGS])], [
		sxe_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
		_AC_LANG_PREFIX[]FLAGS="$4 ${XFLAG} $1"
		AC_LINK_IFELSE([AC_LANG_PROGRAM()],
			eval AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flags_$1)="yes",
			eval AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flags_$1)="no")
		_AC_LANG_PREFIX[]FLAGS=$sxe_save_FLAGS])
	eval sxe_check_linker_flags=$AS_TR_SH(sxe_cv_[]_AC_LANG_ABBREV[]_flags_$1)
	AC_LANG_WERROR([off])

	AC_MSG_RESULT([$sxe_check_linker_flags])
	if test "$sxe_check_linker_flags" = "yes"; then
		m4_default([$2], :)
	else
		m4_default([$3], :)
	fi
])dnl SXE_CHECK_LINKER_FLAGS


AC_DEFUN([SXE_CHECK_LD_ZFLAG], [dnl
	pushdef([LD_ZFLAG], [$1])
	pushdef([cv_zflag], [sxe_cv_ld__z_]translit(LD_ZFLAG,[-.=],[___]))

	SXE_CHECK_LINKER_FLAGS([-z ]LD_ZFLAG[])

dnl Use the check that actually calls the compiler/linker to examine the flags
dnl	AC_CACHE_CHECK([whether linker supports -z ]LD_ZFLAG[],
dnl		[]cv_zflag[], [_SXE_CHECK_LD_ZFLAG(LD_ZFLAG)])

	popdef([cv_zflag])
	popdef([LD_ZFLAG])
])dnl SXE_CHECK_LD_ZFLAG

AC_DEFUN([_SXE_CHECK_LD_ZFLAG], [dnl
	## arg1 is the flag to check for
	pushdef([LD_ZFLAG], [$1])
	pushdef([cv_zflag], [sxe_cv_ld__z_]translit(LD_ZFLAG,[-.=],[___]))

	if test "$GCC" = "yes"; then
		if test "($CC -Xlinker --help 2>&1 | \
			grep \"-z []LD_ZFLAG[]\" > /dev/null 2>&1 ) "; then
			cv_zflag="yes"
		else
			cv_zflag="no"
		fi
	elif test -n "$LD"; then
		if test "($LD --help 2>&1 | \
			grep \"-z []LD_ZFLAG[]\" > /dev/null 2>&1 )"; then
			cv_zflag="yes"
		else
			cv_zflag="no"
		fi
	else
		cv_zflag="no"
	fi

	popdef([cv_zflag])
	popdef([LD_ZFLAG])
])dnl _SXE_CHECK_LD_ZFLAG

AC_DEFUN([SXE_LD_EXPORT_DYNAMIC], [dnl
	SXE_CHECK_LINKER_FLAGS([-export-dynamic], [
		LD_EXPORT_DYNAMIC="-export-dynamic"
	])

	AC_SUBST([LD_EXPORT_DYNAMIC])
])dnl SXE_LD_EXPORT_DYNAMIC

AC_DEFUN([SXE_CHECK_LDFLAGS], [dnl
	AC_REQUIRE([SXE_CHECK_COMPILER_XFLAG])

	## relocation
	SXE_CHECK_LD_ZFLAG([combreloc])
	SXE_CHECK_LD_ZFLAG([nocombreloc])
	## symbols
	SXE_CHECK_LD_ZFLAG([defs])
	SXE_CHECK_LD_ZFLAG([muldefs])
	## search paths
	SXE_CHECK_LD_ZFLAG([nodefaultlib])
	## binding policy
	SXE_CHECK_LD_ZFLAG([lazy])
	SXE_CHECK_LD_ZFLAG([now])

	SXE_LD_EXPORT_DYNAMIC

	LDFLAGS="${ldflags} ${ac_cv_env_LDFLAGS_value}"
	AC_MSG_CHECKING([for preferred LDFLAGS])
	AC_MSG_RESULT([${LDFLAGS}])

	AC_MSG_NOTICE([
If you wish to ADD your own flags you want to stop here and rerun the
configure script like so:
  configure LDFLAGS=

You can always override the determined LDFLAGS, partially or totally,
using
  make -C  LDFLAGS= [target]
or
  make LDFLAGS= [target]
respectively

NOTE: -C  option is not available on all systems
		])
])dnl SXE_CHECK_LDFLAGS

AC_DEFUN([SXE_PREPEND_LINKER_FLAG], [dnl
	## a convenience function to add such linker flags to variables
	## arg1 is the flag to add (must include -z if applicable)
	## arg2 is the variable whither to prepend
	pushdef([FLAG], [$1])
	pushdef([__FLAG], [-Wl,]patsubst([$1], [ ], [[,]]))
	pushdef([VAR], [$2])

	[]VAR[]="[]__FLAG[] $[]VAR[]"
	if test "$extra_verbose" = "yes"; then
		echo "    Prepending linker flag \"[]__FLAG[]\" to \$[]VAR[]"
	fi

	popdef([VAR])
	popdef([__FLAG])
	popdef([FLAG])
])dnl SXE_PREPEND_LINKER_FLAG

dnl sxe-linker.m4 ends here
dateutils-0.3.1/m4/sxe-matlab.m4000066400000000000000000000062401241477753400163500ustar00rootroot00000000000000## first parameter may point to a matlab root or the matlab binary
AC_DEFUN([SXE_CHECK_MATLAB], [dnl
	foo=`mktemp`

	AC_ARG_VAR([MATLAB], [full path to matlab binary])
	sxe_cv_matlab="${MATLAB:-matlab}"

	AC_ARG_VAR([MATLABPATH], [path to matlab toolboxes])
	sxe_cv_matlabpath="${MATLABPATH:-no}"

	AC_MSG_CHECKING([for matlab root])
	## assume no matlab
	sxe_cv_matlabroot="no"

	"${sxe_cv_matlab}" -e 2>/dev/null | grep "MATLAB" > "${foo}"

	## source that
	source "${foo}"

	MATLABROOT="${MATLAB}"
	AC_SUBST([MATLABROOT])
	AC_MSG_RESULT([${MATLABROOT}])

	AC_MSG_CHECKING([for matlab toolbox path])
	if test -z "${sxe_cv_matlabpath}" \
		-o "${sxe_cv_matlabpath}" = "no"; then
		MATLABORIGPATH="${MATLABPATH}"
	else
		MATLABORIGPATH="${MATLABPATH}"
		MATLABPATH="${sxe_cv_matlabpath}"
	fi
	AC_SUBST([MATLABORIGPATH])
	AC_SUBST([MATLABPATH])
	AC_MSG_RESULT([${MATLABPATH}])

	AC_MSG_CHECKING([for matlab mex file extension])
	sxe_cv_mexext=`"${MATLABROOT}/bin/mexext" 2>/dev/null`
	MEXEXT="${sxe_cv_mexext:-mex}"
	AC_SUBST([MEXEXT])
	AC_MSG_RESULT([${sxe_cv_mexext:-mex (assumed)}])

	## now reset *our* idea of what MATLAB should be
	MATLAB="${sxe_cv_matlab}"

	AC_ARG_VAR([matlab_CFLAGS], [include directives for matlab headers])

	if test -n "${matlab_CFLAGS}"; then
		:
	elif test -z "${MATLABROOT}"; then
		## big cluster fuck
		:
	else
		matlab_CFLAGS="-I${MATLABROOT}/extern/include"
	fi
	if test -n "${matlab_CFLAGS}"; then
		save_CPPFLAGS="${CPPFLAGS}"
		CPPFLAGS="${CPPFLAGS} ${matlab_CFLAGS}"
		AC_CHECK_HEADER([mex.h])
		sxe_cv_matlab_mex_h="${ac_cv_header_mex_h}"
		unset ac_cv_header_mex_h
		CPPFLAGS="${save_CPPFLAGS}"
	fi

	rm -f -- "${foo}"
])dnl SXE_CHECK_MATLAB

AC_DEFUN([SXE_CHECK_OCTAVE], [dnl
	## mimic pkg-config
	AC_ARG_VAR([octave_CFLAGS], [include directives for matlab headers])
	AC_ARG_VAR([octave_LIBS], [library directives for octave linking])

	AC_ARG_VAR([OCTAVEPATH], [path to octave toolboxes])
	sxe_cv_octavepath="${OCTAVEPATH:-no}"

	## prep the octave extension path, this is twofold
	AC_PATH_PROG([OCTAVE_CONFIG], [octave-config])
	if test -n "${OCTAVE_CONFIG}"; then
		octave_CFLAGS=-I`"${OCTAVE_CONFIG}" -p OCTINCLUDEDIR`
		octave_LIBS=-L`"${OCTAVE_CONFIG}" -p OCTLIBDIR`
		AC_MSG_CHECKING([for octave toolbox path])
		OCTAVEORIGPATH=`"${OCTAVE_CONFIG}" -p LOCALOCTFILEDIR`
		OCTAVELIBDIR=`"${OCTAVE_CONFIG}" -p LIBDIR`
		OCTAVEPATH=`echo "${OCTAVEORIGPATH#${OCTAVELIBDIR}}"`
		if test "${OCTAVEPATH}" = "${OCTAVEORIGPATH}"; then
			:
		elif test -z "${sxe_cv_octavepath}" \
			-o "${sxe_cv_octavepath}" = "no"; then
			## we did substitute then innit?
			OCTAVEPATH="\${libdir}${OCTAVEPATH}"
		fi
		AC_SUBST([OCTAVEPATH])
		AC_SUBST([OCTAVEORIGPATH])
		AC_MSG_RESULT([${OCTAVEPATH}])
	fi

	save_CPPFLAGS="${CPPFLAGS}"
	CPPFLAGS="${CPPFLAGS} ${octave_CFLAGS}"
	AC_CHECK_HEADERS([mex.h])
	AC_CHECK_HEADERS([octave/mex.h])
	if test "${ac_cv_header_mex_h}" = "yes"; then
		sxe_cv_octave_mex_h="yes"
	elif test "${ac_cv_header_octave_mex_h}" = "yes"; then
		sxe_cv_octave_mex_h="yes"
	fi
	unset ac_cv_header_mex_h
	CPPFLAGS="${save_CPPFLAGS}"

	if test "${sxe_cv_octave_mex_h}" = "yes"; then
		have_octave="yes"
	else
		have_octave="no"
	fi
])dnl SXE_CHECK_OCTAVE

dnl sxe-matlab.m4 ends here
dateutils-0.3.1/m4/sxe-mmap.m4000066400000000000000000000035411241477753400160430ustar00rootroot00000000000000AC_DEFUN([SXE_CHECK_SYS_MMAN], [dnl
	AC_CHECK_HEADERS([sys/mman.h])
])dnl SXE_CHECK_SYS_MMAN

AC_DEFUN([SXE_CHECK_MAP_ANON], [dnl
	AC_MSG_CHECKING([for ANON maps])
	AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#define _POSIX_C_SOURCE 200112L
#define _XOPEN_SOURCE 600
#define _BSD_SOURCE
#if defined HAVE_SYS_MMAN_H
# include 
#endif  /* HAVE_SYS_MMAN_H */
#if defined MAP_ANON
/* good */
#elif defined MAP_ANONYMOUS
/* good too */
#else
# error MAP_ANON | MAP_ANONYMOUS needed
#endif
	]])], [sxe_cv_feat_anon_maps="yes"], [sxe_cv_feat_anon_maps="no"])
	if test "${sxe_cv_feat_anon_maps}" = "no"; then
		AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#define _POSIX_C_SOURCE 200112L
#define _BSD_SOURCE
#define _XOPEN_SOURCE 600
#define _ALL_SOURCE
#if defined HAVE_SYS_MMAN_H
# include 
#endif  /* HAVE_SYS_MMAN_H */
#if defined MAP_ANON
/* good */
#elif defined MAP_ANONYMOUS
/* good too */
#else
# error MAP_ANON | MAP_ANONYMOUS needed
#endif
		]])], [
			sxe_cv_feat_anon_maps="yes"
			AC_DEFINE([MAP_ANON_NEEDS_ALL_SOURCE], [1], 
				[MAP_ANON with _ALL_SOURCE])
		], [
			sxe_cv_feat_anon_maps="no"
		])
	fi
	if test "${sxe_cv_feat_anon_maps}" = "no"; then
		AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#define _POSIX_C_SOURCE 200112L
#define _BSD_SOURCE
#define _XOPEN_SOURCE 600
#define _DARWIN_C_SOURCE
#if defined HAVE_SYS_MMAN_H
# include 
#endif  /* HAVE_SYS_MMAN_H */
#if defined MAP_ANON
/* good */
#elif defined MAP_ANONYMOUS
/* good too */
#else
# error MAP_ANON | MAP_ANONYMOUS needed
#endif
		]])], [
			sxe_cv_feat_anon_maps="yes"
			AC_DEFINE([MAP_ANON_NEEDS_DARWIN_SOURCE], [1], 
				[MAP_ANON with _DARWIN_C_SOURCE])
		], [
			sxe_cv_feat_anon_maps="no"
		])
	fi
	AC_MSG_RESULT([${sxe_cv_feat_anon_maps}])
])dnl SXE_CHECK_MAP_ANON

AC_DEFUN([SXE_CHECK_MMAP], [dnl
	AC_REQUIRE([SXE_CHECK_SYS_MMAN])
	AC_REQUIRE([SXE_CHECK_MAP_ANON])
])dnl SXE_CHECK_MMAP
dateutils-0.3.1/m4/yuck.m4000066400000000000000000000106351241477753400152710ustar00rootroot00000000000000dnl yuck.m4 --- yuck goodies
dnl
dnl Copyright (C) 2013-2014 Sebastian Freundt
dnl
dnl Author: Sebastian Freundt 
dnl
dnl Redistribution and use in source and binary forms, with or without
dnl modification, are permitted provided that the following conditions
dnl are met:
dnl
dnl 1. Redistributions of source code must retain the above copyright
dnl    notice, this list of conditions and the following disclaimer.
dnl
dnl 2. Redistributions in binary form must reproduce the above copyright
dnl    notice, this list of conditions and the following disclaimer in the
dnl    documentation and/or other materials provided with the distribution.
dnl
dnl 3. Neither the name of the author nor the names of any contributors
dnl    may be used to endorse or promote products derived from this
dnl    software without specific prior written permission.
dnl
dnl THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
dnl IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
dnl WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
dnl DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
dnl FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
dnl CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
dnl SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
dnl BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
dnl WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
dnl OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
dnl IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dnl
dnl This file is part of yuck.

AC_DEFUN([AX_CHECK_M4_BUFFERS], [dnl
	AC_MSG_CHECKING([for m4 with sufficient capabilities])

	AC_SUBST([M4])
	probe_M4="${M4:-m4}"
	if ${probe_M4} >/dev/null 2>&1 \
		-Dx='y y y y y y y y y y y y y y y y' \
		-Dy='z z z z z z z z z z z z z z z z' \
                -Dz='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0' <<'EOF'
[define(`foo', x)]
EOF
	then
		## ah well done
		AC_MSG_RESULT([${probe_M4}])
		M4="${probe_M4}"
	else
		## check if a little buffer massage solves the problem
		probe_M4="${M4:-m4} -B16384"
		if ${probe_M4} >/dev/null 2>&1 \
			-Dx='y y y y y y y y y y y y y y y y' \
			-Dy='z z z z z z z z z z z z z z z z' \
			-Dz='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0' <<'EOF'
[define(`foo', x)]
EOF
		then
			## very well then, let's use -B
			AC_MSG_RESULT([${probe_M4}])
			M4="${probe_M4}"
		else
			AC_MSG_WARN([m4 on this machine might suffer from big buffers.])
			M4="${M4:-m4}"
		fi
	fi
])dnl AX_CHECK_M4_BUFFERS

AC_DEFUN([AX_CHECK_YUCK], [dnl
	AC_ARG_WITH([included-yuck], [dnl
AS_HELP_STRING([--with-included-yuck], [
Use included copy of the yuck command line parser generator
instead of the system-wide one.])], [with_included_yuck="${withval}"], [$1])

	if test "${with_included_yuck}" != "yes"; then
		AC_PATH_PROG([YUCK], [yuck])
		AC_ARG_VAR([YUCK], [full path to the yuck tool])
		AC_MSG_CHECKING([for yuck])
		AC_MSG_RESULT([${YUCK}])
	fi
	AM_CONDITIONAL([HAVE_YUCK], [test -n "${YUCK}"])

	AC_REQUIRE([AX_CHECK_M4_BUFFERS])
	if test -n "${YUCK}"; then
		## see what m4 they used back then
		PKG_CHECK_EXISTS([yuck >= 0.1], [dnl
			_PKG_CONFIG([yuck_m4], [variable=yuck_m4], [yuck])
		])
		M4="${pkg_cv_yuck_m4:-m4}"
	fi

	## further requirement is either getline() or fgetln()
	AC_CHECK_FUNCS([getline])
	AC_CHECK_FUNCS([fgetln])
])dnl AX_CHECK_YUCK

AC_DEFUN([AX_YUCK_SCMVER], [dnl
## initially generate version.mk and yuck.version here
## because only GNU make can do this at make time
	pushdef([vfile], [$1])

	AC_MSG_CHECKING([for stipulated version files])
	if test -f "${srcdir}/.version"; then
		## transform reference version
		VERSION=`"${AWK}" -F'-' 'NR == 1 {
PRE = substr([$]1, 1, 1);
VER = substr([$]1, 2);
if (PRE == "v" || PRE == "V") {
	SCM = substr([$]3, 1, 1);
	if (SCM == "g") {
		VER = VER ".git" [$]2 "." substr([$]3, 2);
	}
	if ([$]4) {
		VER = VER "." [$]4;
	}
	print VER;
}
}' "${srcdir}/.version"`
		AC_MSG_RESULT([.version -> ${VERSION}])
	else
		AC_MSG_RESULT([none])
	fi
	## also massage version.mk file
	if test -f "${srcdir}/[]vfile[]"; then
		## make sure it's in the builddir as well
		cp "${srcdir}/[]vfile[]" "[]vfile[]" 2>/dev/null
	elif test -f "${srcdir}/[]vfile[].in"; then
		${M4:-m4} -DYUCK_SCMVER_VERSION="${VERSION}" \
			"${srcdir}/[]vfile[].in" > "[]vfile[]"
	else
		echo "VERSION = ${VERSION}" > "[]vfile[]"
	fi

	popdef([vfile])
])dnl AX_YUCK_SCMVER

dnl yuck.m4 ends here
dateutils-0.3.1/src/000077500000000000000000000000001241477753400143165ustar00rootroot00000000000000dateutils-0.3.1/src/Makefile.am000066400000000000000000000102021241477753400163450ustar00rootroot00000000000000### Makefile.am
include $(top_builddir)/version.mk

AM_CFLAGS = $(EXTRA_CFLAGS)
AM_CPPFLAGS = -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
AM_CPPFLAGS += -DHAVE_VERSION_H
AM_LDFLAGS =

M4 = m4

bin_PROGRAMS =
noinst_PROGRAMS =
noinst_HEADERS =
noinst_LIBRARIES =
BUILT_SOURCES =
CLEANFILES =
GGO_HELPERS =
EXTRA_DIST = $(BUILT_SOURCES) $(GGO_HELPERS)
SUFFIXES =

DT_INCLUDES = -I$(top_srcdir)/lib -I$(top_builddir)/lib
DT_LIBS = $(top_builddir)/lib/libdut.a

noinst_LIBRARIES += libdutio.a
libdutio_a_SOURCES =
libdutio_a_SOURCES += dt-io.c dt-io.h
libdutio_a_SOURCES += dt-io-zone.c dt-io-zone.h
libdutio_a_SOURCES += alist.c alist.h
libdutio_a_SOURCES += dexpr.h
libdutio_a_CPPFLAGS = $(AM_CPPFLAGS)
libdutio_a_CPPFLAGS += $(DT_INCLUDES)
libdutio_a_CPPFLAGS += -DTZMAP_DIR='"$(pkgdatadir)"'
EXTRA_DIST += strpdt-special.gperf
BUILT_SOURCES += strpdt-special.c

bin_PROGRAMS += dseq
dseq_SOURCES = dseq.c dseq.yuck
dseq_CPPFLAGS = $(AM_CPPFLAGS) $(DT_INCLUDES)
dseq_LDFLAGS = $(AM_LDFLAGS)
dseq_LDADD = libdutio.a
dseq_LDADD += $(DT_LIBS)
BUILT_SOURCES += dseq.yucc

if HAVE_STRPTIME
bin_PROGRAMS += strptime
strptime_SOURCES = strptime.c strptime.yuck
strptime_SOURCES += prchunk.c prchunk.h
strptime_CPPFLAGS = $(AM_CPPFLAGS) $(DT_INCLUDES)
strptime_LDFLAGS = $(AM_LDFLAGS)
strptime_LDADD = libdutio.a
strptime_LDADD += $(DT_LIBS)
endif
BUILT_SOURCES += strptime.yucc

bin_PROGRAMS += dconv
dconv_SOURCES = dconv.c dconv.yuck
dconv_SOURCES += prchunk.c prchunk.h
dconv_CPPFLAGS = $(AM_CPPFLAGS) $(DT_INCLUDES)
dconv_LDFLAGS = $(AM_LDFLAGS)
dconv_LDADD = libdutio.a
dconv_LDADD += $(DT_LIBS)
BUILT_SOURCES += dconv.yucc

bin_PROGRAMS += dtest
dtest_SOURCES = dtest.c dtest.yuck
dtest_CPPFLAGS = $(AM_CPPFLAGS) $(DT_INCLUDES)
dtest_LDFLAGS = $(AM_LDFLAGS)
dtest_LDADD = libdutio.a
dtest_LDADD += $(DT_LIBS)
BUILT_SOURCES += dtest.yucc

bin_PROGRAMS += dadd
dadd_SOURCES = dadd.c dadd.yuck
dadd_SOURCES += prchunk.c prchunk.h
dadd_CPPFLAGS = $(AM_CPPFLAGS) $(DT_INCLUDES)
dadd_LDFLAGS = $(AM_LDFLAGS)
dadd_LDADD = libdutio.a
dadd_LDADD += $(DT_LIBS)
BUILT_SOURCES += dadd.yucc

bin_PROGRAMS += ddiff
ddiff_SOURCES = ddiff.c ddiff.yuck
ddiff_SOURCES += prchunk.c prchunk.h
ddiff_CPPFLAGS = $(AM_CPPFLAGS) $(DT_INCLUDES)
ddiff_LDFLAGS = $(AM_LDFLAGS)
ddiff_LDADD = libdutio.a
ddiff_LDADD += $(DT_LIBS)
BUILT_SOURCES += ddiff.yucc

bin_PROGRAMS += dgrep
dgrep_SOURCES = dgrep.c dgrep.yuck
dgrep_SOURCES += prchunk.c prchunk.h
dgrep_CPPFLAGS = $(AM_CPPFLAGS) $(DT_INCLUDES)
dgrep_LDFLAGS = $(AM_LDFLAGS)
dgrep_LDADD = libdutio.a
dgrep_LDADD += $(DT_LIBS)
BUILT_SOURCES += dgrep.yucc

bin_PROGRAMS += dround
dround_SOURCES = dround.c dround.yuck
dround_SOURCES += prchunk.c prchunk.h
dround_CPPFLAGS = $(AM_CPPFLAGS) $(DT_INCLUDES)
dround_LDFLAGS = $(AM_LDFLAGS)
dround_LDADD = libdutio.a
dround_LDADD += $(DT_LIBS)
BUILT_SOURCES += dround.yucc

bin_PROGRAMS += dzone
dzone_SOURCES = dzone.c dzone.yuck
dzone_CPPFLAGS = $(AM_CPPFLAGS) $(DT_INCLUDES)
dzone_LDFLAGS = $(AM_LDFLAGS)
dzone_LDADD = libdutio.a
dzone_LDADD += $(DT_LIBS)
BUILT_SOURCES += dzone.yucc

bin_PROGRAMS += dsort
dsort_SOURCES = dsort.c dsort.yuck
dsort_SOURCES += prchunk.c prchunk.h
dsort_CPPFLAGS = $(AM_CPPFLAGS) $(DT_INCLUDES)
dsort_LDFLAGS = $(AM_LDFLAGS)
dsort_LDADD = libdutio.a
dsort_LDADD += $(DT_LIBS)
BUILT_SOURCES += dsort.yucc

if BUILD_DEXPR
noinst_PROGRAMS += dexpr
dexpr_SOURCES = dexpr.c
dexpr_SOURCES += dexpr-scanner.l
dexpr_SOURCES += dexpr-parser.y
dexpr_CPPFLAGS = $(AM_CPPFLAGS) $(DT_INCLUDES) -DSTANDALONE
dexpr_LDFLAGS = $(AM_LDFLAGS)
dexpr_LDADD = libdutio.a
dexpr_LDADD += $(DT_LIBS)
endif  ## BUILD_DEXPR
BUILT_SOURCES += dexpr-scanner.c dexpr-parser.c dexpr-parser.h


## yuck rule
SUFFIXES += .yuck
SUFFIXES += .yucc
.yuck.yucc:
	$(AM_V_GEN) PATH=$(top_builddir)/build-aux:"$${PATH}" \
		yuck$(EXEEXT) gen -o $@ $<

## gperf rule
SUFFIXES += .gperf
.gperf.c:
	$(AM_V_GEN) $(GPERF) -L ANSI-C $< --output-file $@


## just for parallel builds
dexpr-parser.h: dexpr-parser.c

# 
# Help the developers get nice post-processed source files

## Create preprocessor output (debugging purposes only)
.c.i:
	$(COMPILE) -E -o $@ $<

## Create assembler output (debugging purposes only)
.c.s:
	$(COMPILE) -S -c $(AM_CFLAGS) $<
dateutils-0.3.1/src/alist.c000066400000000000000000000103211241477753400155730ustar00rootroot00000000000000/*** alist.c -- bog standard associative lists
 *
 * Copyright (C) 2010-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/
#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include 
#include "alist.h"
#include "nifty.h"

/* our alist is a simple flat char array with pointers behind every key
 * aligned to void* boundaries. */

static const void**
__assoc(alist_t al, const char *key)
{
	for (const char *ap = al->data, *const ep = ap + al->dend; ap < ep;) {
		const char *kp;
		const void **res = (const void**)al->data;

		/* unrolled strcmp */
		for (kp = key; *ap && *ap == *kp; ap++, kp++);

		/* fast forward to void** boundary */
		res += (ap - al->data) / sizeof(res) + 1U;

		if (*ap == *kp) {
			/* match! invariant: ap == kp == '\0' */
			return res;
		} else if (*ap) {
			/* fast forward in void** increments */
			for (; ((const char*)res)[-1]; res++);
		}
		/* skip over ptr, start again */
		ap = (const char*)++res;
	}
	return NULL;
}

static bool
__fitsp(alist_t al, size_t keylen)
{
	return al->dend + keylen + 2 * sizeof(void**) < al->allz;
}

static void
__chk_resz(alist_t al, size_t keylen)
{
	if (UNLIKELY(!__fitsp(al, keylen))) {
		size_t ol = al->allz;
		al->allz = (al->allz * 2U) ?: 64U;
		al->data = realloc(al->data, al->allz);
		memset(al->data + ol, 0, al->allz - ol);
	}
	return;
}


/* public api */
void
free_alist(alist_t al)
{
	if (LIKELY(al->data != NULL)) {
		free(al->data);
		memset(al, 0, sizeof(*al));
	}
	return;
}

const void*
alist_assoc(alist_t al, const char *key)
{
	const void **res;

	if (UNLIKELY(al->data == NULL)) {
		goto nada;
	} else if ((res = __assoc(al, key)) == NULL) {
		goto nada;
	}
	return *res;
nada:
	return NULL;
}

void
alist_put(alist_t al, const char *key, const void *val)
{
	size_t klen = strlen(key);

	__chk_resz(al, klen);
	memcpy(al->data + al->dend, key, klen);
	/* round up to void** boundary */
	with (const void **data = (const void**)al->data) {
		data += (al->dend + klen) / sizeof(data) + 1U;
		*data++ = val;
		al->dend = (const char*)data - al->data;
	}
	return;
}

void
alist_set(alist_t al, const char *key, const void *val)
{
	const void **ass;

	if ((ass = __assoc(al, key)) != NULL) {
		*ass = val;
		return;
	}
	alist_put(al, key, val);
	return;
}

acons_t
alist_next(alist_t al)
{
	acons_t res;

	if (UNLIKELY((const char*)al->iter >= al->data + al->dend)) {
		al->iter = NULL;
		res = (acons_t){NULL, NULL};
	} else {
		const char *p = al->iter ?: al->data;
		size_t klen = strlen(p);

		with (const void *const *d = (const void*)p) {
			d += klen / sizeof(d) + 1U;
			res.key = p;
			res.val = *d++;
			al->iter = d;
		}
	}
	return res;
}

/* alist.c ends here */
dateutils-0.3.1/src/alist.h000066400000000000000000000050131241477753400156020ustar00rootroot00000000000000/*** alist.h -- bog standard associative lists
 *
 * Copyright (C) 2010-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/
#if !defined INCLUDED_alist_h_
#define INCLUDED_alist_h_

typedef struct alist_s *alist_t;
typedef struct acons_s acons_t;

struct alist_s {
	char *data;
	size_t allz;

	/* private slots */
	size_t dend;
	const void *iter;
};

struct acons_s {
	const char *key;
	const void *val;
};


extern void free_alist(alist_t);

/**
 * Return value associated with KEY in alist, or NULL if none found. */
extern const void *alist_assoc(alist_t, const char *key);

/**
 * Put VAL as value associated with KEY in alist, but don't do a check
 * for duplicates first, i.e. it is assumed that KEY is not present. */
extern void alist_put(alist_t, const char *key, const void *val);

/**
 * Set value associated with KEY in alist to VAL. */
extern void alist_set(alist_t, const char *key, const void *val);

/**
 * Return next alist cons cell. */
extern acons_t alist_next(alist_t);

#endif	/* INCLUDED_alist_h_ */
dateutils-0.3.1/src/dadd.c000066400000000000000000000223701241477753400153620ustar00rootroot00000000000000/*** dadd.c -- perform simple date arithmetic, date plus duration
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include 
#include 

#include "dt-core.h"
#include "dt-io.h"
#include "dt-core-tz-glue.h"
#include "prchunk.h"

const char *prog = "dadd";


static bool
durs_only_d_p(struct dt_dt_s dur[], size_t ndur)
{
	for (size_t i = 0; i < ndur; i++) {
		if (dur[i].t.typ) {
			return false;
		}
	}
	return true;
}

static struct dt_dt_s
dadd_add(struct dt_dt_s d, struct dt_dt_s dur[], size_t ndur)
{
	for (size_t i = 0; i < ndur; i++) {
		d = dt_dtadd(d, dur[i]);
	}
	return d;
}


struct mass_add_clo_s {
	void *pctx;
	const struct grep_atom_soa_s *gra;
	struct __strpdtdur_st_s st;
	struct dt_dt_s rd;
	zif_t fromz;
	zif_t hackz;
	zif_t z;
	const char *ofmt;
	int sed_mode_p;
	int quietp;
};

static int
proc_line(const struct mass_add_clo_s *clo, char *line, size_t llen)
{
	struct dt_dt_s d;
	char *sp = NULL;
	char *ep = NULL;
	int rc = 0;

	do {
		/* check if line matches, */
		d = dt_io_find_strpdt2(line, clo->gra, &sp, &ep, clo->fromz);

		if (!dt_unk_p(d)) {
			if (UNLIKELY(d.fix) && !clo->quietp) {
				rc = 2;
			}
			/* perform addition now */
			d = dadd_add(d, clo->st.durs, clo->st.ndurs);

			if (clo->hackz == NULL && clo->fromz != NULL) {
				/* fixup zone */
				d = dtz_forgetz(d, clo->fromz);
			}

			if (clo->sed_mode_p) {
				__io_write(line, sp - line, stdout);
				dt_io_write(d, clo->ofmt, clo->z, '\0');
				llen -= (ep - line);
				line = ep;
			} else {
				dt_io_write(d, clo->ofmt, clo->z, '\n');
				break;
			}
		} else if (clo->sed_mode_p) {
			line[llen] = '\n';
			__io_write(line, llen + 1, stdout);
			break;
		} else {
			/* obviously unmatched, warn about it in non -q mode */
			if (!clo->quietp) {
				dt_io_warn_strpdt(line);
				rc = 2;
			}
			break;
		}
	} while (1);
	return rc;
}

static int
mass_add_dur(const struct mass_add_clo_s *clo)
{
/* read lines from stdin
 * interpret as dates
 * add to reference duration
 * output */
	size_t lno = 0;
	int rc = 0;

	for (char *line; prchunk_haslinep(clo->pctx); lno++) {
		size_t llen = prchunk_getline(clo->pctx, &line);

		rc |= proc_line(clo, line, llen);
	}
	return rc;
}

static int
mass_add_d(const struct mass_add_clo_s *clo)
{
/* read lines from stdin
 * interpret as durations
 * add to reference date
 * output */
	size_t lno = 0;
	struct dt_dt_s d;
	struct __strpdtdur_st_s st = __strpdtdur_st_initialiser();
	int rc = 0;

	for (char *line; prchunk_haslinep(clo->pctx); lno++) {
		size_t llen;
		int has_dur_p  = 1;

		llen = prchunk_getline(clo->pctx, &line);

		/* check for durations on this line */
		do {
			if (dt_io_strpdtdur(&st, line) < 0) {
				has_dur_p = 0;
			}
		} while (__strpdtdur_more_p(&st));

		/* finish with newline again */
		line[llen] = '\n';

		if (has_dur_p) {
			if (UNLIKELY(clo->rd.fix) && !clo->quietp) {
				rc = 2;
			}
			/* perform addition now */
			d = dadd_add(clo->rd, st.durs, st.ndurs);

			if (clo->hackz == NULL && clo->fromz != NULL) {
				/* fixup zone */
				d = dtz_forgetz(d, clo->fromz);
			}

			/* no sed mode here */
			dt_io_write(d, clo->ofmt, clo->z, '\n');
		} else if (clo->sed_mode_p) {
			__io_write(line, llen + 1, stdout);
		} else if (!clo->quietp) {
			line[llen] = '\0';
			dt_io_warn_strpdt(line);
			rc = 2;
		}
		/* just reset the ndurs slot */
		st.ndurs = 0;
	}
	/* free associated duration resources */
	__strpdtdur_free(&st);
	return rc;
}


#include "dadd.yucc"

int
main(int argc, char *argv[])
{
	yuck_t argi[1U];
	struct dt_dt_s d;
	struct __strpdtdur_st_s st = __strpdtdur_st_initialiser();
	char *inp;
	const char *ofmt;
	char **fmt;
	size_t nfmt;
	int rc = 0;
	bool dt_given_p = false;
	zif_t fromz = NULL;
	zif_t z = NULL;
	zif_t hackz = NULL;

	if (yuck_parse(argi, argc, argv)) {
		rc = 1;
		goto out;
	} else if (argi->nargs == 0) {
		error("Error: DATE or DURATION must be specified\n");
		yuck_auto_help(argi);
		rc = 1;
		goto out;
	}
	/* init and unescape sequences, maybe */
	ofmt = argi->format_arg;
	fmt = argi->input_format_args;
	nfmt = argi->input_format_nargs;
	if (argi->backslash_escapes_flag) {
		dt_io_unescape(argi->format_arg);
		for (size_t i = 0; i < nfmt; i++) {
			dt_io_unescape(fmt[i]);
		}
	}

	/* try and read the from and to time zones */
	if (argi->from_zone_arg) {
		fromz = dt_io_zone(argi->from_zone_arg);
	}
	if (argi->zone_arg) {
		z = dt_io_zone(argi->zone_arg);
	}

	/* check first arg, if it's a date the rest of the arguments are
	 * durations, if not, dates must be read from stdin */
	for (size_t i = 0; i < argi->nargs; i++) {
		inp = argi->args[i];
		do {
			if (dt_io_strpdtdur(&st, inp) < 0) {
				if (UNLIKELY(i == 0)) {
					/* that's ok, must be a date then */
					dt_given_p = true;
				} else {
					serror("Error: \
cannot parse duration string `%s'", st.istr);
					rc = 1;
					goto dur_out;
				}
			}
		} while (__strpdtdur_more_p(&st));
	}
	/* check if there's only d durations */
	hackz = durs_only_d_p(st.durs, st.ndurs) ? NULL : fromz;

	/* sanity checks, decide whether we're a mass date adder
	 * or a mass duration adder, or both, a date and durations are
	 * present on the command line */
	if (dt_given_p) {
		/* date parsing needed postponing as we need to find out
		 * about the durations */
		inp = argi->args[0U];
		if (dt_unk_p(d = dt_io_strpdt(inp, fmt, nfmt, hackz))) {
			error("\
Error: cannot interpret date/time string `%s'", inp);
			rc = 1;
			goto dur_out;
		}
	}

	/* start the actual work */
	if (dt_given_p && st.ndurs) {
		if (!dt_unk_p(d = dadd_add(d, st.durs, st.ndurs))) {
			if (UNLIKELY(d.fix) && !argi->quiet_flag) {
				rc = 2;
			}
			if (hackz == NULL && fromz != NULL) {
				/* fixup zone */
				d = dtz_forgetz(d, fromz);
			}
			dt_io_write(d, ofmt, z, '\n');
		} else {
			rc = 1;
		}

	} else if (st.ndurs) {
		/* read dates from stdin */
		struct grep_atom_s __nstk[16], *needle = __nstk;
		size_t nneedle = countof(__nstk);
		struct grep_atom_soa_s ndlsoa;
		struct mass_add_clo_s clo[1];
		void *pctx;

		/* no threads reading this stream */
		__io_setlocking_bycaller(stdout);

		/* lest we overflow the stack */
		if (nfmt >= nneedle) {
			/* round to the nearest 8-multiple */
			nneedle = (nfmt | 7) + 1;
			needle = calloc(nneedle, sizeof(*needle));
		}
		/* and now build the needle */
		ndlsoa = build_needle(needle, nneedle, fmt, nfmt);

		/* using the prchunk reader now */
		if ((pctx = init_prchunk(STDIN_FILENO)) == NULL) {
			serror("could not open stdin");
			goto ndl_free;
		}

		/* build the clo and then loop */
		clo->pctx = pctx;
		clo->gra = &ndlsoa;
		clo->st = st;
		clo->fromz = fromz;
		clo->hackz = hackz;
		clo->z = z;
		clo->ofmt = ofmt;
		clo->sed_mode_p = argi->sed_mode_flag;
		clo->quietp = argi->quiet_flag;
		while (prchunk_fill(pctx) >= 0) {
			rc |= mass_add_dur(clo);
		}
		/* get rid of resources */
		free_prchunk(pctx);
	ndl_free:
		if (needle != __nstk) {
			free(needle);
		}

	} else {
		/* mass-adding durations to reference date */
		struct mass_add_clo_s clo[1];
		void *pctx;

		/* no threads reading this stream */
		__io_setlocking_bycaller(stdout);

		/* using the prchunk reader now */
		if ((pctx = init_prchunk(STDIN_FILENO)) == NULL) {
			serror("could not open stdin");
			goto dur_out;
		}

		/* build the clo and then loop */
		clo->pctx = pctx;
		clo->rd = d;
		clo->fromz = fromz;
		clo->hackz = hackz;
		clo->z = z;
		clo->ofmt = ofmt;
		clo->sed_mode_p = argi->sed_mode_flag;
		clo->quietp = argi->quiet_flag;
		while (prchunk_fill(pctx) >= 0) {
			rc |= mass_add_d(clo);
		}
		/* get rid of resources */
		free_prchunk(pctx);
	}
dur_out:
	/* free the strpdur status */
	__strpdtdur_free(&st);

	dt_io_clear_zones();

out:
	yuck_free(argi);
	return rc;
}

/* dadd.c ends here */
dateutils-0.3.1/src/dadd.yuck000066400000000000000000000044721241477753400161160ustar00rootroot00000000000000Usage: dadd [OPTION]... [DATE/TIME] [DURATION]

Add DURATION to DATE/TIME and print the result.
If DATE/TIME is omitted but DURATION is given, read a list of DATE/TIMEs from
stdin.
If DURATION is omitted but DATE/TIME is given, read a list of DURATIONs from
stdin.

Durations are specified as nY, nMO, nW, or nD for years, months, weeks, or days
respectively, or nH, nM, nS for hours, minutes, and seconds, where N is a
(possibly negative) number.  The unit symbols can be written lower-case as well
(y, mo, w, d, h, m, s) and the unit symbol `d' can be omitted.

Note that duration addition is not commutative!
  2000-03-30 +1mo +1d -> 2000-05-01
  2000-03-30 +1d +1mo -> 2000-04-30


  -h, --help                 Print help and exit
  -V, --version              Print version and exit
  -q, --quiet                Suppress message about date/time and duration
                             parser errors and fix-ups.
                             The default is to print a warning or the
                             fixed up value and return error code 2.
  -f, --format=STRING        Output format.  This can either be a specifier
                               string (similar to strftime()'s FMT) or the name
                               of a calendar.
  -i, --input-format=STRING...  Input format, can be used multiple times.
                               Each date/time will be passed to the input
                               format parsers in the order they are given, if a
                               date/time can be read successfully with a given
                               input format specifier string, that value will
                               be used.
  -e, --backslash-escapes    Enable interpretation of backslash escapes in the
                               output and input format specifier strings.
  -S, --sed-mode             Copy parts from the input before and after a
                               matching date/time.
                               Note that all occurrences of date/times within a
                               line will be processed.
      --from-zone=ZONE       Interpret dates on stdin or the command line as
                               coming from the time zone ZONE.
  -z, --zone=ZONE            Convert dates printed on stdout to time zone ZONE,
                               default: UTC.
dateutils-0.3.1/src/dconv.c000066400000000000000000000123301241477753400155720ustar00rootroot00000000000000/*** dconv.c -- convert calendrical and time stamp systems
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include 
#include 

#include "dt-core.h"
#include "dt-io.h"
#include "prchunk.h"


const char *prog = "dconv";

struct prln_ctx_s {
	struct grep_atom_soa_s *ndl;
	const char *ofmt;
	zif_t fromz;
	zif_t outz;
	int sed_mode_p;
	int quietp;
};

static int
proc_line(struct prln_ctx_s ctx, char *line, size_t llen)
{
	struct dt_dt_s d;
	char *sp = NULL;
	char *ep = NULL;
	int rc = 0;

	do {
		d = dt_io_find_strpdt2(line, ctx.ndl, &sp, &ep, ctx.fromz);

		/* check if line matches */
		if (!dt_unk_p(d) && ctx.sed_mode_p) {
			__io_write(line, sp - line, stdout);
			dt_io_write(d, ctx.ofmt, ctx.outz, '\0');
			llen -= (ep - line);
			line = ep;
		} else if (!dt_unk_p(d)) {
			if (UNLIKELY(d.fix) && !ctx.quietp) {
				rc = 2;
			}
			dt_io_write(d, ctx.ofmt, ctx.outz, '\n');
			break;
		} else if (ctx.sed_mode_p) {
			line[llen] = '\n';
			__io_write(line, llen + 1, stdout);
			break;
		} else {
			/* obviously unmatched, warn about it in non -q mode */
			if (!ctx.quietp) {
				dt_io_warn_strpdt(line);
				rc = 2;
			}
			break;
		}
	} while (1);
	return rc;
}


#include "dconv.yucc"

int
main(int argc, char *argv[])
{
	yuck_t argi[1U];
	const char *ofmt;
	char **fmt;
	size_t nfmt;
	int rc = 0;
	zif_t fromz = NULL;
	zif_t z = NULL;

	if (yuck_parse(argi, argc, argv)) {
		rc = 1;
		goto out;
	}
	/* init and unescape sequences, maybe */
	ofmt = argi->format_arg;
	fmt = argi->input_format_args;
	nfmt = argi->input_format_nargs;
	if (argi->backslash_escapes_flag) {
		dt_io_unescape(argi->format_arg);
		for (size_t i = 0; i < nfmt; i++) {
			dt_io_unescape(fmt[i]);
		}
	}

	/* try and read the from and to time zones */
	if (argi->from_zone_arg) {
		fromz = dt_io_zone(argi->from_zone_arg);
	}
	if (argi->zone_arg) {
		z = dt_io_zone(argi->zone_arg);
	}
	if (argi->default_arg) {
		struct dt_dt_s dflt = dt_strpdt(argi->default_arg, NULL, NULL);
		dt_set_default(dflt);
	}

	if (argi->nargs) {
		for (size_t i = 0; i < argi->nargs; i++) {
			const char *inp = argi->args[i];
			struct dt_dt_s d = dt_io_strpdt(inp, fmt, nfmt, fromz);

			if (!dt_unk_p(d)) {
				if (UNLIKELY(d.fix) && !argi->quiet_flag) {
					rc = 2;
				}
				dt_io_write(d, ofmt, z, '\n');
			} else if (!argi->quiet_flag) {
				rc = 2;
				dt_io_warn_strpdt(inp);
			}
		}
	} else {
		/* read from stdin */
		size_t lno = 0;
		struct grep_atom_s __nstk[16], *needle = __nstk;
		size_t nneedle = countof(__nstk);
		struct grep_atom_soa_s ndlsoa;
		void *pctx;
		struct prln_ctx_s prln = {
			.ndl = &ndlsoa,
			.ofmt = ofmt,
			.fromz = fromz,
			.outz = z,
			.sed_mode_p = argi->sed_mode_flag,
			.quietp = argi->quiet_flag,
		};

		/* no threads reading this stream */
		__io_setlocking_bycaller(stdout);

		/* lest we overflow the stack */
		if (nfmt >= nneedle) {
			/* round to the nearest 8-multiple */
			nneedle = (nfmt | 7) + 1;
			needle = calloc(nneedle, sizeof(*needle));
		}
		/* and now build the needles */
		ndlsoa = build_needle(needle, nneedle, fmt, nfmt);

		/* using the prchunk reader now */
		if ((pctx = init_prchunk(STDIN_FILENO)) == NULL) {
			serror("Error: could not open stdin");
			goto ndl_free;
		}
		while (prchunk_fill(pctx) >= 0) {
			for (char *line; prchunk_haslinep(pctx); lno++) {
				size_t llen = prchunk_getline(pctx, &line);

				rc |= proc_line(prln, line, llen);
			}
		}
		/* get rid of resources */
		free_prchunk(pctx);
	ndl_free:
		if (needle != __nstk) {
			free(needle);
		}
	}

	dt_io_clear_zones();

out:
	yuck_free(argi);
	return rc;
}

/* dconv.c ends here */
dateutils-0.3.1/src/dconv.yuck000066400000000000000000000046401241477753400163300ustar00rootroot00000000000000Usage: dconv [OPTION]... [DATE/TIME]...

Convert DATE/TIMEs between calendrical systems.
If DATE/TIME is omitted date/times are read from stdin.

DATE/TIME can also be one of the following specials
  - `now'           interpreted as the current (UTC) time stamp
  - `time'          the time part of the current (UTC) time stamp
  - `today'         the current date (according to UTC)
  - `tomo[rrow]'    tomorrow's date (according to UTC)
  - `y[ester]day'   yesterday's date (according to UTC)


  -h, --help                 Print help and exit
  -V, --version              Print version and exit
  -q, --quiet                Suppress message about date/time and duration
                             parser errors and fix-ups.
                             The default is to print a warning or the
                             fixed up value and return error code 2.
  -f, --format=STRING        Output format.  This can either be a specifier
                               string (similar to strftime()'s FMT) or the name
                               of a calendar.
  -i, --input-format=STRING...  Input format, can be used multiple times.
                               Each date/time will be passed to the input
                               format parsers in the order they are given, if a
                               date/time can be read successfully with a given
                               input format specifier string, that value will
                               be used.
      --default=DT           For underspecified input use DT as a fallback to
                               fill in missing fields.  Must be a date/time in
                               ISO8601 format.  If omitted the default value is
                               the current date/time.
  -e, --backslash-escapes    Enable interpretation of backslash escapes in the
                               output and input format specifier strings.
  -S, --sed-mode             Copy parts from the input before and after a
                               matching date/time.
                               Note that all occurrences of date/times within a
                               line will be processed.
      --from-zone=ZONE       Interpret dates on stdin or the command line as
                               coming from the time zone ZONE.
  -z, --zone=ZONE            Convert dates printed on stdout to time zone ZONE,
                               default: UTC.
dateutils-0.3.1/src/ddiff.c000066400000000000000000000406471241477753400155510ustar00rootroot00000000000000/*** ddiff.c -- perform simple date arithmetic, date minus date
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include 
#include 

#include "date-core-private.h"
#include "dt-core-private.h"
#include "dt-io.h"
#include "prchunk.h"

#if !defined UNUSED
# define UNUSED(_x)	__attribute__((unused)) _x
#endif	/* !UNUSED */

typedef union {
	unsigned int flags;
	struct {
		unsigned int has_year:1;
		unsigned int has_mon:1;
		unsigned int has_week:1;
		unsigned int has_day:1;
		unsigned int has_biz:1;

		unsigned int has_hour:1;
		unsigned int has_min:1;
		unsigned int has_sec:1;
		unsigned int has_nano:1;

		unsigned int has_tai:1;
	};
} durfmt_t;

const char *prog = "ddiff";


static durfmt_t
determine_durfmt(const char *fmt)
{
	durfmt_t res = {0};
	dt_dtyp_t special;

	if (fmt == NULL) {
		/* decide later on */
		;
	} else if (UNLIKELY((special = __trans_dfmt_special(fmt)) != DT_DUNK)) {
		switch (special) {
		default:
		case DT_DUNK:
			break;
		case DT_YMD:
			res.has_year = 1;
			res.has_mon = 1;
			res.has_day = 1;
			break;
		case DT_YMCW:
			res.has_year = 1;
			res.has_mon = 1;
			res.has_week = 1;
			res.has_day = 1;
			break;
		case DT_BIZDA:
			res.has_year = 1;
			res.has_mon = 1;
			res.has_day = 1;
			res.has_biz = 1;
			break;
		case DT_BIZSI:
			res.has_day = 1;
			res.has_biz = 1;
			break;
		case DT_YWD:
			res.has_year = 1;
			res.has_week = 1;
			res.has_day = 1;
			break;
		case DT_YD:
			res.has_year = 1;
			res.has_day = 1;
			break;
		}

		/* all special types have %0H:%0M:%0S */
		res.has_hour = 1;
		res.has_min = 1;
		res.has_sec = 1;
	} else {
		/* go through the fmt specs */
		for (const char *fp = fmt; *fp;) {
			const char *fp_sav = fp;
			struct dt_spec_s spec = __tok_spec(fp_sav, &fp);

			switch (spec.spfl) {
			case DT_SPFL_UNK:
			default:
				/* nothing changes */
				break;
			case DT_SPFL_N_YEAR:
				res.has_year = 1;
				break;
			case DT_SPFL_N_MON:
			case DT_SPFL_S_MON:
				res.has_mon = 1;
				break;
			case DT_SPFL_N_DCNT_MON:
				if (spec.bizda) {
					res.has_biz = 1;
				}
			case DT_SPFL_N_DSTD:
			case DT_SPFL_N_DCNT_YEAR:
				res.has_day = 1;
				break;
			case DT_SPFL_N_WCNT_MON:
			case DT_SPFL_N_WCNT_YEAR:
			case DT_SPFL_N_DCNT_WEEK:
			case DT_SPFL_S_WDAY:
				res.has_week = 1;
				break;

			case DT_SPFL_N_TSTD:
			case DT_SPFL_N_SEC:
				if (spec.tai) {
					res.has_tai = 1;
				}
				res.has_sec = 1;
				break;
			case DT_SPFL_N_HOUR:
				res.has_hour = 1;
				break;
			case DT_SPFL_N_MIN:
				res.has_min = 1;
				break;
			case DT_SPFL_N_NANO:
				res.has_nano = 1;
				break;
			}
		}
	}
	return res;
}

static dt_dttyp_t
determine_durtype(struct dt_dt_s d1, struct dt_dt_s d2, durfmt_t f)
{
	/* the type-multiplication table looks like:
	 *
	 * -   D   T   DT
	 * D   d   x   d
	 * T   x   t   x
	 * DT  d   x   s
	 *
	 * where d means a ddur type, t a tdur type and s is DT_SEXY */

	if (UNLIKELY(dt_sandwich_only_t_p(d1) && dt_sandwich_only_t_p(d2))) {
		/* time only duration */
		;
	} else if (dt_sandwich_only_t_p(d1) || dt_sandwich_only_t_p(d2)) {
		/* isn't defined */
		return (dt_dttyp_t)DT_UNK;
	} else if (f.has_week && f.has_mon) {
		return (dt_dttyp_t)DT_YMCW;
	} else if (f.has_week && f.has_year) {
		return (dt_dttyp_t)DT_YWD;
	} else if (f.has_mon) {
		return (dt_dttyp_t)DT_YMD;
	} else if (f.has_year && f.has_day) {
		return (dt_dttyp_t)DT_YD;
	} else if (f.has_day && f.has_biz) {
		return (dt_dttyp_t)DT_BIZSI;
	} else if (f.has_year) {
		return (dt_dttyp_t)DT_MD;
	} else if (dt_sandwich_only_d_p(d1) || dt_sandwich_only_d_p(d2)) {
		/* default date-only type */
		return (dt_dttyp_t)DT_DAISY;
	} else if (UNLIKELY(f.has_tai)) {
		/* we has tais */
		return (dt_dttyp_t)DT_SEXYTAI;
	}
	return (dt_dttyp_t)DT_SEXY;
}


static size_t
ltostr(char *restrict buf, size_t bsz, long int v,
       int range, unsigned int pad)
{
#define C(x)	(char)((x) + '0')
	char *restrict bp = buf;
	const char *const ep = buf + bsz;
	bool negp;

	if (UNLIKELY((negp = v < 0))) {
		v = -v;
	} else if (!v) {
		*bp++ = C(0U);
		range--;
	}
	/* write the mantissa right to left */
	for (; v && bp < ep; range--) {
		register unsigned int x = v % 10U;

		v /= 10U;
		*bp++ = C(x);
	}
	/* fill up with padding */
	if (UNLIKELY(pad)) {
		static const char pads[] = " 0";
		const char p = pads[2U - pad];

		while (range-- > 0) {
			*bp++ = p;
		}
	}
	/* write the sign */
	if (UNLIKELY(negp)) {
		*bp++ = '-';
	}

	/* reverse the string */
	for (char *ip = buf, *jp = bp - 1; ip < jp; ip++, jp--) {
		register char tmp = *ip;
		*ip = *jp;
		*jp = tmp;
	}
#undef C
	return bp - buf;
}

static inline void
dt_io_warn_dur(const char *d1, const char *d2)
{
	error("\
duration between `%s' and `%s' is not defined", d1, d2);
	return;
}

static long int
__strf_tot_secs(struct dt_dt_s dur)
{
	long int res;

	if (dur.typ == DT_SEXY) {
		res = dur.sexydur;
	} else if (dur.typ == DT_SEXYTAI) {
		res = dur.soft;
	} else {
		/* otherwise */
		res = dur.t.sdur;
	}
	return res;
}

static long int
__strf_tot_corr(struct dt_dt_s dur)
{
	if (dur.typ == DT_SEXYTAI) {
		return dur.corr;
	}
	/* otherwise no corrections */
	return 0;
}

static int
__strf_tot_days(struct dt_dt_s dur)
{
/* DUR expressed solely as the number of days */
	int d = 0;

	switch (dur.d.typ) {
	case DT_DAISY:
		d = dur.d.daisydur;
		break;
	case DT_BIZSI:
		d = dur.d.bizsidur;
		break;
	case DT_BIZDA:
		d = dur.d.bizda.bd;
		break;
	case DT_YMD:
		d = dur.d.ymd.d;
		break;
	case DT_YD:
		d = dur.d.yd.d;
		break;
	case DT_YMCW:
		d = dur.d.ymcw.w + dur.d.ymcw.c * (int)GREG_DAYS_P_WEEK;;
		break;
	case DT_YWD:
		d = dur.d.ywd.w + dur.d.ywd.c * (int)GREG_DAYS_P_WEEK;
		break;
	case DT_MD:
		d = dur.d.md.d;
		break;
	default:
		break;
	}
	return d;
}

static int
__strf_tot_mon(struct dt_dt_s dur)
{
/* DUR expressed as month and days */
	int m = 0;

	switch (dur.d.typ) {
	case DT_BIZDA:
		m = dur.d.bizda.m + dur.d.bizda.y * (int)GREG_MONTHS_P_YEAR;
		break;
	case DT_YMD:
		m = dur.d.ymd.m + dur.d.ymd.y * (int)GREG_MONTHS_P_YEAR;
		break;
	case DT_MD:
		m = dur.d.md.m;
		break;
	case DT_YMCW:
		m = dur.d.ymcw.m + dur.d.ymcw.y * (int)GREG_MONTHS_P_YEAR;
		break;
	case DT_YD:
		m = dur.d.yd.y * (int)GREG_MONTHS_P_YEAR;
		break;
	case DT_YWD:
		m = dur.d.ywd.y * (int)GREG_MONTHS_P_YEAR;
		break;
	default:
		break;
	}
	return m;
}

static int
__strf_ym_mon(struct dt_dt_s dur)
{
	return __strf_tot_mon(dur) % (int)GREG_MONTHS_P_YEAR;
}

static int
__strf_tot_years(struct dt_dt_s dur)
{
	return __strf_tot_mon(dur) / (int)GREG_MONTHS_P_YEAR;
}

static struct precalc_s {
	int Y;
	int m;
	int w;
	int d;
	int db;

	long int H;
	long int M;
	long int S;
	long int N;

	long int rS;
} precalc(durfmt_t f, struct dt_dt_s dur)
{
#define MINS_PER_DAY	(MINS_PER_HOUR * HOURS_PER_DAY)
#define SECS_PER_WEEK	(SECS_PER_DAY * GREG_DAYS_P_WEEK)
#define MINS_PER_WEEK	(MINS_PER_DAY * GREG_DAYS_P_WEEK)
#define HOURS_PER_WEEK	(HOURS_PER_DAY * GREG_DAYS_P_WEEK)
	struct precalc_s res = {0};

	/* date specs */
	if (f.has_year) {
		/* just years */
		res.Y = __strf_tot_years(dur);
	}
	if (f.has_year && f.has_mon) {
		/* years and months */
		res.m = __strf_ym_mon(dur);
	} else if (f.has_mon) {
		/* just months */
		res.m = __strf_tot_mon(dur);
	}
	if (f.has_day || f.has_week) {
		res.d = __strf_tot_days(dur);
		if (f.has_week) {
			/* week shadows days in the hierarchy */
			res.w = res.d / (int)GREG_DAYS_P_WEEK;
			res.d %= (int)GREG_DAYS_P_WEEK;
		}
	}

	/* time specs */
	if (f.has_sec || f.has_min || f.has_hour) {
		res.S = __strf_tot_secs(dur);

		/* carry from the date specs */
		res.S += res.w * (long int)SECS_PER_WEEK;
		res.S += res.d * (long int)SECS_PER_DAY;

		if (f.has_week) {
			res.w = res.S / (long int)SECS_PER_WEEK;
			res.S %= (long int)SECS_PER_WEEK;
		}
		if (f.has_day) {
			res.d = res.S / (long int)SECS_PER_DAY;
			res.S %= (long int)SECS_PER_DAY;
		}
		if (f.has_hour) {
			res.H = res.S / (long int)SECS_PER_HOUR;
			res.S %= (long int)SECS_PER_HOUR;
		}
		if (f.has_min) {
			/* minutes and seconds */
			res.M = res.S / (long int)SECS_PER_MIN;
			res.S %= (long int)SECS_PER_MIN;
		}

		/* just in case the duration iss negative jump through all
		 * the hoops again, backwards */
		if (res.w < 0 || res.d < 0 ||
		    res.H < 0 || res.M < 0 || res.S < 0) {
			if (0) {
			fixup_d:
				res.d = -res.d;
			fixup_H:
				res.H = -res.H;
			fixup_M:
				res.M = -res.M;
			fixup_S:
				res.S = -res.S;
			} else if (f.has_week) {
				goto fixup_d;
			} else if (f.has_day) {
				goto fixup_H;
			} else if (f.has_hour) {
				goto fixup_M;
			} else if (f.has_min) {
				goto fixup_S;
			}
		}
	}
	return res;
}

static size_t
__strfdtdur(
	char *restrict buf, size_t bsz, const char *fmt,
	struct dt_dt_s dur, durfmt_t f)
{
/* like strfdtdur() but do some calculations based on F on the way there */
	static const char sexy_dflt_dur[] = "%0T";
	static const char ddur_dflt_dur[] = "%d";
	struct precalc_s pre;
	const char *fp;
	char *bp;

	if (UNLIKELY(buf == NULL || bsz == 0)) {
		bp = buf;
		goto out;
	}

	/* translate high-level format names */
	if (dur.typ == DT_SEXY) {
		if (fmt == NULL) {
			fmt = sexy_dflt_dur;
			f.has_sec = 1U;
		}
	} else if (dur.typ == DT_SEXYTAI) {
		if (fmt == NULL) {
			fmt = sexy_dflt_dur;
			f.has_sec = 1U;
		}
	} else if (dt_sandwich_p(dur)) {
		if (fmt == NULL) {
			fmt = sexy_dflt_dur;
			f.has_sec = 1U;
		} else {
			__trans_dtdurfmt(&fmt);
		}
	} else if (dt_sandwich_only_d_p(dur)) {
		if (fmt == NULL) {
			fmt = ddur_dflt_dur;
			f.has_day = 1U;
		} else {
			__trans_ddurfmt(&fmt);
			f.has_day = 1U;
		}
	} else if (dt_sandwich_only_t_p(dur)) {
		if (fmt == NULL) {
			fmt = sexy_dflt_dur;
			f.has_sec = 1U;
		}
	} else {
		bp = buf;
		goto out;
	}

	/* precompute */
	pre = precalc(f, dur);

	/* assign and go */
	bp = buf;
	fp = fmt;
	if (dur.neg) {
		*bp++ = '-';
	}
	for (char *const eo = buf + bsz; *fp && bp < eo;) {
		const char *fp_sav = fp;
		struct dt_spec_s spec = __tok_spec(fp_sav, &fp);

		if (spec.spfl == DT_SPFL_UNK) {
			/* must be literal then */
			*bp++ = *fp_sav;
		} else if (UNLIKELY(spec.rom)) {
			continue;
		}
		/* otherwise switch over spec.spfl */
		switch (spec.spfl) {
		case DT_SPFL_LIT_PERCENT:
			/* literal % */
			*bp++ = '%';
			break;
		case DT_SPFL_LIT_TAB:
			/* literal tab */
			*bp++ = '\t';
			break;
		case DT_SPFL_LIT_NL:
			/* literal \n */
			*bp++ = '\n';
			break;

		case DT_SPFL_N_DSTD:
			bp += ltostr(bp, eo - bp, pre.d, -1, DT_SPPAD_NONE);
			*bp++ = 'd';
			goto bizda_suffix;

		case DT_SPFL_N_DCNT_MON: {
			int rng = 2;

			if (!f.has_mon && !f.has_week && f.has_year) {
				rng++;
			}
			bp += ltostr(bp, eo - bp, pre.d, rng, spec.pad);
		}
		bizda_suffix:
			if (spec.bizda) {
				/* don't print the b after an ordinal */
				switch (__get_bizda_param(dur.d).ab) {
				case BIZDA_AFTER:
					*bp++ = 'b';
					break;
				case BIZDA_BEFORE:
					*bp++ = 'B';
					break;
				}
			}
			break;

		case DT_SPFL_N_WCNT_MON:
		case DT_SPFL_N_DCNT_WEEK:
			bp += ltostr(bp, eo - bp, pre.w, 2, spec.pad);
			break;

		case DT_SPFL_N_MON:
			bp += ltostr(bp, eo - bp, pre.m, 2, spec.pad);
			break;

		case DT_SPFL_N_YEAR:
			bp += ltostr(bp, eo - bp, pre.Y, -1, DT_SPPAD_NONE);
			break;

			/* time specs */
		case DT_SPFL_N_TSTD:
			if (UNLIKELY(spec.tai)) {
				pre.S += __strf_tot_corr(dur);
			}
			bp += ltostr(bp, eo - bp, pre.S, -1, DT_SPPAD_NONE);
			*bp++ = 's';
			break;

		case DT_SPFL_N_SEC:
			if (UNLIKELY(spec.tai)) {
				pre.S += __strf_tot_corr(dur);
			}

			bp += ltostr(bp, eo - bp, pre.S, 2, spec.pad);
			break;

		case DT_SPFL_N_MIN:
			bp += ltostr(bp, eo - bp, pre.M, 2, spec.pad);
			break;

		case DT_SPFL_N_HOUR:
			bp += ltostr(bp, eo - bp, pre.H, 2, spec.pad);
			break;

		default:
			break;
		}
	}
out:
	if (bp < buf + bsz) {
		*bp = '\0';
	}
	return bp - buf;
}

static int
ddiff_prnt(struct dt_dt_s dur, const char *fmt, durfmt_t f)
{
/* this is mainly a better dt_strfdtdur() */
	char buf[256];
	size_t res = __strfdtdur(buf, sizeof(buf), fmt, dur, f);

	if (res > 0 && buf[res - 1] != '\n') {
		/* auto-newline */
		buf[res++] = '\n';
	}
	if (res > 0) {
		__io_write(buf, res, stdout);
	}
	return (res > 0) - 1;
}


#include "ddiff.yucc"

int
main(int argc, char *argv[])
{
	yuck_t argi[1U];
	struct dt_dt_s d;
	const char *ofmt;
	const char *refinp;
	char **fmt;
	size_t nfmt;
	int rc = 0;
	durfmt_t dfmt;
	dt_dttyp_t dtyp;
	zif_t fromz = NULL;

	if (yuck_parse(argi, argc, argv)) {
		rc = 1;
		goto out;
	}
	/* unescape sequences, maybe */
	if (argi->backslash_escapes_flag) {
		dt_io_unescape(argi->format_arg);
	}

	/* try and read the from and to time zones */
	if (argi->from_zone_arg) {
		fromz = dt_io_zone(argi->from_zone_arg);
	}

	ofmt = argi->format_arg;
	fmt = argi->input_format_args;
	nfmt = argi->input_format_nargs;

	if (argi->nargs == 0 ||
	    (refinp = argi->args[0U],
	     dt_unk_p(d = dt_io_strpdt(refinp, fmt, nfmt, fromz)) &&
	     dt_unk_p(d = dt_io_strpdt(refinp, NULL, 0U, fromz)))) {
		error("Error: reference DATE must be specified\n");
		yuck_auto_help(argi);
		rc = 1;
		goto out;
	} else if (UNLIKELY(d.fix) && !argi->quiet_flag) {
		rc = 2;
	}

	/* try and guess the diff tgttype most suitable for user's FMT */
	dfmt = determine_durfmt(ofmt);

	if (argi->nargs > 1) {
		for (size_t i = 1; i < argi->nargs; i++) {
			struct dt_dt_s d2;
			struct dt_dt_s dur;
			const char *inp = argi->args[i];

			d2 = dt_io_strpdt(inp, fmt, nfmt, fromz);
			if (dt_unk_p(d2)) {
				if (!argi->quiet_flag) {
					dt_io_warn_strpdt(inp);
					rc = 2;
				}
				continue;
			} else if (UNLIKELY(d2.fix) && !argi->quiet_flag) {
				rc = 2;
			}
			/* guess the diff type */
			if ((dtyp = determine_durtype(d, d2, dfmt)) == DT_UNK) {
				if (!argi->quiet_flag) {
				        dt_io_warn_dur(refinp, inp);
					rc = 2;
				}
				continue;
			}
			/* subtraction and print */
			dur = dt_dtdiff(dtyp, d, d2);
			ddiff_prnt(dur, ofmt, dfmt);
		}
	} else {
		/* read from stdin */
		size_t lno = 0;
		void *pctx;

		/* no threads reading this stream */
		__io_setlocking_bycaller(stdout);

		/* using the prchunk reader now */
		if ((pctx = init_prchunk(STDIN_FILENO)) == NULL) {
			serror("Error: could not open stdin");
			goto out;
		}
		while (prchunk_fill(pctx) >= 0) {
			for (char *line; prchunk_haslinep(pctx); lno++) {
				struct dt_dt_s d2;
				struct dt_dt_s dur;

				(void)prchunk_getline(pctx, &line);
				d2 = dt_io_strpdt(line, fmt, nfmt, fromz);

				if (dt_unk_p(d2)) {
					if (!argi->quiet_flag) {
						dt_io_warn_strpdt(line);
						rc = 2;
					}
					continue;
				} else if (UNLIKELY(d2.fix) &&
					   !argi->quiet_flag) {
					rc = 2;
				}
				/* guess the diff type */
				dtyp = determine_durtype(d, d2, dfmt);
				if (dtyp == DT_UNK) {
					if (!argi->quiet_flag) {
						dt_io_warn_dur(refinp, line);
						rc = 2;
					}
					continue;
				}
				/* perform subtraction now */
				dur = dt_dtdiff(dtyp, d, d2);
				ddiff_prnt(dur, ofmt, dfmt);
			}
		}
		/* get rid of resources */
		free_prchunk(pctx);
	}

	dt_io_clear_zones();

out:
	yuck_free(argi);
	return rc;
}

/* ddiff.c ends here */
dateutils-0.3.1/src/ddiff.yuck000066400000000000000000000041621241477753400162720ustar00rootroot00000000000000Usage: ddiff [OPTION]... DATE/TIME [DATE/TIME]...

Compute duration from DATE/TIME (the reference date/time) to the other
DATE/TIMEs given and print the result as duration.
If the other DATE/TIMEs are omitted read them from stdin.

DATE/TIME can also be one of the following specials
  - `now'           interpreted as the current (UTC) time stamp
  - `time'          the time part of the current (UTC) time stamp
  - `today'         the current date (according to UTC)
  - `tomo[rrow]'    tomorrow's date (according to UTC)
  - `y[ester]day'   yesterday's date (according to UTC)

Note: The output format of durations (specified via -f) takes all format
specifiers into account, i.e. specifying %M and %S for example prints the
duration in minutes and seconds, whereas specifying %S only prints the duration
in seconds.

See section `The refinement rule' in ddiff(1).

  -h, --help                 Print help and exit
  -V, --version              Print version and exit
  -q, --quiet                Suppress message about date/time and duration
                             parser errors and fix-ups.
                             The default is to print a warning or the
                             fixed up value and return error code 2.
  -f, --format=STRING        Output format.  This can either be a specifier
                               string (similar to strftime()'s FMT) or the name
                               of a calendar.
  -i, --input-format=STRING...  Input format, can be used multiple times.
                               Each date/time will be passed to the input
                               format parsers in the order they are given, if a
                               date/time can be read successfully with a given
                               input format specifier string, that value will
                               be used.
  -e, --backslash-escapes    Enable interpretation of backslash escapes in the
                               output and input format specifier strings.
      --from-zone=ZONE       Interpret dates on stdin or the command line as
                               coming from the time zone ZONE.

dateutils-0.3.1/src/dexpr-parser.y000066400000000000000000000133061241477753400171270ustar00rootroot00000000000000/*** dexpr-parser.y -- parsing date expressions -*- c -*-
 *
 * Copyright (C) 2002-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/

%defines
%output="y.tab.c"
%pure-parser
%parse-param{dexpr_t *cur}

%{
#include 
#include 
#include 
#include "token.h"
#include "date-core-strpf.h"
#include "dexpr.h"

extern int yylex(YYSTYPE *yylval_param);
extern int yyerror(dexpr_t *cur __attribute__((unused)), const char *errmsg);
extern char *yytext;

/* grrrrr, bug in bison */
extern int yyparse();

#define YYENABLE_NLS		0
#define YYLTYPE_IS_TRIVIAL	1
#define YYSTACK_USE_ALLOCA	1

int
yyerror(dexpr_t *cur __attribute__((unused)), const char *errmsg)
{
	fputs("dexpr-parser: ", stderr);
	fputs(errmsg, stderr);
	if (errno) {
		fputc(':', stderr);
		fputc(' ', stderr);
		fputs(strerror(errno), stderr);
	}
	fputc('\n', stderr);
	return -1;
}

/* static stuff */
static struct dexkv_s ckv[1];

static char *const *ckv_fmt = NULL;
static size_t ckv_nfmt = 0;
%}

%union {
	dexpr_t dex;
	char *sval;
}

%expect 0

%start root

%token TOK_EQ
%token TOK_NE
%token TOK_LT
%token TOK_LE
%token TOK_GT
%token TOK_GE

%token TOK_SPEC
%token TOK_STRING
%token TOK_DATETIME
%token TOK_INT

%token TOK_OR
%token TOK_AND
%token TOK_NOT

%token TOK_LPAREN
%token TOK_RPAREN

%left TOK_OR
%left TOK_AND
%left TOK_NOT

%%

root:
	stmt {
		*cur = $$;
		YYACCEPT;
	}

stmt
	: {
		memset(ckv, 0, sizeof(*ckv));
	} exp {
		$$ = calloc(1, sizeof(struct dexpr_s));
		$$->type = DEX_VAL;
		$$->kv[0] = *ckv;
	}
	| stmt TOK_OR stmt {
		$$ = calloc(1, sizeof(struct dexpr_s));
		$$->type = DEX_DISJ;
		$$->left = $1;
		$$->right = $3;
	}
	| stmt TOK_AND stmt {
		$$ = calloc(1, sizeof(struct dexpr_s));
		$$->type = DEX_CONJ;
		$$->left = $1;
		$$->right = $3;
	}
	| TOK_NOT stmt {
		($$ = $2)->nega = 1;
	}
	| TOK_LPAREN stmt TOK_RPAREN {
		$$ = $2;
	}
	;

exp
	: rhs
	| spec TOK_LT { ckv->op = OP_LT; } rhs
	| spec TOK_GT { ckv->op = OP_GT; } rhs
	| spec TOK_LE { ckv->op = OP_LE; } rhs
	| spec TOK_GE { ckv->op = OP_GE; } rhs
	| spec TOK_EQ { ckv->op = OP_EQ; } rhs
	| spec TOK_NE { ckv->op = OP_NE; } rhs
	;

spec
	:
	| TOK_SPEC {
		struct dt_spec_s sp = __tok_spec($1, NULL);
		ckv->sp = sp;
	}
	;

rhs
	: TOK_DATETIME {
		ckv->d = dt_io_strpdt($1, ckv_fmt, ckv_nfmt, NULL);
		if (ckv->d.typ == DT_UNK) {
			/* one more try */
			ckv->d = dt_strpdt($1, NULL, NULL);
		}
		ckv->sp.spfl = DT_SPFL_N_STD;
	}
	| TOK_STRING {
		switch (ckv->sp.spfl) {
		case DT_SPFL_N_YEAR:
		case DT_SPFL_N_MON:
		case DT_SPFL_N_DCNT_WEEK:
		case DT_SPFL_N_DCNT_MON:
		case DT_SPFL_N_DCNT_YEAR:
		case DT_SPFL_N_WCNT_MON:
		case DT_SPFL_N_WCNT_YEAR:
			ckv->s = strtol($1, NULL, 10);
			break;
		case DT_SPFL_S_WDAY:
			switch (ckv->sp.abbr) {
			case DT_SPMOD_NORM:
				ckv->s = strtoarri(
					$1, NULL,
					dut_abbr_wday, dut_nabbr_wday);
				break;
			case DT_SPMOD_LONG:
				ckv->s = strtoarri(
					$1, NULL,
					dut_long_wday, dut_nlong_wday);
				break;
			case DT_SPMOD_ABBR: {
				const char *pos;
				if ((pos = strchr(
					     dut_abab_wday, *$1)) != NULL) {
					ckv->s = pos - dut_abab_wday;
					break;
				}
			}
			case DT_SPMOD_ILL:
			default:
				ckv->s = -1;
				break;
			}
			break;
		case DT_SPFL_S_MON:
			switch (ckv->sp.abbr) {
			case DT_SPMOD_NORM:
				ckv->s = strtoarri(
					$1, NULL,
					dut_abbr_mon, dut_nabbr_mon);
				break;
			case DT_SPMOD_LONG:
				ckv->s = strtoarri(
					$1, NULL,
					dut_long_mon, dut_nlong_mon);
				break;
			case DT_SPMOD_ABBR: {
				const char *pos;
				if ((pos = strchr(
					     dut_abab_mon, *$1)) != NULL) {
					ckv->s = pos - dut_abab_mon;
					break;
				}
			}
			case DT_SPMOD_ILL:
			default:
				ckv->s = -1;
				break;
			}
			break;
		default:
			break;
		}
	}
	| TOK_INT {
		switch (ckv->sp.spfl) {
		case DT_SPFL_N_YEAR:
		case DT_SPFL_N_MON:
		case DT_SPFL_N_DCNT_WEEK:
		case DT_SPFL_N_DCNT_MON:
		case DT_SPFL_N_DCNT_YEAR:
		case DT_SPFL_N_WCNT_MON:
		case DT_SPFL_N_WCNT_YEAR:
			ckv->s = strtol($1, NULL, 10);
			break;
		default:
			/* the rest can hardly have ints as inputs */
			YYERROR;
		}
	}
	;

%%

/* dexpr-parser.y ends here */
dateutils-0.3.1/src/dexpr-scanner.l000066400000000000000000000071571241477753400172560ustar00rootroot00000000000000/*** dexpr.l -- date/time expressions for dateutils -*- C -*-
 *
 * Copyright (C) 2002-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/

%{
#include "dexpr.h"
#include "dexpr-parser.h"

/* grrrrr, bug in bison */
extern int yyparse();

/* turn off tedious warnings */
#if defined __INTEL_COMPILER
# pragma warning (disable:593)
# pragma warning (disable:869)
# pragma warning (disable:1419)
# pragma warning (disable:2259)
#elif defined __GNUC__
# pragma GCC diagnostic ignored "-Wswitch-default"
# pragma GCC diagnostic ignored "-Wsign-compare"
# pragma GCC diagnostic ignored "-Wunused-parameter"
#endif	/* __GNUC__ || __INTEL_COMPILER */
%}

%option noyywrap
%option nounput
%option noinput
%option warn
%option bison-bridge
%option pointer
%option nodebug

%{
#define RETURN_TOKEN(_x)			\
	do {					\
		return _x;			\
	} while (0)
%}

string	\"(\\.|[^\\\"])*\"|'(\\.|[^\\\'])*'
/* only canonical dates are allowed */
int	[0-9]+

%%
"="=?	{ RETURN_TOKEN(TOK_EQ); }
"!="	{ RETURN_TOKEN(TOK_NE); }
"<"	{ RETURN_TOKEN(TOK_LT); }
"<="	{ RETURN_TOKEN(TOK_LE); }
">"	{ RETURN_TOKEN(TOK_GT); }
">="	{ RETURN_TOKEN(TOK_GE); }

"||"	{ RETURN_TOKEN(TOK_OR); }
"&&"	{ RETURN_TOKEN(TOK_AND); }
"!"	{ RETURN_TOKEN(TOK_NOT); }

"("	{ RETURN_TOKEN(TOK_LPAREN); }
")"	{ RETURN_TOKEN(TOK_RPAREN); }

"%"[_a-zA-Z]*	{
	yylval->sval = yytext;
	RETURN_TOKEN(TOK_SPEC);
}

{string}	{
	/* strip quotes */
	yytext[yyleng - 1] = '\0';
	yylval->sval = yytext + 1;
	RETURN_TOKEN(TOK_STRING);
}

{int}	{
	yylval->sval = yytext;
	RETURN_TOKEN(TOK_INT);
}

[^\v\n\f()!&|<>=]*	{
	/* return for parsing with our strpdt reader */
	yylval->sval = yytext;
	RETURN_TOKEN(TOK_DATETIME);
}

[ \t\v\n\f]	{ /* ignore whitespace */ }
.	{ /* ignore */ }

%%

int
dexpr_parse(dexpr_t *root, const char *s, size_t l)
{
	YY_BUFFER_STATE buf;
	char *scan;
	int res;

	/* hack to avoid string dup'ing, we assume, that l can take
	 * at least 2 more bytes */
	
	scan = malloc(l + 2);
	memcpy(scan, s, l);
	scan[l++] = '\0';
	scan[l++] = '\0';
	buf = yy_scan_buffer(scan, l);

	/* parse them */
	res = yyparse(root);
	yy_delete_buffer(buf);
	return (res == 0) - 1;
}

/* dexpr.l ends here */
dateutils-0.3.1/src/dexpr.c000066400000000000000000000300311241477753400156010ustar00rootroot00000000000000#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include 
#include "strops.h"
#include "dexpr.h"
#include "dexpr-parser.h"

#if !defined STANDALONE
# if defined __INTEL_COMPILER
#  pragma warning (disable:2259)
# endif	/* __INTEL_COMPILER */
# include "dexpr-parser.c"
# if defined __INTEL_COMPILER
#  pragma warning (default:2259)
# endif	/* __INTEL_COMPILER */

# if defined __INTEL_COMPILER
#  pragma warning (disable:2557)
# endif	/* __INTEL_COMPILER */
# include "dexpr-scanner.c"
# if defined __INTEL_COMPILER
#  pragma warning (default:2557)
# endif	/* __INTEL_COMPILER */
#endif	/* !STANDALONE */

static void
free_dexpr(dexpr_t root)
{
/* recursive free :( */
	switch (root->type) {
	case DEX_CONJ:
	case DEX_DISJ:
		if (root->left != NULL) {
			free_dexpr(root->left);
			free(root->left);
		}
		if (root->right != NULL) {
			free_dexpr(root->right);
			free(root->right);
		}
		break;
	case DEX_UNK:
	case DEX_VAL:
	default:
		break;
	}
	return;
}

static __attribute__((unused)) void
__pr_val(struct dexkv_s *kv)
{
	switch (kv->sp.spfl) {
	case DT_SPFL_N_DCNT_MON:
		fputs("%d ", stdout);
		break;
	case DT_SPFL_N_MON:
	case DT_SPFL_S_MON:
		fputs("%b ", stdout);
		break;
	case DT_SPFL_N_YEAR:
		fputs("%Y ", stdout);
		break;
	case DT_SPFL_N_DCNT_WEEK:
	case DT_SPFL_S_WDAY:
		fputs("%a ", stdout);
		break;
	case DT_SPFL_N_WCNT_MON:
		fputs("%c ", stdout);
		break;
	case DT_SPFL_N_DCNT_YEAR:
		fputs("%D ", stdout);
		break;
	case DT_SPFL_N_WCNT_YEAR:
		fputs("%C ", stdout);
		break;
	default:
		break;
	}

	switch (kv->op) {
	case OP_LT:
		fputs("< ", stdout);
		break;
	case OP_LE:
		fputs("<= ", stdout);
		break;
	case OP_GT:
		fputs("> ", stdout);
		break;
	case OP_GE:
		fputs(">= ", stdout);
		break;
	case OP_NE:
		fputs("!= ", stdout);
		break;
	case OP_EQ:
	default:
		fputs("== ", stdout);
		break;
	}

	switch (kv->sp.spfl) {
	case DT_SPFL_N_STD: {
		char buf[32];
		dt_strfdt(buf, sizeof(buf), NULL, kv->d);
		fputs(buf, stdout);
		break;
	}
	case DT_SPFL_N_DCNT_MON:
		fprintf(stdout, "%02d", kv->s);
		break;
	case DT_SPFL_N_MON:
	case DT_SPFL_S_MON:
		if (kv->s >= 0 && kv->s <= 12) {
			fputs(dut_abbr_mon[kv->s], stdout);
		}
		break;
	case DT_SPFL_N_YEAR:
		fprintf(stdout, "%04d", kv->s);
		break;
	case DT_SPFL_N_DCNT_WEEK:
	case DT_SPFL_S_WDAY:
		if (kv->s >= 0 && kv->s <= 7) {
			fputs(dut_abbr_wday[kv->s], stdout);
		}
		break;
	case DT_SPFL_N_WCNT_MON:
	case DT_SPFL_N_WCNT_YEAR:
		fprintf(stdout, "%02d", kv->s);
		break;
	case DT_SPFL_N_DCNT_YEAR:
		fprintf(stdout, "%03d", kv->s);
		break;
	default:
		break;
	}
	return;
}

static __attribute__((unused)) void
__pr(dexpr_t root, size_t ind)
{
	switch (root->type) {
	case DEX_VAL:
		for (size_t i = 0; i < ind; i++) {
			fputc(' ', stdout);
		}
		if (root->nega) {
			fputs("!(", stdout);
		}
		__pr_val(root->kv);
		if (root->nega) {
			fputs(")\n", stdout);
		} else {
			fputc('\n', stdout);
		}
		break;

	case DEX_CONJ:
		for (size_t i = 0; i < ind; i++) {
			fputc(' ', stdout);
		}
		if (!root->nega) {
			fputs("AND\n", stdout);
		} else {
			fputs("NAND\n", stdout);
		}
		__pr(root->left, ind + 2);
		__pr(root->right, ind + 2);
		break;

	case DEX_DISJ:
		for (size_t i = 0; i < ind; i++) {
			fputc(' ', stdout);
		}
		if (!root->nega) {
			fputs("OR\n", stdout);
		} else {
			fputs("NOR\n", stdout);
		}
		__pr(root->left, ind + 2);
		__pr(root->right, ind + 2);
		break;

	case DEX_UNK:
	default:
		for (size_t i = 0; i < ind; i++) {
			fputc(' ', stdout);
		}
		if (root->left != NULL) {
			fputs("ROOT\n", stderr);
			__pr(root->left, ind + 2);
			break;
		}
		break;
	}
	return;
}

static __attribute__((unused)) void
__pr_infix(dexpr_t root)
{
	if (root->type == DEX_VAL) {
		__pr_val(root->kv);
		return;
	}

	__pr_infix(root->left);

	switch (root->type) {
	case DEX_CONJ:
		fputs(" && ", stdout);
		break;

	case DEX_DISJ:
		fputs(" || ", stdout);
		break;

	case DEX_VAL:
	case DEX_UNK:
	default:
		/* shouldn't happen :O */
		fputs(" bollocks ", stdout);
		break;
		
	}
	__pr_infix(root->right);

	/* just ascend */
	return;
}


static dexpr_t
make_dexpr(dex_type_t type)
{
	dexpr_t res = calloc(1, sizeof(*res));
	res->type = type;
	return res;
}

static dexpr_t
dexpr_copy(const_dexpr_t src)
{
	dexpr_t res = calloc(1, sizeof(*res));

	memcpy(res, src, sizeof(*res));

	/* deep copy anyone? */
	switch (src->type) {
	case DEX_CONJ:
	case DEX_DISJ:
		res->left = dexpr_copy(src->left);
		res->right = dexpr_copy(src->right);
		break;
	case DEX_VAL:
	case DEX_UNK:
	default:
		break;
	}
	return res;
}

static dexpr_t
dexpr_copy_j(dexpr_t src)
{
/* copy SRC, but only if it's a junction (disjunction or conjunction) */
	if (src->type == DEX_VAL) {
		return (dexpr_t)src;
	}
	return dexpr_copy(src);
}

static void
__dnf(dexpr_t root)
{
/* recursive __dnf'er */
	switch (root->type) {
	case DEX_CONJ: {
		/* check if one of the children is a disjunction */
		dex_type_t rlt = root->left->type;
		dex_type_t rrt = root->right->type;

		if (rlt == DEX_DISJ && rrt == DEX_DISJ) {
			/* complexestest case
			 * (a|b)&(c|d) -> (a&c)|(a&d)|(b&c)|(b&d) */
			dexpr_t a;
			dexpr_t b;
			dexpr_t c;
			dexpr_t d;

			/* get the new idea of b and c */
			a = root->left->left;
			b = root->left->right;
			c = root->right->left;
			d = root->right->right;

			/* now reuse what's possible */
			root->type = DEX_DISJ;
			root->left->type = DEX_CONJ;
#if 0
			/* silly assignment, a comes from left->left */
			root->left->left = a;
#endif	/* 0 */
			root->left->right = c;

			root->right->type = DEX_DISJ;
			root->right->left = make_dexpr(DEX_CONJ);
			root->right->left->left = dexpr_copy_j(a);
			root->right->left->right = d;

			root->right->right = make_dexpr(DEX_DISJ);
			root->right->right->left = make_dexpr(DEX_CONJ);
			root->right->right->left->left = b;
			root->right->right->left->right = dexpr_copy_j(c);
			/* right side, finalise the right branches with CONJ */
			root->right->right->right = make_dexpr(DEX_CONJ);
			root->right->right->right->left = dexpr_copy_j(b);
			root->right->right->right->right = dexpr_copy_j(d);

		} else if (rlt == DEX_DISJ || rrt == DEX_DISJ) {
			/* ok'ish case
			 * a&(b|c) -> a&b|a&c
			 * the other case gets normalised: (a|b)&c -> c&(a|b) */
			dexpr_t a;
			dexpr_t b;
			dexpr_t c;

			/* put the non-DISJ case left */
			if ((a = root->left)->type == DEX_DISJ) {
				a = root->right;
				root->right = root->left;
			}
			/* get the new idea of b and c */
			b = root->right->left;
			c = root->right->right;

			/* turn into disjoint */
			root->type = DEX_DISJ;

			/* inflate left branch */
			root->left = make_dexpr(DEX_CONJ);
			root->left->left = a;
			root->left->right = b;

			/* rearrange this node now, reuse the right disjoint */
			root->right->type = DEX_CONJ;
			root->right->left = a;
			root->right->right = c;
		}
		/* fallthrough! */
	}
	case DEX_DISJ:
		/* nothing to be done other than a quick descent */
		__dnf(root->left);
		__dnf(root->right);

		/* upon ascent fixup double OR's */
		if (root->left->type == DEX_DISJ &&
		    root->right->type == DEX_DISJ) {
			/*      |             |
			 *    /   \          / \
			 *   |     |    ~>  a   |
			 *  / \   / \          / \
			 * a   b c   d        b   |
			 *                       / \
			 *                      c   d */
			dexpr_t i = root->left;
			dexpr_t j = root->right;
			dexpr_t a = i->left;
			dexpr_t b = i->right;
			dexpr_t c = j->left;

			root->left = a;
			root->right = i;
			i->left = b;
			i->right = j;
			j->left = c;

		} else if (root->left->type == DEX_DISJ) {
			/*     |           |
			 *    / \         / \
			 *   |   c   ~>  a   |
			 *  / \             / \
			 * a   b           b   c */
			dexpr_t i = root->left;
			dexpr_t c = root->right;
			dexpr_t a = i->left;
			dexpr_t b = i->right;

			root->left = a;
			root->right = i;
			i->left = b;
			i->right = c;
		}
		break;

	case DEX_VAL:
	case DEX_UNK:
	default:
		/* can't do anything to get the DNF going */
		break;
	}
	return;
}

static void
__nega_kv(struct dexkv_s *kv)
{
/* assume the parent dexpr has the nega flag set, negate KV */
	kv->op = ~kv->op;
	return;
}

static void
__denega(dexpr_t root)
{
	dexpr_t left;
	dexpr_t right;

	if (root->nega) {
		/* negate */
		root->nega = 0;

		switch (root->type) {
		case DEX_CONJ:
			/* !(a&b) -> !a | !b */
			root->type = DEX_DISJ;
			break;
		case DEX_DISJ:
			/* !(a|b) -> !a & !b */
			root->type = DEX_DISJ;
			break;
		case DEX_VAL:
			__nega_kv(root->kv);
			/* fallthrough */
		case DEX_UNK:
		default:
			return;
		}

		if ((left = root->left) != NULL) {
			left->nega = ~left->nega;
		}
		if ((right = root->right) != NULL) {
			right->nega = ~right->nega;
		}
	} else {
		switch (root->type) {
		case DEX_CONJ:
		case DEX_DISJ:
			left = root->left;
			right = root->right;
			break;
		case DEX_VAL:
		case DEX_UNK:
		default:
			return;
		}
	}
	/* descend */
	if (left != NULL) {
		__denega(left);
	}
	if (right != NULL) {
		__denega(right);
	}
	return;
}

static void
dexpr_simplify(dexpr_t root)
{
	__denega(root);
	__dnf(root);
	return;
}

static int
__cmp(struct dt_dt_s stream, struct dt_dt_s cell)
{
/* special promoting/demoting version of dt_dtcmp()
 * if CELL is d-only or t-only, demote STREAM */
	if (dt_sandwich_only_d_p(cell)) {
		return dt_dcmp(stream.d, cell.d);
	} else if (dt_sandwich_only_t_p(cell)) {
		return dt_tcmp(stream.t, cell.t);
	}
	return dt_dtcmp(stream, cell);
}


static bool
dexkv_matches_p(const_dexkv_t dkv, struct dt_dt_s d)
{
	signed int cmp;
	bool res;

	if (dkv->sp.spfl == DT_SPFL_N_STD) {
		if ((cmp = __cmp(d, dkv->d)) == -2) {
			return false;
		}
		switch (dkv->op) {
		case OP_UNK:
		case OP_EQ:
			res = cmp == 0;
			break;
		case OP_LT:
			res = cmp < 0;
			break;
		case OP_LE:
			res = cmp <= 0;
			break;
		case OP_GT:
			res = cmp > 0;
			break;
		case OP_GE:
			res = cmp >= 0;
			break;
		case OP_NE:
			res = cmp != 0;
			break;
		case OP_TRUE:
			res = true;
			break;
		default:
			res = false;
			break;
		}
		return res;
	}
	/* otherwise it's stuff that uses the S slot */
	switch (dkv->sp.spfl) {
	case DT_SPFL_N_YEAR:
		cmp = dt_get_year(d.d);
		break;
	case DT_SPFL_N_MON:
	case DT_SPFL_S_MON:
		cmp = dt_get_mon(d.d);
		break;
	case DT_SPFL_N_DCNT_MON:
		cmp = dt_get_mday(d.d);
		break;
	case DT_SPFL_N_DCNT_WEEK:
	case DT_SPFL_S_WDAY:
		cmp = dt_get_wday(d.d);
		break;
	case DT_SPFL_N_WCNT_MON:
		/* exotic function, needs extern'ing */
		cmp = /*dt_get_count(d)*/0;
		break;
	case DT_SPFL_N_DCNT_YEAR:
		cmp = dt_get_yday(d.d);
		break;
	case DT_SPFL_N_WCNT_YEAR:
		/* %C/%W week count */
		cmp = dt_get_wcnt_year(d.d, dkv->sp.wk_cnt);
		break;
	case DT_SPFL_N_STD:
	default:
		return false;
	}
	/* now do the actual comparison */
	switch (dkv->op) {
	case OP_EQ:
		res = dkv->s == cmp;
		break;
	case OP_LT:
		res = dkv->s < cmp;
		break;
	case OP_LE:
		res = dkv->s <= cmp;
		break;
	case OP_GT:
		res = dkv->s > cmp;
		break;
	case OP_GE:
		res = dkv->s >= cmp;
		break;
	case OP_NE:
		res = dkv->s != cmp;
		break;
	case OP_TRUE:
		res = true;
		break;
	default:
	case OP_UNK:
		res = false;
		break;
	}
	return res;
}

static bool
__conj_matches_p(const_dexpr_t dex, struct dt_dt_s d)
{
	const_dexpr_t a;

	for (a = dex; a->type == DEX_CONJ; a = a->right) {
		if (!dexkv_matches_p(a->left->kv, d)) {
			return false;
		}
	}
	/* rightmost cell might be a DEX_VAL */
	return dexkv_matches_p(a->kv, d);
}

static bool
__disj_matches_p(const_dexpr_t dex, struct dt_dt_s d)
{
	const_dexpr_t o;

	for (o = dex; o->type == DEX_DISJ; o = o->right) {
		if (__conj_matches_p(o->left, d)) {
			return true;
		}
	}
	/* rightmost cell may be a DEX_VAL */
	return __conj_matches_p(o, d);
}

static __attribute__((unused)) bool
dexpr_matches_p(const_dexpr_t dex, struct dt_dt_s d)
{
	return __disj_matches_p(dex, d);
}


#if defined STANDALONE
int
main(int argc, char *argv[])
{
	dexpr_t root;

	for (int i = 1; i < argc; i++) {
		root = NULL;
		dexpr_parse(&root, argv[i], strlen(argv[i]));
		__pr(root, 0);
		fputc('\n', stdout);
		dexpr_simplify(root);
		__pr(root, 0);
		fputc('\n', stdout);
		/* also print an infix line */
		__pr_infix(root);
		fputc('\n', stdout);
		free_dexpr(root);
	}
	return 0;
}
#endif	/* STANDALONE */

/* dexpr.c ends here */
dateutils-0.3.1/src/dexpr.h000066400000000000000000000014751241477753400156200ustar00rootroot00000000000000/*** dexpr.h -- helper for date expressions */
#if !defined INCLUDED_dexpr_h_
#define INCLUDED_dexpr_h_

#include "dt-core.h"
#include "token.h"

typedef struct dexpr_s *dexpr_t;
typedef const struct dexpr_s *const_dexpr_t;

typedef struct dexkv_s *dexkv_t;
typedef const struct dexkv_s *const_dexkv_t;

typedef enum {
	DEX_UNK,
	DEX_VAL,
	DEX_CONJ,
	/* must be last as other types will be considered inferior */
	DEX_DISJ,
} dex_type_t;

struct dexkv_s {
	struct dt_spec_s sp;
	oper_t op:3;
	union {
		struct dt_dt_s d;
		signed int s;
	};
};

struct dexpr_s {
	dex_type_t type:31;
	unsigned int nega:1;
	dexpr_t left;
	union {
		struct dexkv_s kv[1];
		struct {
			dexpr_t right;
			dexpr_t up;
		};
	};
};


/* parser routine */
extern int dexpr_parse(dexpr_t *root, const char *s, size_t l);

#endif	/* INCLUDED_dexpr_h_ */
dateutils-0.3.1/src/dgrep.c000066400000000000000000000136541241477753400155740ustar00rootroot00000000000000/*** dgrep.c -- grep for lines with dates
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include 
#include 

#include "dt-core.h"
#include "dt-core-tz-glue.h"
#include "dt-io.h"
#include "dexpr.h"
#include "prchunk.h"

const char *prog = "dgrep";


/* dexpr subsystem */
#include "dexpr.c"

struct prln_ctx_s {
	struct grep_atom_soa_s *ndl;
	dexpr_t root;
	zif_t fromz;
	zif_t z;
	unsigned int only_matching_p:1U;
	unsigned int invert_match_p:1U;
};

static void
proc_line(struct prln_ctx_s ctx, char *line, size_t llen)
{
	char *osp = NULL;
	char *oep = NULL;

	/* check if line matches,
	 * there's currently no way to specify NEEDLE */
	for (char *lp = line, *sp, *ep; ; lp = ep, osp = sp, oep = ep) {
		struct dt_dt_s d =
			dt_io_find_strpdt2(lp, ctx.ndl, &sp, &ep, ctx.fromz);
		bool unkp = dt_unk_p(d);

		if (unkp) {
			/* just plain nothing */
			break;
		} else if (ctx.z != NULL) {
			/* promote to zone ctx.z */
			d = dtz_enrichz(d, ctx.z);
		}
		/* otherwise */
		if (dexpr_matches_p(ctx.root, d)) {
			if (ctx.invert_match_p) {
				/* nothing must match */
				return;
			} else if (!ctx.only_matching_p) {
				sp = line;
				ep = line + llen;
			}
			/* make sure we finish the line */
			*ep++ = '\n';
			__io_write(sp, ep - sp, stdout);
			return;
		}
	}
	if (ctx.invert_match_p) {
		/* no match but invert_match select, print line */
		if (!ctx.only_matching_p) {
			osp = line;
			oep = line + llen;
		} else if (osp == NULL || oep == NULL) {
			/* no date in line and only-matching is active
			 * bugger off */
			return;
		}
		/* finish the line and bugger off */
		*oep++ = '\n';
		__io_write(osp, oep - osp, stdout);
	}
	return;
}


#include "dgrep.yucc"

int
main(int argc, char *argv[])
{
	yuck_t argi[1U];
	char **fmt;
	size_t nfmt;
	dexpr_t root;
	oper_t o = OP_UNK;
	int res = 0;

	if (yuck_parse(argi, argc, argv)) {
		res = 1;
		goto out;
	}

	/* init and unescape sequences, maybe */
	ckv_fmt = fmt = argi->input_format_args;
	ckv_nfmt = nfmt = argi->input_format_nargs;
	if (argi->backslash_escapes_flag) {
		for (size_t i = 0; i < nfmt; i++) {
			dt_io_unescape(fmt[i]);
		}
	}

	if (argi->eq_flag) {
		o = OP_EQ;
	} else if (argi->ne_flag) {
		o = OP_NE;
	} else if (argi->lt_flag || argi->ot_flag) {
		o = OP_LT;
	} else if (argi->le_flag) {
		o = OP_LE;
	} else if (argi->gt_flag || argi->nt_flag) {
		o = OP_GT;
	} else if (argi->ge_flag) {
		o = OP_GE;
	}
	/* parse the expression */
	if (argi->nargs == 0U || 
	    dexpr_parse(&root, argi->args[0U], strlen(argi->args[0U])) < 0) {
		res = 1;
		error("Error: need an expression to grep");
		goto out;
	}
	/* fixup o, default is OP_EQ */
	if (o != OP_UNK && root->type != DEX_VAL) {
		res = 1;
		error("\
long opt operators (--lt, --gt, ...) cannot be used in conjunction \n\
with complex expressions");
		goto out;
	} else if (o != OP_UNK) {
		/* fiddle with the operator in the expression */
		root->kv->op = o;
	}

	/* otherwise bring dexpr to normal form */
	dexpr_simplify(root);
	/* beef */
	{
		/* read from stdin */
		size_t lno = 0;
		struct grep_atom_s __nstk[16], *needle = __nstk;
		size_t nneedle = countof(__nstk);
		struct grep_atom_soa_s ndlsoa;
		void *pctx;
		struct prln_ctx_s prln = {
			.ndl = &ndlsoa,
			.root = root,
			.fromz = dt_io_zone(argi->from_zone_arg),
			.z = dt_io_zone(argi->zone_arg),
			.only_matching_p = argi->only_matching_flag,
			.invert_match_p = argi->invert_match_flag,
		};

		/* no threads reading this stream */
		__io_setlocking_bycaller(stdout);

		/* lest we overflow the stack */
		if (nfmt >= nneedle) {
			/* round to the nearest 8-multiple */
			nneedle = (nfmt | 7) + 1;
			needle = calloc(nneedle, sizeof(*needle));
		}
		/* and now build the needle */
		ndlsoa = build_needle(needle, nneedle, fmt, nfmt);

		/* using the prchunk reader now */
		if ((pctx = init_prchunk(STDIN_FILENO)) == NULL) {
			serror("Error: could not open stdin");
			goto ndl_free;
		}
		while (prchunk_fill(pctx) >= 0) {
			for (char *line; prchunk_haslinep(pctx); lno++) {
				size_t llen = prchunk_getline(pctx, &line);

				proc_line(prln, line, llen);
			}
		}
		/* get rid of resources */
		free_prchunk(pctx);
	ndl_free:
		if (needle != __nstk) {
			free(needle);
		}
	}
	/* resource freeing */
	free_dexpr(root);
	dt_io_clear_zones();
out:
	yuck_free(argi);
	return res;
}

/* dgrep.c ends here */
dateutils-0.3.1/src/dgrep.yuck000066400000000000000000000061621241477753400163210ustar00rootroot00000000000000Usage: dgrep [OPTION]... EXPRESSION

Grep standard input for lines that match EXPRESSION.

EXPRESSION may be date/times prefixed with an operator `<', `<=', '=', '>=',
'>', `!=', `<>' (if omitted defaults to `='),
which will match lines with date/times which are older, older-equal, equal,
newer-equal, newer, or not equal respectively.

EXPRESSION may also be format specifiers infixed by above operators
and suffixed by a value (e.g. `%a="Wed"') which matches lines whose
%a representation (weekday name abbreviated) is "Wed".

EXPRESSION may be statements as described above concatenated through `&&' (for
conjunction) or `||' (disjunction), both of which may be parenthesised as per
usual to change precedence (`&&' goes over `||').

If multiple date/times occur on the same line and any one of them fulfills the
criteria then the line is considered a match and will be output.

  -h, --help                 Print help and exit
  -V, --version              Print version and exit
  -q, --quiet                Suppress message about date/time and duration
                               parser errors.
  -i, --input-format=STRING...  Input format, can be used multiple times.
                               Each date/time will be passed to the input
                               format parsers in the order they are given, if a
                               date/time can be read successfully with a given
                               input format specifier string, that value will
                               be used.
  -e, --backslash-escapes    Enable interpretation of backslash escapes in the
                               output and input format specifier strings.
  -o, --only-matching        Show only the part of a line matching DATE.
  -v, --invert-match         Select non-matching lines.
      --from-zone=ZONE  Consider date/times on stdin as coming from the
                        zone ZONE, default: UTC.
  -z, --zone=ZONE       Consider date/times in EXPRESSION as coming from
                        the zone ZONE, default: UTC.

Note:
  Operations can be specified by options (--eq, --gt, ...) as well.
  This serves solely as a means of convenience, e.g. the dtest tool has a
  similar syntax.

      --eq                   Lines match when date/times are equal to
                               EXPRESSION.
      --ne                   Lines match when date/times are not the same as
                               EXPRESSION.
      --gt                   Lines match when date/times are newer than
                               EXPRESSION.
      --lt                   Lines match when date/times are older than
                               EXPRESSION.
      --ge                   Lines match when date/times are newer than or
                               equal EXPRESSION.
      --le                   Lines match when date/times are older than or
                               equal EXPRESSION.
      --nt                   Lines match when date/times are newer than or
                               equal EXPRESSION.
      --ot                   Lines match when date/times are older than or
                               equal EXPRESSION.
dateutils-0.3.1/src/dround.c000066400000000000000000000322571241477753400157660ustar00rootroot00000000000000/*** dround.c -- perform simple date arithmetic, round to duration
 *
 * Copyright (C) 2012-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include 
#include 

#include "dt-core.h"
#include "dt-io.h"
#include "dt-core-tz-glue.h"
#include "prchunk.h"
/* parsers and formatters */
#include "date-core-strpf.h"

#if !defined assert
# define assert(x)
#endif	/* !assert */

const char *prog = "dround";


static bool
durs_only_d_p(struct dt_dt_s dur[], size_t ndur)
{
	for (size_t i = 0; i < ndur; i++) {
		if (dur[i].t.typ) {
			return false;
		}
	}
	return true;
}

static struct dt_t_s
tround_tdur(struct dt_t_s t, struct dt_t_s dur, bool nextp)
{
/* this will return the rounded to DUR time of T and, to encode carry
 * (which can only take values 0 or 1), we will use t's neg bit */
	signed int mdur;
	signed int diff;

	/* no dur is a no-op */
	if (UNLIKELY(!dur.sdur)) {
		return t;
	}

	/* unpack t */
	mdur = t.hms.h * SECS_PER_HOUR +
		t.hms.m * SECS_PER_MIN +
		t.hms.s;
	if (!(diff = mdur % dur.sdur) && !t.hms.ns && !nextp) {
		return t;
	}

	/* compute the result */
	mdur -= diff;
	if (dur.sdur > 0 || nextp) {
		mdur += dur.sdur;
	}
	if (UNLIKELY(mdur < 0)) {
		/* lift */
		mdur += SECS_PER_DAY;
		/* denote the carry */
		t.neg = 1;
	} else if (UNLIKELY(mdur >= (signed)SECS_PER_DAY)) {
		t.neg = 1;
	}
	/* and convert back */
	t.hms.ns = 0;
	t.hms.s = mdur % SECS_PER_MIN;
	mdur /= SECS_PER_MIN;
	t.hms.m = mdur % MINS_PER_HOUR;
	mdur /= MINS_PER_HOUR;
	t.hms.h = mdur % HOURS_PER_DAY;
	return t;
}

static struct dt_d_s
dround_ddur(struct dt_d_s d, struct dt_d_s dur, bool nextp)
{
	switch (dur.typ) {
		unsigned int tgt;
		bool forw;
	case DT_DAISY:
		if (dur.daisydur > 0) {
			tgt = dur.daisydur;
			forw = true;
		} else if (dur.daisydur < 0) {
			tgt = -dur.daisydur;
			forw = false;
		} else {
			/* user is an idiot */
			break;
		}

		switch (d.typ) {
			unsigned int mdays;
		case DT_YMD:
			if ((forw && d.ymd.d < tgt) ||
			    (!forw && d.ymd.d > tgt)) {
				/* no month or year adjustment */
				;
			} else if (d.ymd.d == tgt && !nextp) {
				/* we're ON the date already and no
				 * next/prev date is requested */
				;
			} else if (forw) {
				if (LIKELY(d.ymd.m < GREG_MONTHS_P_YEAR)) {
					d.ymd.m++;
				} else {
					d.ymd.m = 1;
					d.ymd.y++;
				}
			} else {
				if (UNLIKELY(--d.ymd.m < 1)) {
					d.ymd.m = GREG_MONTHS_P_YEAR;
					d.ymd.y--;
				}
			}
			/* get ultimo */
			mdays = __get_mdays(d.ymd.y, d.ymd.m);
			if (UNLIKELY(tgt > mdays)) {
				tgt = mdays;
			}
			/* final assignment */
			d.ymd.d = tgt;
			break;
		default:
			break;
		}
		break;

	case DT_BIZSI:
		/* bizsis only work on bizsidurs atm */
		if (dur.bizsidur > 0) {
			tgt = dur.bizsidur;
			forw = true;
		} else if (dur.bizsidur < 0) {
			tgt = -dur.bizsidur;
			forw = false;
		} else {
			/* user is an idiot */
			break;
		}

		switch (d.typ) {
			unsigned int bdays;
		case DT_BIZDA:
			if ((forw && d.bizda.bd < tgt) ||
			    (!forw && d.bizda.bd > tgt)) {
				/* no month or year adjustment */
				;
			} else if (d.bizda.bd == tgt && !nextp) {
				/* we're ON the date already and no
				 * next/prev date is requested */
				;
			} else if (forw) {
				if (LIKELY(d.bizda.m < GREG_MONTHS_P_YEAR)) {
					d.bizda.m++;
				} else {
					d.bizda.m = 1;
					d.bizda.y++;
				}
			} else {
				if (UNLIKELY(--d.bizda.m < 1)) {
					d.bizda.m = GREG_MONTHS_P_YEAR;
					d.bizda.y--;
				}
			}
			/* get ultimo */
			bdays = __get_bdays(d.bizda.y, d.bizda.m);
			if (UNLIKELY(tgt > bdays)) {
				tgt = bdays;
			}
			/* final assignment */
			d.bizda.bd = tgt;
			break;
		default:
			break;
		}
		break;

	case DT_YMD:
		switch (d.typ) {
			unsigned int mdays;
		case DT_YMD:
			forw = !dur.neg;
			tgt = dur.ymd.m;

			if ((forw && d.ymd.m < tgt) ||
			    (!forw && d.ymd.m > tgt)) {
				/* no year adjustment */
				;
			} else if (d.ymd.m == tgt && !nextp) {
				/* we're IN the month already and no
				 * next/prev date is requested */
				;
			} else if (forw) {
				/* years don't wrap around */
				d.ymd.y++;
			} else {
				/* years don't wrap around */
				d.ymd.y--;
			}
			/* final assignment */
			d.ymd.m = tgt;
			/* fixup ultimo mismatches */
			mdays = __get_mdays(d.ymd.y, d.ymd.m);
			if (UNLIKELY(d.ymd.d > mdays)) {
				d.ymd.d = mdays;
			}
			break;
		default:
			break;
		}
		break;

	case DT_YMCW: {
		struct dt_d_s tmp;
		unsigned int wday;
		signed int diff;

		forw = !dur.neg;
		tgt = dur.ymcw.w;

		tmp = dt_dconv(DT_DAISY, d);
		wday = dt_get_wday(tmp);
		diff = (signed)tgt - (signed)wday;


		if ((forw && wday < tgt) ||
		    (!forw && wday > tgt)) {
			/* nothing to do */
			;
		} else if (wday == tgt && !nextp) {
			/* we're on WDAY already, do fuckall */
			;
		} else if (forw) {
			/* week wrap */
			diff += 7;
		} else {
			/* week wrap */
			diff -= 7;
		}

		/* final assignment */
		tmp.daisy += diff;
		d = dt_dconv(d.typ, tmp);
		break;
	}

	case DT_MD:
	default:
		break;
	}
	return d;
}

static struct dt_d_s one_day = {
	.typ = DT_DAISY,
	.dur = 1,
	.neg = 0,
};

static struct dt_dt_s
dt_round(struct dt_dt_s d, struct dt_dt_s dur, bool nextp)
{
	if (dt_sandwich_only_t_p(dur) && d.sandwich) {
		d.t = tround_tdur(d.t, dur.t, nextp);
		/* check carry */
		if (UNLIKELY(d.t.neg == 1)) {
			/* we need to add a day */
			one_day.daisydur = 1 | -(dur.t.sdur < 0);
			d.t.neg = 0;
			d.d = dt_dadd(d.d, one_day);
		}
	} else if (dt_sandwich_only_d_p(dur) &&
		   (dt_sandwich_p(d) || dt_sandwich_only_d_p(d))) {
		unsigned int sw = d.sandwich;
		d.d = dround_ddur(d.d, dur.d, nextp);
		d.sandwich = (uint8_t)sw;
	}
	return d;
}


static struct dt_dt_s
dround(struct dt_dt_s d, struct dt_dt_s dur[], size_t ndur, bool nextp)
{
	for (size_t i = 0; i < ndur; i++) {
		d = dt_round(d, dur[i], nextp);
	}
	return d;
}

/* extended duration reader */
static int
dt_io_strpdtrnd(struct __strpdtdur_st_s *st, const char *str)
{
	char *sp = NULL;
	struct strpd_s d = strpd_initialiser();
	struct dt_spec_s s = spec_initialiser();
	struct dt_dt_s payload = dt_dt_initialiser();
	bool negp = false;

	if (dt_io_strpdtdur(st, str) >= 0) {
		return 0;
	}

	/* check if there's a sign + or - */
	if (*str == '-') {
		negp = true;
		str++;
	} else if (*str == '+') {
		str++;
	}

	/* try weekdays, set up s */
	s.spfl = DT_SPFL_S_WDAY;
	s.abbr = DT_SPMOD_NORM;
	if (__strpd_card(&d, str, s, &sp) >= 0) {
		payload.d = dt_make_ymcw(0, 0, 0, d.w);
		/* make sure it's d-only */
		payload.sandwich = 0;
		goto out;
	}

	/* try months, set up s */
	s.spfl = DT_SPFL_S_MON;
	s.abbr = DT_SPMOD_NORM;
	if (__strpd_card(&d, str, s, &sp) >= 0) {
		payload.d = dt_make_ymd(0, d.m, 0);
		/* make sure it's d-only */
		payload.sandwich = 0;
		goto out;
	}

	/* bugger */
	st->istr = str;
	return -1;
out:
	st->sign = 0;
	st->cont = NULL;
	payload.neg = negp;
	return __add_dur(st, payload);
}

struct prln_ctx_s {
	struct grep_atom_soa_s *ndl;
	const char *ofmt;
	zif_t fromz;
	zif_t outz;
	zif_t hackz;
	int sed_mode_p;
	int quietp;

	const struct __strpdtdur_st_s *st;
	bool nextp;
};

static int
proc_line(struct prln_ctx_s ctx, char *line, size_t llen)
{
	struct dt_dt_s d;
	char *sp = NULL;
	char *ep = NULL;
	int rc = 0;

	do {
		/* check if line matches, */
		d = dt_io_find_strpdt2(line, ctx.ndl, &sp, &ep, ctx.fromz);

		if (!dt_unk_p(d)) {
			if (UNLIKELY(d.fix) && !ctx.quietp) {
				rc = 2;
			}
			/* perform addition now */
			d = dround(d, ctx.st->durs, ctx.st->ndurs, ctx.nextp);

			if (ctx.hackz == NULL && ctx.fromz != NULL) {
				/* fixup zone */
				d = dtz_forgetz(d, ctx.fromz);
			}

			if (ctx.sed_mode_p) {
				__io_write(line, sp - line, stdout);
				dt_io_write(d, ctx.ofmt, ctx.outz, '\0');
				llen -= (ep - line);
				line = ep;
			} else {
				dt_io_write(d, ctx.ofmt, ctx.outz, '\n');
				break;
			}
		} else if (ctx.sed_mode_p) {
			line[llen] = '\n';
			__io_write(line, llen + 1, stdout);
			break;
		} else {
			/* obviously unmatched, warn about it in non -q mode */
			if (!ctx.quietp) {
				dt_io_warn_strpdt(line);
				rc = 2;
			}
			break;
		}
	} while (1);
	return rc;
}


#include "dround.yucc"

int
main(int argc, char *argv[])
{
	yuck_t argi[1U];
	struct dt_dt_s d;
	struct __strpdtdur_st_s st = __strpdtdur_st_initialiser();
	char *inp;
	const char *ofmt;
	char **fmt;
	size_t nfmt;
	int rc = 0;
	bool dt_given_p = false;
	bool nextp = false;
	zif_t fromz = NULL;
	zif_t z = NULL;
	zif_t hackz = NULL;

	if (yuck_parse(argi, argc, argv)) {
		rc = 1;
		goto out;
	} else if (argi->nargs == 0U) {
		error("Error: DATE or DURATION must be specified\n");
		yuck_auto_help(argi);
		rc = 1;
		goto out;
	}
	/* init and unescape sequences, maybe */
	ofmt = argi->format_arg;
	fmt = argi->input_format_args;
	nfmt = argi->input_format_nargs;
	if (argi->backslash_escapes_flag) {
		dt_io_unescape(argi->format_arg);
		for (size_t i = 0; i < nfmt; i++) {
			dt_io_unescape(fmt[i]);
		}
	}

	/* try and read the from and to time zones */
	if (argi->from_zone_arg) {
		fromz = dt_io_zone(argi->from_zone_arg);
	}
	if (argi->zone_arg) {
		z = dt_io_zone(argi->zone_arg);
	}
	if (argi->next_flag) {
		nextp = true;
	}

	/* check first arg, if it's a date the rest of the arguments are
	 * durations, if not, dates must be read from stdin */
	for (size_t i = 0U; i < argi->nargs; i++) {
		inp = argi->args[i];
		do {
			if (dt_io_strpdtrnd(&st, inp) < 0) {
				if (UNLIKELY(i == 0)) {
					/* that's ok, must be a date then */
					dt_given_p = true;
				} else {
					serror("Error: \
cannot parse duration/rounding string `%s'", st.istr);
				}
			}
		} while (__strpdtdur_more_p(&st));
	}
	/* check if there's only d durations */
	hackz = durs_only_d_p(st.durs, st.ndurs) ? NULL : fromz;

	/* sanity checks */
	if (dt_given_p) {
		/* date parsing needed postponing as we need to find out
		 * about the durations */
		inp = argi->args[0U];
		if (dt_unk_p(d = dt_io_strpdt(inp, fmt, nfmt, hackz))) {
			error("Error: \
cannot interpret date/time string `%s'", argi->args[0U]);
			rc = 1;
			goto out;
		}
	} else if (st.ndurs == 0) {
		error("Error: \
no durations given");
		rc = 1;
		goto out;
	}

	/* start the actual work */
	if (dt_given_p) {
		if (UNLIKELY(d.fix) && !argi->quiet_flag) {
			rc = 2;
		}
		if (!dt_unk_p(d = dround(d, st.durs, st.ndurs, nextp))) {
			if (hackz == NULL && fromz != NULL) {
				/* fixup zone */
				d = dtz_forgetz(d, fromz);
			}
			dt_io_write(d, ofmt, z, '\n');
		} else {
			rc = 1;
		}
	} else {
		/* read from stdin */
		size_t lno = 0;
		struct grep_atom_s __nstk[16], *needle = __nstk;
		size_t nneedle = countof(__nstk);
		struct grep_atom_soa_s ndlsoa;
		void *pctx;
		struct prln_ctx_s prln = {
			.ndl = &ndlsoa,
			.ofmt = ofmt,
			.fromz = fromz,
			.outz = z,
			.hackz = hackz,
			.sed_mode_p = argi->sed_mode_flag,
			.quietp = argi->quiet_flag,
			.st = &st,
			.nextp = nextp,
		};

		/* no threads reading this stream */
		__io_setlocking_bycaller(stdout);

		/* lest we overflow the stack */
		if (nfmt >= nneedle) {
			/* round to the nearest 8-multiple */
			nneedle = (nfmt | 7) + 1;
			needle = calloc(nneedle, sizeof(*needle));
		}
		/* and now build the needle */
		ndlsoa = build_needle(needle, nneedle, fmt, nfmt);


		/* using the prchunk reader now */
		if ((pctx = init_prchunk(STDIN_FILENO)) == NULL) {
			serror("Error: could not open stdin");
			goto ndl_free;
		}
		while (prchunk_fill(pctx) >= 0) {
			for (char *line; prchunk_haslinep(pctx); lno++) {
				size_t llen = prchunk_getline(pctx, &line);

				rc |= proc_line(prln, line, llen);
			}
		}
		/* get rid of resources */
		free_prchunk(pctx);
	ndl_free:
		if (needle != __nstk) {
			free(needle);
		}
		goto out;
	}
	/* free the strpdur status */
	__strpdtdur_free(&st);

	dt_io_clear_zones();

out:
	yuck_free(argi);
	return rc;
}

/* dround.c ends here */
dateutils-0.3.1/src/dround.yuck000066400000000000000000000065551241477753400165210ustar00rootroot00000000000000Usage: dround [OPTION]... [DATE/TIME] RNDSPEC...

Round DATE/TIME to the next occurrence of RNDSPEC.

If DATE/TIME is omitted a stream of date/times is read from stdin.

DATE/TIME can also be one of the following specials
  - `now'           interpreted as the current (UTC) time stamp
  - `time'          the time part of the current (UTC) time stamp
  - `today'         the current date (according to UTC)
  - `tomo[rrow]'    tomorrow's date (according to UTC)
  - `y[ester]day'   yesterday's date (according to UTC)


RNDSPECs can be month names (Jan, Feb, ...), weekday names (Sun, Mon, ...), or
days.
If a month name the next date/time relative to DATE/TIME is returned whose
month part matches the value given, so e.`g. dround 2012-01-01 Feb' will return
2012-02-01.
If a weekday name is given, the next date/time after DATE/TIME whose weekday
part matches the values given is returned.
If a day, the next date/time after DATE/TIME whose day part matches is
returned, so `dround 2012-01-15 1' will return 2012-02-01.

RNDSPECs can also be multiples of the day dividing units, e.g 1h rounds to the
nearest full hour, 30m to the nearest half hour, and 10s to the next 10s mark.

To round to the previous occurrence of a RNDSPEC any argument can be prefixed
with a `-' to denote that.  E.g. `dround 2012-02-14 -1' will return 2012-02-01.
And `dround 2012-02-11 -- -Sep' will return 2011-09-11.

Multiple RNDSPECs are evaluated left to right.

Note that rounding isn't commutative, e.g.
	2012-03-01 Sat Sep -> 2012-09-03
vs.
	2012-03-01 Sep Sat -> 2012-09-01

Note that non-numeric strings prefixed with a `-' conflict with the command
line options and a separating `--' has to be used.

  -h, --help                 Print help and exit
  -V, --version              Print version and exit
  -q, --quiet                Suppress message about date/time and duration
                             parser errors and fix-ups.
                             The default is to print a warning or the
                             fixed up value and return error code 2.
  -f, --format=STRING        Output format.  This can either be a specifier
                               string (similar to strftime()'s FMT) or the name
                               of a calendar.
  -i, --input-format=STRING...  Input format, can be used multiple times.
                               Each date/time will be passed to the input
                               format parsers in the order they are given, if a
                               date/time can be read successfully with a given
                               input format specifier string, that value will
                               be used.
  -e, --backslash-escapes    Enable interpretation of backslash escapes in the
                               output and input format specifier strings.
  -S, --sed-mode             Copy parts from the input before and after a
                               matching date/time.
                               Note that all occurrences of date/times within a
                               line will be processed.
      --from-zone=ZONE       Interpret dates on stdin or the command line as
                               coming from the time zone ZONE.
  -z, --zone=ZONE            Convert dates printed on stdout to time zone ZONE,
                               default: UTC.
  -n, --next                 Always round to a different date or time.
dateutils-0.3.1/src/dseq.c000066400000000000000000000372441241477753400154300ustar00rootroot00000000000000/*** dseq.c -- like seq(1) but for dates
 *
 * Copyright (C) 2009 - 2011 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/

#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include 
#include 
#include 

#include "dt-core.h"
#include "dt-io.h"
#include "tzraw.h"

typedef uint8_t __skipspec_t;

/* generic closure */
struct dseq_clo_s {
	struct dt_dt_s fst;
	struct dt_dt_s lst;
	struct dt_dt_s *ite;
	size_t nite;
	struct dt_dt_s *altite;
	__skipspec_t ss;
	size_t naltite;
	/* direction, >0 if increasing, <0 if decreasing, 0 if undefined */
	int dir;
	int flags;
#define CLO_FL_FREE_ITE		(1)
};

const char *prog = "dseq";


/* skip system */
static int
skipp(__skipspec_t ss, struct dt_dt_s dt)
{
	dt_dow_t dow;
	/* common case first */
	if (ss == 0) {
		return 0;
	}
	dow = dt_get_wday(dt.d);
	/* just check if the bit in the bitset `skip' is set */
	return (ss & (1 << dow)) != 0;
}

#define SKIP_MON	(1 << DT_MONDAY)
#define SKIP_TUE	(1 << DT_TUESDAY)
#define SKIP_WED	(1 << DT_WEDNESDAY)
#define SKIP_THU	(1 << DT_THURSDAY)
#define SKIP_FRI	(1 << DT_FRIDAY)
#define SKIP_SAT	(1 << DT_SATURDAY)
#define SKIP_SUN	(1 << DT_SUNDAY)

static inline int
__toupper(int c)
{
	return c & ~0x20;
}

static dt_dow_t
__parse_wd(const char *str)
{
#define ILEA(a, b)	(((a) << 8) | (b))
	int s1 = __toupper(str[0]);
	int s2 = __toupper(str[1]);

	switch (ILEA(s1, s2)) {
	case ILEA('M', 'O'):
	case ILEA('M', 0):
		/* monday */
		return DT_MONDAY;
	case ILEA('T', 'U'):
		/* tuesday */
		return DT_TUESDAY;
	case ILEA('W', 'E'):
	case ILEA('W', 0):
		/* wednesday */
		return DT_WEDNESDAY;
	case ILEA('T', 'H'):
		/* thursday */
		return DT_THURSDAY;
	case ILEA('F', 'R'):
	case ILEA('F', 0):
		/* friday */
		return DT_FRIDAY;
	case ILEA('S', 'A'):
	case ILEA('A', 0):
		/* saturday */
		return DT_SATURDAY;
	case ILEA('S', 'U'):
	case ILEA('S', 0):
		/* sunday */
		return DT_SUNDAY;
	default:
		return DT_MIRACLEDAY;
	}
}

static __skipspec_t
__skip_dow(__skipspec_t ss, unsigned int wd)
{
	if (wd > GREG_DAYS_P_WEEK) {
		wd -= GREG_DAYS_P_WEEK;
	}

	switch (wd) {
	case DT_MONDAY:
		/* monday */
		ss |= SKIP_MON;
		break;
	case DT_TUESDAY:
		/* tuesday */
		ss |= SKIP_TUE;
		break;
	case DT_WEDNESDAY:
		/* wednesday */
		ss |= SKIP_WED;
		break;
	case DT_THURSDAY:
		/* thursday */
		ss |= SKIP_THU;
		break;
	case DT_FRIDAY:
		/* friday */
		ss |= SKIP_FRI;
		break;
	case DT_SATURDAY:
		/* saturday */
		ss |= SKIP_SAT;
		break;
	case DT_SUNDAY:
		/* sunday */
		ss |= SKIP_SUN;
		break;
	default:
	case DT_MIRACLEDAY:
		break;
	}
	return ss;
}

static __skipspec_t
__skip_str(__skipspec_t ss, const char *str)
{
	dt_dow_t tmp;

	if ((tmp = __parse_wd(str)) != DT_MIRACLEDAY) {
		ss = __skip_dow(ss, tmp);
	} else {
		int s1 = __toupper(str[0]);
		int s2 = __toupper(str[1]);

		if (ILEA(s1, s2) == ILEA('S', 'S')) {
			/* weekend */
			ss |= SKIP_SAT;
			ss |= SKIP_SUN;
		}
	}
	return ss;
}

static __skipspec_t
__skip_1spec(__skipspec_t ss, char *spec)
{
	char *tmp;
	dt_dow_t from, till;

	if ((tmp = strchr(spec, '-')) == NULL) {
		return __skip_str(ss, spec);
	}
	/* otherwise it's a range */
	*tmp = '\0';
	from = __parse_wd(spec);
	till = __parse_wd(tmp + 1);
	for (int d = from, e = till >= from ? till : till + 7; d <= e; d++) {
		ss = __skip_dow(ss, d);
	}
	return ss;
}

static __skipspec_t
set_skip(__skipspec_t ss, char *spec)
{
	char *tmp, *tm2;

	if ((tmp = strchr(spec, ',')) == NULL) {
		return __skip_1spec(ss, spec);
	}
	/* const violation */
	*tmp++ = '\0';
	ss = __skip_1spec(ss, spec);
	while ((tmp = strchr(tm2 = tmp, ','))) {
		*tmp++ = '\0';
		ss = __skip_1spec(ss, tm2);
	}
	return __skip_1spec(ss, tm2);
}

static struct dt_dt_s
date_add(struct dt_dt_s d, struct dt_dt_s dur[], size_t ndur)
{
	for (size_t i = 0; i < ndur; i++) {
		d = dt_dtadd(d, dur[i]);
	}
	return d;
}

static void
date_neg_dur(struct dt_dt_s dur[], size_t ndur)
{
	for (size_t i = 0; i < ndur; i++) {
		dur[i] = dt_neg_dtdur(dur[i]);
	}
	return;
}

static bool
__daisy_feasible_p(struct dt_dt_s dur[], size_t ndur)
{
	if (ndur != 1) {
		return false;
	} else if (dur->typ == (dt_dttyp_t)DT_YMD) {
		if (dur->d.ymd.y || dur->d.ymd.m) {
			return false;
		}
	} else if (dur->typ == (dt_dttyp_t)DT_MD) {
		if (dur->d.md.m) {
			return false;
		}
	} else if (dur->typ == (dt_dttyp_t)DT_BIZDA && (dur->d.bizda.bd)) {
		return false;
	}
	return true;
}

static bool
__dur_naught_p(struct dt_dt_s dur)
{
	return dur.d.u == 0 && dur.t.sdur == 0;
}

static bool
__durstack_naught_p(struct dt_dt_s dur[], size_t ndur)
{
	if (ndur == 0) {
		return true;
	} else if (ndur == 1) {
		return __dur_naught_p(dur[0]);
	}
	for (size_t i = 0; i < ndur; i++) {
		if (!__dur_naught_p(dur[i])) {
		    return false;
		}
	}
	return true;
}

static bool
__in_range_p(struct dt_dt_s now, struct dseq_clo_s *clo)
{
	if (!dt_sandwich_only_t_p(now)) {
		if (clo->dir > 0) {
			return dt_dt_in_range_p(now, clo->fst, clo->lst);
		} else if (clo->dir < 0) {
			return dt_dt_in_range_p(now, clo->lst, clo->fst);
		}
	}
	/* otherwise perform a simple range check */
	if (clo->dir > 0) {
		if (now.t.u >= clo->fst.t.u && now.t.u <= clo->lst.t.u) {
			return true;
		} else if (clo->fst.t.u >= clo->lst.t.u) {
			return now.t.u <= clo->lst.t.u || now.d.daisydur == 0;
		}
	} else if (clo->dir < 0) {
		if (now.t.u <= clo->fst.t.u && now.t.u >= clo->lst.t.u) {
			return true;
		} else if (clo->fst.t.u <= clo->lst.t.u) {
			return now.t.u >= clo->lst.t.u || now.d.daisydur == 0;
		}
	}
	return false;
}

static struct dt_dt_s
__seq_altnext(struct dt_dt_s now, struct dseq_clo_s *clo)
{
	do {
		now = date_add(now, clo->altite, clo->naltite);
	} while (skipp(clo->ss, now) && __in_range_p(now, clo));
	return now;
}

static struct dt_dt_s
__seq_this(struct dt_dt_s now, struct dseq_clo_s *clo)
{
/* if NOW is on a skip date, find the next date according to ALTITE, then ITE */
	if (!skipp(clo->ss, now) && __in_range_p(now, clo)) {
		return now;
	} else if (clo->naltite > 0) {
		return __seq_altnext(now, clo);
	} else if (clo->nite) {
		/* advance until it goes out of range */
		for (;
		     skipp(clo->ss, now) && __in_range_p(now, clo);
		     now = date_add(now, clo->ite, clo->nite));
	} else {
		/* good question */
		;
	}
	return now;
}

static struct dt_dt_s
__seq_next(struct dt_dt_s now, struct dseq_clo_s *clo)
{
/* advance NOW, then fix it */
	struct dt_dt_s tmp = date_add(now, clo->ite, clo->nite);
	return __seq_this(tmp, clo);
}

static int
__get_dir(struct dt_dt_s d, struct dseq_clo_s *clo)
{
	if (!dt_sandwich_only_t_p(d)) {
		/* trial addition to to see where it goes */
		struct dt_dt_s tmp = __seq_next(d, clo);
		return dt_dtcmp(tmp, d);
	}
	if (clo->ite->t.sdur && !clo->ite->t.neg) {
		return 1;
	} else if (clo->ite->t.sdur && clo->ite->t.neg) {
		return -1;
	}
	return 0;
}

static struct dt_dt_s
__fixup_fst(struct dseq_clo_s *clo)
{
	struct dt_dt_s tmp;
	struct dt_dt_s old;

	/* assume clo->dir has been computed already */
	old = tmp = clo->lst;
	date_neg_dur(clo->ite, clo->nite);
	while (__in_range_p(tmp, clo)) {
		old = tmp;
		tmp = __seq_next(tmp, clo);
	}
	/* final checks */
	old = __seq_this(old, clo);
	date_neg_dur(clo->ite, clo->nite);
	/* fixup again with negated dur */
	old = __seq_this(old, clo);
	return old;
}

static struct dt_t_s
tseq_guess_ite(struct dt_t_s beg, struct dt_t_s end)
{
	struct dt_t_s res;

	if (beg.hms.h != end.hms.h &&
	    beg.hms.m == 0 && end.hms.m == 0&&
	    beg.hms.s == 0 && end.hms.s == 0) {
		if (beg.u < end.u) {
			res.sdur = SECS_PER_HOUR;
		} else {
			res.sdur = -SECS_PER_HOUR;
		}
	} else if (beg.hms.m != end.hms.m &&
		   beg.hms.s == 0 && end.hms.s == 0) {
		if (beg.u < end.u) {
			res.sdur = SECS_PER_MIN;
		} else {
			res.sdur = -SECS_PER_MIN;
		}
	} else {
		if (beg.u < end.u) {
			res.sdur = 1L;
		} else {
			res.sdur = -1L;
		}
	}
	res.dur = 1;
	return res;
}


#include "dseq.yucc"

int
main(int argc, char *argv[])
{
	static struct dt_dt_s ite_p1;
	yuck_t argi[1U];
	struct dt_dt_s tmp;
	char **ifmt;
	size_t nifmt;
	char *ofmt;
	dt_dttyp_t tgttyp;
	int rc = 0;
	struct dseq_clo_s clo = {
		.ite = &ite_p1,
		.nite = 1,
		.altite = NULL,
		.naltite = 0,
		.ss = 0,
		.dir = 0,
		.flags = 0,
	};

	if (yuck_parse(argi, argc, argv)) {
		rc = 1;
		goto out;
	}
	/* assign ofmt/ifmt */
	ofmt = argi->format_arg;
	if (argi->backslash_escapes_flag) {
		dt_io_unescape(ofmt);
	}
	nifmt = argi->input_format_nargs;
	ifmt = argi->input_format_args;

	for (size_t i = 0; i < argi->skip_nargs; i++) {
		clo.ss = set_skip(clo.ss, argi->skip_args[i]);
	}

	if (argi->alt_inc_arg) {
		struct __strpdtdur_st_s st = __strpdtdur_st_initialiser();

		do {
			if (dt_io_strpdtdur(&st, argi->alt_inc_arg) < 0) {
				if (!argi->quiet_flag) {
					error("Error: \
cannot parse duration string `%s'", argi->alt_inc_arg);
				}
				rc = 1;
				goto out;
			}
		} while (__strpdtdur_more_p(&st));
		/* assign values */
		clo.altite = st.durs;
		clo.naltite = st.ndurs;
	}

	switch (argi->nargs) {
		struct dt_dt_s fst, lst;
	default:
		yuck_auto_help(argi);
		rc = 1;
		goto out;

	case 2:
		lst = dt_io_strpdt(argi->args[1U], ifmt, nifmt, NULL);
		if (dt_unk_p(lst)) {
			if (!argi->quiet_flag) {
				dt_io_warn_strpdt(argi->args[1U]);
			}
			rc = 1;
			goto out;
		} else if (UNLIKELY(lst.fix) && !argi->quiet_flag) {
			rc = 2;
		}
		/* fallthrough */
	case 1:
		fst = dt_io_strpdt(argi->args[0U], ifmt, nifmt, NULL);
		if (dt_unk_p(fst)) {
			if (!argi->quiet_flag) {
				dt_io_warn_strpdt(argi->args[0U]);
			}
			rc = 1;
			goto out;
		} else if (UNLIKELY(fst.fix) && !argi->quiet_flag) {
			rc = 2;
		}

		/* check the input arguments and do the sane thing now
		 * if it's all dates, use daisy iterator
		 * if it's all times, use sdur iterator
		 * if one of them is a dt, promote the other */
		if (dt_sandwich_only_d_p(fst)) {
			/* emulates old dseq(1) */
			if (argi->nargs == 1U) {
				lst.d = dt_date(DT_YMD);
				dt_make_d_only(&lst, DT_YMD);
			}

			dt_make_d_only(clo.ite, DT_DAISY);
			clo.ite->d.daisy = 1;
		} else if (dt_sandwich_only_t_p(fst)) {
			/* emulates old tseq(1) */
			if (argi->nargs == 1U) {
				lst.t = dt_time();
				dt_make_t_only(&lst, DT_HMS);
			}
			/* let the guesser do the work */
			clo.ite->t.sdur = 0;
		} else if (dt_sandwich_p(fst)) {
			if (argi->nargs == 1U) {
				lst = dt_datetime((dt_dttyp_t)DT_YMD);
				dt_make_sandwich(&lst, DT_YMD, DT_HMS);
			}

			dt_make_sandwich(clo.ite, DT_DAISY, DT_TUNK);
			clo.ite->d.daisy = 1;
		} else {
			error("\
don't know how to handle single argument case");
			rc = 1;
			goto out;
		}

		clo.fst = fst;
		clo.lst = lst;
		clo.ite->dur = 1;
		break;
	case 3: {
		struct __strpdtdur_st_s st = __strpdtdur_st_initialiser();

		/* get lower bound */
		fst = dt_io_strpdt(argi->args[0U], ifmt, nifmt, NULL);
		if (dt_unk_p(fst)) {
			if (!argi->quiet_flag) {
				dt_io_warn_strpdt(argi->args[0U]);
			}
			rc = 1;
			goto out;
		} else if (UNLIKELY(fst.fix) && !argi->quiet_flag) {
			rc = 2;
		}

		/* get increment */
		do {
			if (dt_io_strpdtdur(&st, argi->args[1U]) < 0) {
				error("Error: \
cannot parse duration string `%s'", argi->args[1U]);
				rc = 1;
				goto out;
			}
		} while (__strpdtdur_more_p(&st));
		/* assign values */
		clo.ite = st.durs;
		clo.nite = st.ndurs;
		clo.flags |= CLO_FL_FREE_ITE;

		/* get upper bound */
		lst = dt_io_strpdt(argi->args[2U], ifmt, nifmt, NULL);
		if (dt_unk_p(lst)) {
			if (!argi->quiet_flag) {
				dt_io_warn_strpdt(argi->args[2U]);
			}
			rc = 1;
			goto out;
		} else if (UNLIKELY(lst.fix) && !argi->quiet_flag) {
			rc = 2;
		}
		clo.fst = fst;
		clo.lst = lst;
		break;
	}
	}

	/* promote the args maybe */
	if ((dt_sandwich_only_d_p(clo.fst) && dt_sandwich_only_t_p(clo.lst)) ||
	    (dt_sandwich_only_t_p(clo.fst) && dt_sandwich_only_d_p(clo.lst))) {
		error("\
cannot mix dates and times as arguments");
		rc = 1;
		goto out;
	} else if (dt_sandwich_only_d_p(clo.fst) && dt_sandwich_p(clo.lst)) {
		/* promote clo.fst */
		clo.fst.t = clo.lst.t;
		dt_make_sandwich(&clo.fst, clo.fst.d.typ, clo.lst.t.typ);
	} else if (dt_sandwich_p(clo.fst) && dt_sandwich_only_d_p(clo.lst)) {
		/* promote clo.lst */
		clo.lst.t = clo.fst.t;
		dt_make_sandwich(&clo.lst, clo.lst.d.typ, clo.fst.t.typ);
	} else if (dt_sandwich_only_t_p(clo.fst) && dt_sandwich_p(clo.lst)) {
		/* promote clo.fst */
		clo.fst.d = clo.lst.d;
		dt_make_sandwich(&clo.fst, clo.fst.d.typ, clo.lst.t.typ);
	} else if (dt_sandwich_p(clo.fst) && dt_sandwich_only_t_p(clo.lst)) {
		/* promote clo.lst */
		clo.lst.d = clo.fst.d;
		dt_make_sandwich(&clo.lst, clo.lst.d.typ, clo.fst.t.typ);
	}

#define _DAISY	((dt_dttyp_t)DT_DAISY)
	tgttyp = clo.fst.typ;
	if ((dt_sandwich_p(clo.fst) || dt_sandwich_only_d_p(clo.fst)) &&
	    clo.fst.d.typ == DT_YMD && clo.fst.d.ymd.m == 0) {
		/* iterate year-wise */
		dt_make_d_only(clo.ite, DT_YMD);
		clo.ite->d.ymd.y = 1;
		clo.ite->d.ymd.m = 0;
		clo.ite->d.ymd.d = 0;
	} else if ((dt_sandwich_p(clo.fst) || dt_sandwich_only_d_p(clo.fst)) &&
		   clo.fst.d.typ == DT_YMD && clo.fst.d.ymd.d == 0) {
		/* iterate month-wise */
		dt_make_d_only(clo.ite, DT_YMD);
		clo.ite->d.ymd.y = 0;
		clo.ite->d.ymd.m = 1;
		clo.ite->d.ymd.d = 0;
	} else if (dt_sandwich_only_d_p(clo.fst) &&
		   __daisy_feasible_p(clo.ite, clo.nite) &&
		   clo.fst.d.typ == DT_YMD &&
		   /* convert to daisies */
		   ((clo.fst = dt_dtconv(_DAISY, clo.fst)).d.typ != DT_DAISY ||
		    (clo.lst = dt_dtconv(_DAISY, clo.lst)).d.typ != DT_DAISY)) {
		if (!argi->quiet_flag) {
			error("\
cannot convert calendric system internally");
		}
		rc = 1;
		goto out;
	} else if (dt_sandwich_only_t_p(clo.fst) && clo.ite->t.sdur == 0) {
		clo.ite->t = tseq_guess_ite(clo.fst.t, clo.lst.t);
	}

	if (__durstack_naught_p(clo.ite, clo.nite) ||
	    (clo.dir = __get_dir(clo.fst, &clo)) == 0) {
		if (!argi->quiet_flag) {
			error("\
increment must not be naught");
		}
		rc = 1;
		goto out;
	} else if (argi->compute_from_last_flag) {
		tmp = __fixup_fst(&clo);
	} else {
		tmp = __seq_this(clo.fst, &clo);
	}

	for (; __in_range_p(tmp, &clo); tmp = __seq_next(tmp, &clo)) {
		struct dt_dt_s tgt = tmp;

		if (UNLIKELY(ofmt == NULL)) {
			tgt = dt_dtconv(tgttyp, tmp);
		}
		dt_io_write(tgt, ofmt, NULL, '\n');
	}

out:
	/* free strpdur resources */
	if (clo.ite && clo.flags & CLO_FL_FREE_ITE) {
		free(clo.ite);
	}
	if (clo.altite != NULL) {
		free(clo.altite);
	}
	yuck_free(argi);
	return rc;
}

/* dseq.c ends here */
dateutils-0.3.1/src/dseq.yuck000066400000000000000000000066041241477753400161550ustar00rootroot00000000000000Usage: dseq [OPTION]... FIRST [[INCREMENT] LAST]

Generate a sequence of date/times from FIRST to LAST, optionally in steps of
INCREMENT (which defaults to `1d').

If LAST is omitted it defaults to `now' if FIRST is a date/time, or `today' if
FIRST is a date, or `time' if FIRST is a time.

The values of FIRST and LAST are always inclusive and no date/times before
FIRST and no date/times after LAST will be printed.

Negative INCREMENTs must be given, i.e. if FIRST is newer than LAST.

  -h, --help                 Print help and exit
  -V, --version              Print version and exit
  -q, --quiet                Suppress message about date/time and duration
                             parser errors and fix-ups.
                             The default is to print a warning or the
                             fixed up value and return error code 2.
  -f, --format=STRING        Output format.  This can either be a specifier
                               string (similar to strftime()'s FMT) or the name
                               of a calendar.
  -i, --input-format=STRING...  Input format, can be used multiple times.
                               Each date/time will be passed to the input
                               format parsers in the order they are given, if a
                               date/time can be read successfully with a given
                               input format specifier string, that value will
                               be used.
  -e, --backslash-escapes    Enable interpretation of backslash escapes in the
                               output and input format specifier strings.
  -s, --skip=STRING...          Skip weekdays specified by STRING.
                               STRING can be a single weekday (Mon, Tue, etc.),
                               and to skip several days the --skip option can
                               be used multiple times.
                               STRING can also be a comma-separated list of
                               weekday names, or `ss' to skip weekends
                               (sat+sun) altogether.
                               STRING can also contain date ranges like `mo-we'
                               for monday to wednesday.
      --alt-inc=STRING       Alternative increment to use when a date is hit
                               that is skipped as per --skip.
                               This increment will be applied until a
                               non-skipped date is reached.
                               The special case `0' (default) deactivates
                               alternative incrementing.  A useful value could
                               be `1d' for increasing sequences and `-1d' for
                               decreasing sequences, so if a skipped date is
                               encountered the next non-skipped date
                               after/before will be used.
      --compute-from-last    Compute a start value from LAST using INCREMENT.
                               This option has an effect only when INCREMENT is
                               not a divisor of the duration between FIRST and
                               LAST.  In such case, an alternative FIRST will
                               be computed by consecutively subtracting
                               INCREMENT from LAST until FIRST is hit or
                               crossed.
dateutils-0.3.1/src/dsort.c000066400000000000000000000171031241477753400156170ustar00rootroot00000000000000/*** dsort.c -- sort FILEs or stdin chronologically
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "dt-core.h"
#include "dt-io.h"
#include "prchunk.h"

const char *prog = "dsort";

struct prln_ctx_s {
	struct grep_atom_soa_s *ndl;
	zif_t fromz;
	int outfd;
};

struct sort_ctx_s {
	unsigned int revp:1U;
	unsigned int unqp:1U;
};


static void
safe_write(int fd, const char *buf, size_t bsz)
{
	size_t tot = 0U;
	for (ssize_t nwr;
	     tot < bsz && (nwr = write(fd, buf + tot, bsz - tot)) >= 0;
	     tot += nwr);
	return;
}

static void
proc_line(struct prln_ctx_s ctx, char *line, size_t llen)
{
	struct dt_dt_s d;

	do {
		char buf[64U];
		char *sp, *tp;
		char *bp = buf;
		const char *const ep = buf + sizeof(buf);

		/* find first occurrence then */
		d = dt_io_find_strpdt2(line, ctx.ndl, &sp, &tp, ctx.fromz);
		/* print line, first thing */
		safe_write(ctx.outfd, line, llen);

		/* extend by separator */
		*bp++ = '\001';
		/* check if line matches */
		if (!dt_unk_p(d)) {
			/* match! */
			if (!dt_sandwich_only_t_p(d)) {
				bp += dt_strfdt(bp, ep - bp, "%F", d);
			}
			*bp++ = '\001';
			if (!dt_sandwich_only_d_p(d)) {
				bp += dt_strfdt(bp, ep - bp, "%T", d);
			}
		} else {
			/* just two empty fields then, innit? */
			*bp++ = '\001';
		}
		/* finalise the line and print */
		*bp++ = '\n';
		safe_write(ctx.outfd, buf, bp - buf);
	} while (0);
	return;
}

static int
proc_file(struct prln_ctx_s prln, const char *fn)
{
	size_t lno = 0;
	void *pctx;
	int fd;

	if (fn == NULL) {
		/* stdin then innit */
		fd = STDIN_FILENO;
	} else if ((fd = open(fn, O_RDONLY)) < 0) {
		serror("Error: cannot open file `%s'", fn);
		return -1;
	}

	/* using the prchunk reader now */
	if ((pctx = init_prchunk(fd)) == NULL) {
		serror("Error: cannot read from `%s'", fn ?: "");
		return -1;
	}

	while (prchunk_fill(pctx) >= 0) {
		for (char *line; prchunk_haslinep(pctx); lno++) {
			size_t llen = prchunk_getline(pctx, &line);

			proc_line(prln, line, llen);
		}
	}
	/* get rid of resources */
	free_prchunk(pctx);
	close(fd);
	return 0;
}


/* helper children, sort(1) and cut(1) */
static pid_t
spawn_sort(int *restrict infd, const int outfd, struct sort_ctx_s sopt)
{
	static char *cmdline[16U] = {"sort", "-t", "-k2"};
	pid_t sortp;
	/* to snarf off traffic from the child */
	int intfd[2];

	if (pipe(intfd) < 0) {
		serror("pipe setup to/from sort failed");
		return -1;
	}

	switch ((sortp = vfork())) {
	case -1:
		/* i am an error */
		serror("vfork for sort failed");
		return -1;

	default:
		/* i am the parent */
		close(intfd[0]);
		*infd = intfd[1];
		/* close outfd here already */
		close(outfd);
		return sortp;

	case 0:;
		char **cp = cmdline + 3U;

		/* i am the child */
		if (sopt.revp) {
			*cp++ = "-r";
		}
		if (sopt.unqp) {
			*cp++ = "-u";
		}
		*cp++ = NULL;

		/* stdout -> outfd */
		dup2(outfd, STDOUT_FILENO);
		/* *infd -> stdin */
		dup2(intfd[0], STDIN_FILENO);
		close(intfd[1]);

		execvp("sort", cmdline);
		serror("execvp(sort) failed");
		_exit(EXIT_FAILURE);
	}
}

static pid_t
spawn_cut(int *restrict infd)
{
	static char *const cmdline[] = {"cut", "-d", "-f1", NULL};
	pid_t cutp;
	/* to snarf off traffic from the child */
	int intfd[2];

	if (pipe(intfd) < 0) {
		serror("pipe setup to/from cut failed");
		return -1;
	}

	switch ((cutp = vfork())) {
	case -1:
		/* i am an error */
		serror("vfork for cut failed");
		return -1;

	default:;
		/* i am the parent */
		close(intfd[0]);
		*infd = intfd[1];
		return cutp;

	case 0:;
		/* i am the child */
		dup2(intfd[0], STDIN_FILENO);
		close(intfd[1]);

		execvp("cut", cmdline);
		serror("execvp(cut) failed");
		_exit(EXIT_FAILURE);
	}
}


#include "dsort.yucc"

int
main(int argc, char *argv[])
{
	yuck_t argi[1U];
	char **fmt;
	size_t nfmt;
	zif_t fromz = NULL;
	int rc = 0;
	struct sort_ctx_s sopt = {0U};

	if (yuck_parse(argi, argc, argv)) {
		rc = 1;
		goto out;
	}
	/* init and unescape sequences, maybe */
	fmt = argi->input_format_args;
	nfmt = argi->input_format_nargs;
	if (argi->backslash_escapes_flag) {
		for (size_t i = 0; i < nfmt; i++) {
			dt_io_unescape(fmt[i]);
		}
	}

	/* try and read the from and to time zones */
	if (argi->from_zone_arg) {
		fromz = dt_io_zone(argi->from_zone_arg);
	}
	if (argi->default_arg) {
		struct dt_dt_s dflt = dt_strpdt(argi->default_arg, NULL, NULL);
		dt_set_default(dflt);
	}

	/* prepare a mini-argi for the sort invocation */
	if (argi->reverse_flag) {
		sopt.revp = 1U;
	}
	if (argi->unique_flag) {
		sopt.unqp = 1U;
	}

	{
		/* process all files */
		struct grep_atom_s __nstk[16], *needle = __nstk;
		size_t nneedle = countof(__nstk);
		struct grep_atom_soa_s ndlsoa;
		struct prln_ctx_s prln = {
			.ndl = &ndlsoa,
			.fromz = fromz,
		};
		pid_t cutp, sortp;

		/* lest we overflow the stack */
		if (nfmt >= nneedle) {
			/* round to the nearest 8-multiple */
			nneedle = (nfmt | 7) + 1;
			needle = calloc(nneedle, sizeof(*needle));
		}
		/* and now build the needles */
		ndlsoa = build_needle(needle, nneedle, fmt, nfmt);

		/* spawn children */
		with (int ifd, ofd) {
			if ((cutp = spawn_cut(&ifd)) < 0) {
				goto ndl_free;
			}
			if ((sortp = spawn_sort(&ofd, ifd, sopt)) < 0) {
				goto ndl_free;
			}
			prln.outfd = ofd;
		}

		for (size_t i = 0U; i < argi->nargs || i == 0U; i++) {
			if (proc_file(prln, argi->args[i]) < 0) {
				rc = 1;
			}
		}

		/* indicate we're no longer writing to the sort helper */
		close(prln.outfd);

		/* wait for sort first */
		with (int st) {
			while (waitpid(sortp, &st, 0) != sortp);
			if (WIFEXITED(st) && WEXITSTATUS(st)) {
				rc = rc ?: WEXITSTATUS(st);
			}
		}
		/* wait for cut then */
		with (int st) {
			while (waitpid(cutp, &st, 0) != cutp);
			if (WIFEXITED(st) && WEXITSTATUS(st)) {
				rc = rc ?: WEXITSTATUS(st);
			}
		}

	ndl_free:
		if (needle != __nstk) {
			free(needle);
		}
	}

	dt_io_clear_zones();

out:
	yuck_free(argi);
	return rc;
}

/* dsort.c ends here */
dateutils-0.3.1/src/dsort.yuck000066400000000000000000000031431241477753400163470ustar00rootroot00000000000000Usage: dsort [OPTION]... [FILE]...

Sort contents of FILE chronologically.
If FILE is omitted read from stdin.

The first date/time value per line is the sort key.  Dates without times
account for a smaller value than any date/time on the same day.  Times
without dates account for a smaller value than any date or date/time.
If a line contains no dates or times or date/times it is sorted towards
the front.

  -h, --help                 Print help and exit
  -V, --version              Print version and exit
  -i, --input-format=STRING...  Input format, can be used multiple times.
                               Each date/time will be passed to the input
                               format parsers in the order they are given, if a
                               date/time can be read successfully with a given
                               input format specifier string, that value will
                               be used.
      --default=DT           For underspecified input use DT as a fallback to
                               fill in missing fields.  Must be a date/time in
                               ISO8601 format.  If omitted the default value is
                               the current date/time.
  -e, --backslash-escapes    Enable interpretation of backslash escapes in the
                               input format specifier strings.
      --from-zone=ZONE       Interpret dates on stdin or the command line as
                               coming from the time zone ZONE.

  -r, --reverse              Reverse the sort order.
  -u, --unique               Print at most one line per date/time value.dateutils-0.3.1/src/dt-io-zone.c000066400000000000000000000110411241477753400164440ustar00rootroot00000000000000/*** dt-io-zone.c -- abstract from raw zone interface
 *
 * Copyright (C) 2010-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/
#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include "tzmap.h"
#include "dt-io.h"
#include "dt-io-zone.h"
#include "alist.h"

#if defined TZMAP_DIR
static const char tmdir[] = TZMAP_DIR;
#else  /* !TZMAP_DIR */
static const char tmdir[] = ".";
#endif	/* TZMAP_DIR */
#define TZMAP_SUF	".tzmcc"

static size_t
xstrlncpy(char *restrict dst, size_t dsz, const char *src, size_t ssz)
{
	if (ssz > dsz) {
		ssz = dsz - 1U;
	}
	memcpy(dst, src, ssz);
	dst[ssz] = '\0';
	return ssz;
}

static size_t
xstrlcpy(char *restrict dst, const char *src, size_t dsz)
{
	size_t ssz = strlen(src);
	if (ssz > dsz) {
		ssz = dsz - 1U;
	}
	memcpy(dst, src, ssz);
	dst[ssz] = '\0';
	return ssz;
}


/* extended zone handling, tzmaps and stuff */
#if !defined PATH_MAX
# define PATH_MAX	256U
#endif	/* !PATH_MAX */

static struct alist_s zones[1U];
static struct alist_s tzmaps[1U];

static tzmap_t
find_tzmap(const char *mnm, size_t mnz)
{
	static const char tzmap_suffix[] = TZMAP_SUF;
	char tzmfn[PATH_MAX];
	char *tp = tzmfn;
	size_t tz = sizeof(tzmfn);
	const char *p;
	size_t z;

	/* prefer TZMAP_DIR */
	if ((p = getenv("TZMAP_DIR")) != NULL) {
		z = xstrlcpy(tp, p, tz);
	} else {
		z = xstrlncpy(tp, tz, tmdir, sizeof(tmdir) - 1U);
	}
	tp += z, tz -= z;
	*tp++ = '/', tz--;

	/* try and find it the hard way */
	xstrlncpy(tp, tz, mnm, mnz);
	tp += mnz, tz -= mnz;
	xstrlncpy(tp, tz, tzmap_suffix, sizeof(tzmap_suffix) - 1U);

	/* try and open the thing, then try and look up SPEC */
	return tzm_open(tzmfn);
}

static zif_t
__io_zone(const char *spec)
{
	zif_t res;

	/* try looking up SPEC first */
	if ((res = alist_assoc(zones, spec)) == NULL) {
		/* open 'im */
		if ((res = zif_open(spec)) != NULL) {
			/* cache 'im */
			alist_put(zones, spec, res);
		}
	}
	return res;
}

zif_t
dt_io_zone(const char *spec)
{
	char *p;

	if (spec == NULL) {
		/* safety net */
		return NULL;
	}
	/* see if SPEC is a MAP:KEY */
	if ((p = strchr(spec, ':')) != NULL) {
		char tzmfn[PATH_MAX];
		tzmap_t tzm;

		xstrlncpy(tzmfn, sizeof(tzmfn), spec, p - spec);

		/* check tzmaps alist first */
		if ((tzm = alist_assoc(tzmaps, tzmfn)) != NULL) {
			;
		} else if ((tzm = find_tzmap(tzmfn, p - spec)) != NULL) {
			/* cache the instance */
			alist_put(tzmaps, tzmfn, tzm);
		} else {
			error("\
Cannot find `%s" TZMAP_SUF "' in the tzmaps search path\n\
Set TZMAP_DIR environment variable to where " TZMAP_SUF " files reside", tzmfn);
			return NULL;
		}
		/* look up key bit in tzmap and use that if found */
		if ((spec = tzm_find(tzm, ++p)) == NULL) {
			return NULL;
		}
	}
	return __io_zone(spec);
}

void
dt_io_clear_zones(void)
{
	if (tzmaps->data != NULL) {
		for (acons_t c; (c = alist_next(tzmaps)).val;) {
			tzm_close(c.val);
		}
		free_alist(tzmaps);
	}
	if (zones->data != NULL) {
		for (acons_t c; (c = alist_next(zones)).val;) {
			zif_close(c.val);
		}
		free_alist(zones);
	}
	return;
}

/* dt-io-zone.c ends here */
dateutils-0.3.1/src/dt-io-zone.h000066400000000000000000000035341241477753400164610ustar00rootroot00000000000000/*** dt-io-zone.h -- abstract from raw zone interface
 *
 * Copyright (C) 2009-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/
#if !defined INCLUDED_dt_io_zone_h_
#define INCLUDED_dt_io_zone_h_

#include "tzraw.h"

extern zif_t dt_io_zone(const char *spec);

extern void dt_io_clear_zones(void);

#endif	/* INCLUDED_dt_io_zone_h_ */
dateutils-0.3.1/src/dt-io.c000066400000000000000000000371761241477753400155140ustar00rootroot00000000000000#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#if defined __GLIBC__
/* for *_unlocked protos */
# include 
#endif	/* __GLIBC__ */
/* for strstr() */
#include 
/* for strcasecmp() */
#include 
#include 
#include 
#include "dt-core.h"
#include "dt-core-tz-glue.h"
#include "date-core-private.h"
#include "tzraw.h"
#include "tzmap.h"
#include "strops.h"
#include "token.h"
#include "nifty.h"
#include "dt-io.h"
#include "alist.h"

#if defined __INTEL_COMPILER
/* we MUST return a char* */
# pragma warning (disable:2203)
#elif defined __GNUC__
# pragma GCC diagnostic ignored "-Wcast-qual"
#endif	/* __INTEL_COMPILER */


/* our own perror() implementation */
void
__attribute__((format(printf, 1, 2)))
error(const char *fmt, ...)
{
	va_list vap;
	va_start(vap, fmt);
	fputs(prog, stderr);
	fputs(": ", stderr);
	vfprintf(stderr, fmt, vap);
	va_end(vap);
	fputc('\n', stderr);
	return;
}

void
__attribute__((format(printf, 1, 2)))
serror(const char *fmt, ...)
{
	va_list vap;
	va_start(vap, fmt);
	fputs(prog, stderr);
	fputs(": ", stderr);
	vfprintf(stderr, fmt, vap);
	va_end(vap);
	if (errno) {
		fputc(':', stderr);
		fputc(' ', stderr);
		fputs(strerror(errno), stderr);
	}
	fputc('\n', stderr);
	return;
}


#include "strpdt-special.c"

dt_strpdt_special_t
dt_io_strpdt_special(const char *str)
{
	size_t len = strlen(str);
	const struct dt_strpdt_special_s *res;

	if (UNLIKELY((res = __strpdt_special(str, len)) != NULL)) {
		return res->e;
	}
	return STRPDT_UNK;
}

struct dt_dt_s
dt_io_strpdt_ep(
	const char *str,
	const char *const *fmt, size_t nfmt, char **ep,
	zif_t zone)
{
	struct dt_dt_s res = dt_dt_initialiser();
	dt_strpdt_special_t now;

	/* init */
	if (ep != NULL) {
		*ep = NULL;
	}
	/* basic sanity checks, catch phrases first */
	now = dt_io_strpdt_special(str);

	if (now > STRPDT_UNK) {
		res = dt_datetime((dt_dttyp_t)DT_YMD);
		/* rinse according to flags */
		switch (now) {
			signed int add;
		case STRPDT_TOMO:
			add = 1;
			goto date;
		case STRPDT_YDAY:
			add = -1;
			goto date;
		case STRPDT_DATE:
			add = 0;
		date:
			res.t = dt_t_initialiser();
			dt_make_d_only(&res, res.d.typ);
			if (add) {
				res.d = dt_dadd(res.d, dt_make_daisydur(add));
			}
			break;
		case STRPDT_TIME:
			res.d = dt_d_initialiser();
			dt_make_t_only(&res, res.t.typ);
			break;
		case STRPDT_NOW:
		case STRPDT_UNK:
		default:
			break;
		}
		return res;
	} else if (nfmt == 0) {
		res = dt_strpdt(str, NULL, ep);
	} else {
		for (size_t i = 0; i < nfmt; i++) {
			if (!dt_unk_p(res = dt_strpdt(str, fmt[i], ep))) {
				break;
			}
		}
	}
	if (LIKELY(!dt_unk_p(res)) && zone != NULL && !res.znfxd) {
		return dtz_forgetz(res, zone);
	}
	return res;
}

struct dt_dt_s
dt_io_find_strpdt(
	const char *str, char *const *fmt, size_t nfmt,
	const char *needle, size_t needlen, char **sp, char **ep,
	zif_t zone)
{
	const char *__sp = str;
	struct dt_dt_s d = dt_dt_initialiser();
	const char *const *cfmt = (const char*const*)fmt;

	d = dt_io_strpdt_ep(__sp, cfmt, nfmt, ep, zone);
	if (dt_unk_p(d)) {
		while ((__sp = strstr(__sp, needle)) &&
		       (d = dt_io_strpdt_ep(
				__sp += needlen, cfmt, nfmt, ep, zone),
			dt_unk_p(d)));
	}
	*sp = (char*)__sp;
	return d;
}

struct dt_dt_s
dt_io_find_strpdt2(
	const char *str,
	const struct grep_atom_soa_s *needles,
	char **sp, char **ep,
	zif_t zone)
{
	struct dt_dt_s d = dt_dt_initialiser();
	const char *needle = needles->needle;
	const char *p = str;

	for (; *(p = xstrpbrk(p, needle)); p++) {
		/* find the offset */
		const struct grpatm_payload_s *fp;
		const char *np;

		for (np = needle, fp = needles->flesh; *np < *p; np++, fp++);

		/* nc points to the first occurrence of *p in needle,
		 * f is the associated grpatm payload */
		while (*np++ == *p) {
			const struct grpatm_payload_s f = *fp++;
			const char *fmt = f.fmt;
			const char *q = p + f.off_min;
			const char *r = p + f.off_max;

			if (UNLIKELY(q < str)) {
				q = str;
			}

			for (; *q && q <= r; q++) {
				if (!dt_unk_p(d = dt_strpdt(q, fmt, ep))) {
					p = q;
					goto found;
				}
			}
		}
	}
	/* otherwise check character classes */
	for (size_t i = 0; needle[i] == GRPATM_NEEDLELESS_MODE_CHAR; i++) {
		struct grpatm_payload_s f = needles->flesh[i];
		const char *fmt = f.fmt;
		const char *ndl;

		/* look out for char classes*/
		switch (f.flags) {
			/* this isn't the bestest of approaches as it involves
			 * details about the contents behind the specifiers */
			static const char a_needle[] = "FMSTWfmstw";
			static const char ta_needle[] = "MTWRFAS";
			static const char b_needle[] = "ADFJMNOSadfjmnos";
			static const char tb_needle[] = "FGHJKMNQUVXZ";
			static const char o_needle[] = "CDILMVXcdilmvx";
		case GRPATM_A_SPEC:
			ndl = a_needle;
			break;
		case GRPATM_B_SPEC:
			ndl = b_needle;
			break;
		case GRPATM_TINY_A_SPEC:
			ndl = ta_needle;
			break;
		case GRPATM_TINY_B_SPEC:
			ndl = tb_needle;
			break;
		case GRPATM_O_SPEC:
			ndl = o_needle;
			break;

		case GRPATM_DIGITS:
			/* yay, look for all digits */
			for (p = str; *p && !(*p >= '0' && *p <= '9'); p++);
			for (const char *q = p;
			     *q && *q >= '0' && *q <= '9'; q++) {
				if ((--f.off_min <= 0) &&
				    !dt_unk_p(d = dt_strpdt(p, fmt, ep))) {
					goto found;
				}
			}
			continue;

		case GRPATM_DIGITS | GRPATM_ORDINALS:
			/* yay, look for all digits and ordinals */
			for (p = str; *p && !(*p >= '0' && *p <= '9'); p++);
			for (const char *q = p; *q; q++) {
				switch (*q) {
				case '0' ... '9':
					break;
				case 't':
					if (*++q == 'h') {
						break;
					}
					goto bugger;
				case 's':
					if (*++q == 't') {
						break;
					}
					goto bugger;
				case 'n':
				case 'r':
					if (*++q == 'd') {
						break;
					}
					goto bugger;
				default:
					goto bugger;
				}
				if ((--f.off_min <= 0) &&
				    !dt_unk_p(d = dt_strpdt(p, fmt, ep))) {
					goto found;
				}
			}
		bugger:
		default:
			continue;
		}
		/* not reached unless ndl is set */
		for (p = str; *(p = xstrpbrk(p, ndl)); p++) {
			if (p + f.off_min < str /*|| p + f.off_max > ?*/) {
				continue;
			}
			for (int8_t j = f.off_min; j <= f.off_max; j++) {
				if (!dt_unk_p(d = dt_strpdt(p + j, fmt, ep))) {
					p += j;
					goto found;
				}
			}
		}
	}
	/* reset to some sane defaults */
	*ep = (char*)(p = str);
found:
	*sp = (char*)p;
	if (LIKELY(!dt_unk_p(d)) && zone != NULL) {
		return dtz_forgetz(d, zone);
	}
	return d;
}

int
dt_io_write(struct dt_dt_s d, const char *fmt, zif_t zone, int apnd_ch)
{
	static char buf[256];
	size_t n;

	if (zone != NULL) {
		d = dtz_enrichz(d, zone);
	} else {
		/* zone == NULL is UTC, kill zdiff */
		d.zdiff = 0U;
		d.neg = 0U;
	}
	n = dt_io_strfdt(buf, sizeof(buf), fmt, d, apnd_ch);
	__io_write(buf, n, stdout);
	return (n > 0) - 1;
}


/* needles for the grep mode */
struct grep_atom_s
calc_grep_atom(const char *fmt)
{
	struct grep_atom_s res = __grep_atom_initialiser();
	int8_t andl_idx = 0;
	int8_t bndl_idx = 0;
	int8_t pndl_idx = 0;

	/* init */
	if (fmt == NULL) {
	dstd:
		/* standard format, %Y-%m-%d */
		res.needle = '-';
		res.pl.off_min = -4;
		res.pl.off_max = -4;
		goto out;
	tstd:
		/* standard format, %H:%M:%S */
		res.needle = ':';
		res.pl.off_min = -2;
		res.pl.off_max = -1;
		goto out;
	} else {
		/* try and transform shortcuts */
		switch (__trans_dfmt(&fmt)) {
		default:
			break;
		case DT_LDN:
		case DT_JDN:
			/* there's no format specifiers for lilian/julian */
			res.pl.off_min += -10;
			res.pl.off_max += -1;
			res.pl.flags |= GRPATM_DIGITS;
			goto post_snarf;
		}
	}

	/* rest here ... */
	for (const char *fp = fmt; *fp;) {
		const char *fp_sav = fp;
		struct dt_spec_s spec = __tok_spec(fp_sav, &fp);

		/* pre checks */
		switch (spec.spfl) {
		case DT_SPFL_S_WDAY:
			res.pl.flags |= GRPATM_A_SPEC;
			if (res.pl.off_min == res.pl.off_max) {
				andl_idx = res.pl.off_min;
			}
			break;
		case DT_SPFL_S_MON:
			res.pl.flags |= GRPATM_B_SPEC;
			if (res.pl.off_min == res.pl.off_max) {
				bndl_idx = res.pl.off_min;
			}
			break;
		case DT_SPFL_S_AMPM:
			res.pl.flags |= GRPATM_P_SPEC;
			if (res.pl.off_min == res.pl.off_max) {
				pndl_idx = res.pl.off_min;
			}
			break;
		default:
			break;
		}
		if (spec.ord) {
			/* account for the extra 2 letters, but they're
			 * optional now, so don't fiddle with the max bit */
			res.pl.off_min -= 2;
			res.pl.flags |= GRPATM_ORDINALS;
		}
#if 0
		if (spec.bizda) {
			/* account for the extra suffix character, it's
			 * optional again */
			res.pl.off_min -= 1;
			res.pl.flags |= GRPATM_SUFFIX;
		}
#endif
		switch (spec.spfl) {
		case DT_SPFL_UNK:
			/* found a non-spec character that can be
			 * used as needle, we should check for the
			 * character's suitability though, a space is not
			 * the best needle to find in a haystack of
			 * english text, in fact it's more like a haystack
			 * itself */
			res.needle = *fp_sav;
			goto out;
		case DT_SPFL_LIT_PERCENT:
			/* very good needle character methinks */
			res.needle = '%';
			goto out;
		case DT_SPFL_LIT_NL:
			/* quite good needle characters */
			res.needle = '\n';
			goto out;
		case DT_SPFL_LIT_TAB:
			res.needle = '\t';
			goto out;
		case DT_SPFL_N_DSTD:
			goto dstd;
		case DT_SPFL_N_TSTD:
			goto tstd;
		case DT_SPFL_N_YEAR:
			if (spec.abbr != DT_SPMOD_ABBR) {
				res.pl.off_min += -4;
				res.pl.off_max += -4;
			} else {
				res.pl.off_min += -2;
				res.pl.off_max += -2;
			}
			res.pl.flags |= GRPATM_DIGITS;
			break;
		case DT_SPFL_N_MON:
		case DT_SPFL_N_DCNT_WEEK:
		case DT_SPFL_N_DCNT_MON:
		case DT_SPFL_N_WCNT_MON:
		case DT_SPFL_N_WCNT_YEAR:
		case DT_SPFL_N_QTR:
		case DT_SPFL_N_HOUR:
		case DT_SPFL_N_MIN:
		case DT_SPFL_N_SEC:
			res.pl.off_min += -2;
			res.pl.off_max += -1;
			res.pl.flags |= GRPATM_DIGITS;
			break;
		case DT_SPFL_S_WDAY:
			if (spec.abbr == DT_SPMOD_LONG) {
				/* Wednesday */
				res.pl.off_min += -9;
				/* Friday */
				res.pl.off_max += -6;
				break;
			}
		case DT_SPFL_S_MON:
			if (spec.abbr == DT_SPMOD_LONG) {
				/* September */
				res.pl.off_min += -9;
				/* May */
				res.pl.off_max += -3;
				break;
			}
			switch (spec.abbr) {
			case DT_SPMOD_NORM:
				res.pl.off_min += -3;
				res.pl.off_max += -3;
				break;
			case DT_SPMOD_ABBR:
				res.pl.off_min += -1;
				res.pl.off_max += -1;
				res.pl.flags |= GRPATM_T_FLAG;
				break;
			default:
				break;
			}
			break;
		case DT_SPFL_N_DCNT_YEAR:
			res.pl.off_min += -3;
			res.pl.off_max += -1;
			res.pl.flags |= GRPATM_DIGITS;
			break;
		case DT_SPFL_S_QTR:
			res.needle = 'Q';
			goto out;
		case DT_SPFL_S_AMPM:
			res.pl.off_min += -2;
			res.pl.off_max += -2;
			break;

		case DT_SPFL_N_EPOCH:
			res.pl.off_min += -10;
			res.pl.off_max += -1;
			res.pl.flags |= GRPATM_DIGITS;
			break;
		default:
			break;
		}
	}

post_snarf:
	if (res.needle == 0 && (res.pl.off_min || res.pl.off_max)) {
		if ((res.pl.flags & ~(GRPATM_DIGITS | GRPATM_ORDINALS)) == 0) {
			/* ah, only digits, thats good */
			int8_t tmp = (int8_t)-res.pl.off_min;

			/* swap-invert min and max */
			res.pl.off_min = (int8_t)-res.pl.off_max;
			res.pl.off_max = tmp;
			/* use a needle that is unlikely to occur and
			 * that will bubble to the front of the needlestack */
			res.needle = GRPATM_NEEDLELESS_MODE_CHAR;
			goto out;
		} else if (res.pl.flags & GRPATM_A_SPEC) {
			res.needle = GRPATM_NEEDLELESS_MODE_CHAR;
			res.pl.off_min = res.pl.off_max = andl_idx;
			res.pl.flags = GRPATM_A_SPEC;
			goto out;
		} else if (res.pl.flags & GRPATM_B_SPEC) {
			res.needle = GRPATM_NEEDLELESS_MODE_CHAR;
			res.pl.off_min = res.pl.off_max = bndl_idx;
			res.pl.flags = GRPATM_B_SPEC;
			goto out;
		} else if (res.pl.flags & GRPATM_O_SPEC) {
			res.needle = GRPATM_NEEDLELESS_MODE_CHAR;
		} else if (res.pl.flags & GRPATM_P_SPEC) {
			res.needle = GRPATM_NEEDLELESS_MODE_CHAR;
			res.pl.off_min = res.pl.off_max = pndl_idx;
			res.pl.flags = GRPATM_P_SPEC;
			goto out;
		}
	}
	/* naught flags mean the usual needle char search */
	res.pl.flags = 0;
out:
	/* finally assign the format */
	if (res.needle || res.pl.flags) {
		res.pl.fmt = fmt;
	}
	return res;
}

struct grep_atom_soa_s
build_needle(grep_atom_t atoms, size_t natoms, char *const *fmt, size_t nfmt)
{
	struct grep_atom_soa_s res = make_grep_atom_soa(atoms, natoms);
	struct grep_atom_s a;

	if (nfmt == 0) {
		/* inject the standard needles for %F and %T */
		size_t idx;

		/* standard format %F */
		idx = res.natoms++;
		res.needle[idx] = '-';
		res.flesh[idx].off_min = -4;
		res.flesh[idx].off_max = -4;
		res.flesh[idx].fmt = NULL;

		/* standard format, %T */
		idx = res.natoms++;
		res.needle[idx] = ':';
		res.flesh[idx].off_min = -2;
		res.flesh[idx].off_max = -1;
		res.flesh[idx].fmt = NULL;
		goto out;
	}
	/* otherwise collect needles from all formats */
	for (size_t i = 0; i < nfmt && res.natoms < natoms; i++) {
		if ((a = calc_grep_atom(fmt[i])).needle) {
			const char *ndl = res.needle;
			size_t idx = res.natoms++;
			size_t j;

			/* stable insertion sort, find the slot first ... */
			for (j = 0; j < idx && ndl[j] <= a.needle; j++);
			/* ... j now points to where we insert, so move
			 * everything behind j */
			if (j < idx) {
				memmove(res.needle + j + 1, ndl + j, idx - j);
				memmove(
					res.flesh + j + 1,
					res.flesh + j,
					(idx - j) * sizeof(*res.flesh));
			}
			res.needle[j] = a.needle;
			res.flesh[j] = a.pl;
		}
	}
out:
	/* terminate needle with \0 */
	res.needle[res.natoms] = '\0';
	return res;
}

void
dt_io_unescape(char *s)
{
	static const char esc_map[] = "\a\bcd\e\fghijklm\nopq\rs\tu\v";
	char *p, *q;

	if (UNLIKELY(s == NULL)) {
		return;
	} else if ((p = q = strchr(s, '\\')) != NULL) {
		do {
			if (*p != '\\' || !*++p) {
				*q++ = *p++;
			} else if (*p < 'a' || *p > 'v') {
				*q++ = *p++;
			} else {
				*q++ = esc_map[*p++ - 'a'];
			}
		} while (*p);
		*q = '\0';
	}
	return;
}


/* duration parser */
/* we parse durations ourselves so we can cope with the
 * non-commutativity of duration addition:
 * 2000-03-30 +1m -> 2000-04-30 +1d -> 2000-05-01
 * 2000-03-30 +1d -> 2000-03-31 +1m -> 2000-04-30 */
int
__add_dur(struct __strpdtdur_st_s *st, struct dt_dt_s dur)
{
	if (dt_unk_p(dur)) {
		return -1;
	}
	if (st->durs == NULL) {
		st->durs = calloc(16, sizeof(*st->durs));
	} else if ((st->ndurs % 16) == 0) {
		st->durs = realloc(
			st->durs,
			(16 + st->ndurs) * sizeof(*st->durs));
		memset(st->durs + st->ndurs, 0, 16 * sizeof(*st->durs));
	}
	st->durs[st->ndurs++] = dur;
	return 0;
}

int
dt_io_strpdtdur(struct __strpdtdur_st_s *st, const char *str)
{
/* at the moment we allow only one format */
	const char *sp = NULL;
	const char *ep = NULL;
	int res = 0;

	/* check if we should continue */
	if (st->cont != NULL) {
		str = st->istr = st->cont;
	} else if ((st->istr = str) != NULL) {
		;
	} else {
		goto out;
	}

	/* read over signs and prefixes */
	sp = str;
	while (1) {
		switch (*sp++) {
		case '\0':
			res = -1;
			ep = sp;
			goto out;
		case '+':
			st->sign = 1;
			break;
		case '-':
			st->sign = -1;
			break;
		case '=':
			if (st->sign > 0) {
				st->sign++;
			} else if (st->sign < 0) {
				st->sign--;
			} else {
				st->sign = 0;
			}
			break;
		case '>':
			st->sign = 2;
			break;
		case '<':
			st->sign = -2;
			break;
		case 'p':
		case 'P':
		case ' ':
		case '\t':
		case '\n':
			continue;
		default:
			sp--;
			break;
		}
		break;
	}

	/* try reading the stuff with our strpdur() */
	{
		struct dt_dt_s d = dt_strpdtdur(sp, (char**)&ep);
		if ((st->sign == 1 && dt_dtdur_neg_p(d)) ||
		    (st->sign == -1 && !dt_dtdur_neg_p(d))) {
			d = dt_neg_dtdur(d);
		}
		res = __add_dur(st, d);
	}
out:
	if (((st->cont = ep) && *ep == '\0') || (sp == ep)) {
		st->sign = 0;
		st->cont = NULL;
	}
	return res;
}

#if defined __INTEL_COMPILER
# pragma warning (default:2203)
#elif defined __GNUC__
# pragma GCC diagnostic warning "-Wcast-qual"
#endif	/* __INTEL_COMPILER */

/* dt-io.c ends here */
dateutils-0.3.1/src/dt-io.h000066400000000000000000000137041241477753400155100ustar00rootroot00000000000000/*** dt-io.h -- helper for formats, parsing, printing, escaping, etc. */
#if !defined INCLUDED_dt_io_h_
#define INCLUDED_dt_io_h_

#include 
#include 
#if defined __GLIBC__
/* for *_unlocked protos */
# include 
#endif	/* __GLIBC__ */
/* for strstr() */
#include 
/* for strcasecmp() */
#include 
#include "dt-core.h"
#include "dt-io-zone.h"
#include "nifty.h"

typedef enum {
	STRPDT_UNK,
	STRPDT_DATE,
	STRPDT_TIME,
	STRPDT_NOW,
	STRPDT_YDAY,
	STRPDT_TOMO,
} dt_strpdt_special_t;

/* needles for the grep mode */
typedef struct grep_atom_s *grep_atom_t;
typedef const struct gep_atom_s *const_grep_atom_t;

struct grpatm_payload_s {
	uint8_t flags;
#define GRPATM_DIGITS	(1)
#define GRPATM_ORDINALS	(2)
#define GRPATM_SUFFIX	(4)
#define GRPATM_A_SPEC	(8)
#define GRPATM_B_SPEC	(16)
#define GRPATM_O_SPEC	(32)
#define GRPATM_T_FLAG	(64)
#define GRPATM_P_SPEC	(128)
	int8_t off_min;
	int8_t off_max;
	const char *fmt;
};
/* combos */
#define GRPATM_TINY_A_SPEC	(GRPATM_T_FLAG | GRPATM_A_SPEC)
#define GRPATM_TINY_B_SPEC	(GRPATM_T_FLAG | GRPATM_B_SPEC)

/* atoms are maps needle-character -> payload */
struct grep_atom_s {
	/* 4 bytes it should be */
	char needle;
	struct grpatm_payload_s pl;
};

struct grep_atom_soa_s {
	size_t natoms;
	char *needle;
	struct grpatm_payload_s *flesh;
};

/* duration parser */
/* we parse durations ourselves so we can cope with the
 * non-commutativity of duration addition:
 * 2000-03-30 +1m -> 2000-04-30 +1d -> 2000-05-01
 * 2000-03-30 +1d -> 2000-03-31 +1m -> 2000-04-30 */
struct __strpdtdur_st_s {
	int sign;
	const char *istr;
	const char *cont;
	size_t ndurs;
	struct dt_dt_s *durs;
};


/* public API */
extern dt_strpdt_special_t dt_io_strpdt_special(const char *str);
extern struct dt_dt_s
dt_io_strpdt_ep(
	const char *str,
	const char *const *fmt, size_t nfmt, char **ep,
	zif_t zone);

extern struct dt_dt_s
dt_io_find_strpdt(
	const char *str, char *const *fmt, size_t nfmt,
	const char *needle, size_t needlen, char **sp, char **ep,
	zif_t zone);

extern struct dt_dt_s
dt_io_find_strpdt2(
	const char *str,
	const struct grep_atom_soa_s *needles,
	char **sp, char **ep,
	zif_t zone);

extern int
dt_io_write(struct dt_dt_s d, const char *fmt, zif_t zone, int apnd_ch);

/* grep atoms */
extern struct grep_atom_s calc_grep_atom(const char *fmt);

extern struct grep_atom_soa_s
build_needle(grep_atom_t atoms, size_t natoms, char *const *fmt, size_t nfmt);

extern void dt_io_unescape(char *s);

/* error messages, warnings, etc. */
extern __attribute__((format(printf, 1, 2))) void error(const char *fmt, ...);

/* error messages, warnings, etc. */
extern __attribute__((format(printf, 1, 2))) void serror(const char *fmt, ...);

/* for error() above, use PROG as name for the tool. */
extern const char *prog;

/* duration parser */
extern int __add_dur(struct __strpdtdur_st_s *st, struct dt_dt_s dur);
extern int dt_io_strpdtdur(struct __strpdtdur_st_s *st, const char *str);

/* zone handling, tzmaps et al. */
extern zif_t dt_io_zone(const char *spec);


/* inlines */
static inline struct dt_dt_s
dt_io_strpdt(const char *input, char *const *fmt, size_t nfmt, zif_t zone)
{
	return dt_io_strpdt_ep(input, (const char*const*)fmt, nfmt, NULL, zone);
}

/* grep atoms */
static inline __attribute__((pure, const)) struct grep_atom_s
__grep_atom_initialiser(void)
{
#if defined HAVE_SLOPPY_STRUCTS_INIT
	static const struct grep_atom_s res = {0};
#else
	static const struct grep_atom_s res;
#endif	/* HAVE_SLOPPY_STRUCTS_INIT */
	return res;
}

static inline __attribute__((pure, const)) struct grep_atom_soa_s
__grep_atom_soa_initialiser(void)
{
#if defined HAVE_SLOPPY_STRUCTS_INIT
	static const struct grep_atom_soa_s res = {0};
#else
	static const struct grep_atom_soa_s res;
#endif	/* HAVE_SLOPPY_STRUCTS_INIT */
	return res;
}

static inline struct grep_atom_soa_s
make_grep_atom_soa(grep_atom_t atoms, size_t natoms)
{
	struct grep_atom_soa_s res = __grep_atom_soa_initialiser();

	res.needle = (char*)atoms;
	res.flesh = (void*)(res.needle + natoms);
	return res;
}

#define GRPATM_NEEDLELESS_MODE_CHAR	(1)

/* formatter */
static inline size_t
dt_io_strfdt(
	char *restrict buf, size_t bsz,
	const char *fmt, struct dt_dt_s that, int apnd_ch)
{
	size_t res = dt_strfdt(buf, bsz, fmt, that);

	if (LIKELY(res > 0) && apnd_ch && buf[res - 1] != apnd_ch) {
		/* auto-newline */
		buf[res++] = (char)apnd_ch;
	}
	return res;
}


static __attribute__((unused)) size_t
__io_write(const char *line, size_t llen, FILE *where)
{
#if defined __GLIBC__
	return fwrite_unlocked(line, sizeof(*line), llen, where);
#else  /* !__GLIBC__ */
	return fwrite(line, sizeof(*line), llen, where);
#endif	/* __GLIBC__ */
}

static __attribute__((unused)) int
__io_putc(int c, FILE *where)
{
#if defined __GLIBC__
	return fputc_unlocked(c, where);
#else  /* !__GLIBC__ */
	return fputc(c, where);
#endif	/* __GLIBC__ */
}

static inline __attribute__((unused)) void
#if defined __GLIBC__
__io_setlocking_bycaller(FILE *fp)
{
	__fsetlocking(fp, FSETLOCKING_BYCALLER);
	return;
}
#else  /* !__GLIBC__ */
__io_setlocking_bycaller(__attribute__((unused)) FILE *fp)
{
	return;
}
#endif	/* __GLIBC__ */

static inline __attribute__((unused)) int
__io_eof_p(FILE *fp)
{
#if defined __GLIBC__
	return feof_unlocked(fp);
#else  /* !__GLIBC__ */
	return feof(fp);
#endif	/* __GLIBC__ */
}

static inline void
dt_io_warn_strpdt(const char *inp)
{
	error("cannot make sense of `%s' using the given input formats", inp);
	return;
}


/* duration parser */
static inline __attribute__((pure, const)) struct __strpdtdur_st_s
__strpdtdur_st_initialiser(void)
{
#if defined HAVE_SLOPPY_STRUCTS_INIT
	static const struct __strpdtdur_st_s res = {};
#else
	static const struct __strpdtdur_st_s res;
#endif	/* HAVE_SLOPPY_STRUCTS_INIT */
	return res;
}

static inline int
__strpdtdur_more_p(struct __strpdtdur_st_s *st)
{
	return st->cont != NULL;
}

static inline void
__strpdtdur_free(struct __strpdtdur_st_s *st)
{
	if (st->durs != NULL) {
		free(st->durs);
	}
	return;
}

#endif	/* INCLUDED_dt_io_h_ */
dateutils-0.3.1/src/dtest.c000066400000000000000000000064361241477753400156160ustar00rootroot00000000000000/*** dtest.c -- like test(1) but for dates
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/

#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include 
#include 
#include 

#include "dt-core.h"
#include "dt-io.h"

const char *prog = "dtest";


#include "dtest.yucc"

int
main(int argc, char *argv[])
{
	yuck_t argi[1U];
	char **ifmt;
	size_t nifmt;
	struct dt_dt_s d1, d2;
	int res = 0;

	if (yuck_parse(argi, argc, argv)) {
		res = 2;
		goto out;
	}

	if (argi->nargs != 2U) {
		yuck_auto_help(argi);
		res = 2;
		goto out;
	}

	ifmt = argi->input_format_args;
	nifmt = argi->input_format_nargs;

	if (dt_unk_p(d1 = dt_io_strpdt(argi->args[0U], ifmt, nifmt, NULL))) {
		if (!argi->quiet_flag) {
			dt_io_warn_strpdt(argi->args[0U]);
		}
		res = 2;
		goto out;
	}
	if (dt_unk_p(d2 = dt_io_strpdt(argi->args[1U], ifmt, nifmt, NULL))) {
		if (!argi->quiet_flag) {
			dt_io_warn_strpdt(argi->args[1U]);
		}
		res = 2;
		goto out;
	}

	/* just do the comparison */
	if ((res = dt_dtcmp(d1, d2)) == -2) {
		/* uncomparable */
		res = 3;
	} else if (argi->cmp_flag) {
		switch (res) {
		case 0:
			res = 0;
			break;
		case -1:
			res = 2;
			break;
		case 1:
			res = 1;
			break;
		default:
			res = 3;
			break;
		}
	} else if (argi->eq_flag) {
		res = res == 0 ? 0 : 1;
	} else if (argi->ne_flag) {
		res = res != 0 ? 0 : 1;
	} else if (argi->lt_flag || argi->ot_flag) {
		res = res == -1 ? 0 : 1;
	} else if (argi->le_flag) {
		res = res == -1 || res == 0 ? 0 : 1;
	} else if (argi->gt_flag || argi->nt_flag) {
		res = res == 1 ? 0 : 1;
	} else if (argi->ge_flag) {
		res = res == 1 || res == 0 ? 0 : 1;
	}
out:
	yuck_free(argi);
	return res;
}

/* dtest.c ends here */
dateutils-0.3.1/src/dtest.yuck000066400000000000000000000031471241477753400163430ustar00rootroot00000000000000Usage: dtest [OPTION]... DATE/TIME1 OP DATE/TIME2

Like test(1) but for dates.

  -h, --help                 Print help and exit
  -V, --version              Print version and exit
  -q, --quiet                Suppress message about date/time and duration
                               parser errors.
  -i, --input-format=STRING...  Input format, can be used multiple times.
                               Each date/time will be passed to the input
                               format parsers in the order they are given, if a
                               date/time can be read successfully with a given
                               input format specifier string, that value will
                               be used.
  -e, --backslash-escapes    Enable interpretation of backslash escapes in the
                               output and input format specifier strings.

      --eq                   DATE/TIME1 is the same as DATE/TIME2
      --ne                   DATE/TIME1 is not the same as DATE/TIME2
      --gt                   DATE/TIME1 is newer than DATE/TIME2
      --lt                   DATE/TIME1 is older than DATE/TIME2
      --ge                   DATE/TIME1 is newer than or equals DATE/TIME2
      --le                   DATE/TIME1 is older than or equals DATE/TIME2
      --nt                   DATE/TIME1 is newer than DATE/TIME2
      --ot                   DATE/TIME1 is older than DATE/TIME2
      --cmp                  compare DATE/TIME1 to DATE/TIME2, return with 0 if
                               equal, 1 if left argument was newer and 2 if
                               right argument was newer
dateutils-0.3.1/src/dzone.c000066400000000000000000000170671241477753400156140ustar00rootroot00000000000000/*** dzone.c -- convert date/times between timezones
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **/
#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include 
#include 

#include "dt-core.h"
#include "dt-io.h"
#include "dt-core-tz-glue.h"
#include "tzraw.h"

struct ztr_s {
	int32_t trns;
	int32_t offs;
};

/* fwd decld in tzraw.h */
struct ztrdtl_s {
	int32_t offs;
	uint8_t dstp;
	uint8_t abbr;
} __attribute__((packed));

const char *prog = "dzone";
static char gbuf[256U];

static const char never[] = "never";
static const char nindi[] = " -> ";
static const char pindi[] = " <- ";


static size_t
xstrlcpy(char *restrict dst, const char *src, size_t dsz)
{
	size_t ssz = strlen(src);
	if (ssz > dsz) {
		ssz = dsz - 1U;
	}
	memcpy(dst, src, ssz);
	dst[ssz] = '\0';
	return ssz;
}

static int
dz_io_write(struct dt_dt_s d, zif_t zone, const char *name)
{
	static const char fmt[] = "%FT%T%Z";
	char *restrict bp = gbuf;
	const char *const ep = gbuf + sizeof(gbuf);

	if (LIKELY(zone != NULL)) {
		d = dtz_enrichz(d, zone);
	}
	bp += dt_strfdt(bp, ep - bp, fmt, d);
	/* append name */
	if (LIKELY(name != NULL)) {
		*bp++ = '\t';
		bp += xstrlcpy(bp, name, ep - bp);
	}
	*bp++ = '\n';
	__io_write(gbuf, bp - gbuf, stdout);
	return (bp > gbuf) - 1;
}

static size_t
dz_strftr(char *restrict buf, size_t bsz, struct ztr_s t)
{
	static const char fmt[] = "%FT%T%Z";
	struct dt_dt_s d = dt_dt_initialiser();

	d.typ = DT_SEXY;
	d.sexy = t.trns + t.offs;
	if (t.offs > 0) {
		d.zdiff = (uint16_t)(t.offs / ZDIFF_RES);
	} else if (t.offs < 0) {
		d.neg = 1;
		d.zdiff = (uint16_t)(-t.offs / ZDIFF_RES);
	}
	return dt_strfdt(buf, bsz, fmt, d);
}

static int
dz_write_nxtr(struct zrng_s r, zif_t z, const char *zn)
{
	char *restrict bp = gbuf;
	const char *const ep = gbuf + sizeof(gbuf);
	size_t ntr = zif_ntrans(z);

	if (r.next == INT_MAX) {
		bp += xstrlcpy(bp, never, bp - ep);
	} else {
		bp += dz_strftr(bp, ep - bp, (struct ztr_s){r.next, r.offs});
	}
	/* append next indicator */
	bp += xstrlcpy(bp, nindi, bp - ep);
	if (r.trno + 1U < ntr) {
		/* thank god there's another one */
		struct ztrdtl_s zd = zif_trdtl(z, r.trno + 1);

		bp += dz_strftr(bp, ep - bp, (struct ztr_s){r.next, zd.offs});
	} else {
		bp += xstrlcpy(bp, never, bp - ep);
	}

	/* append name */
	if (LIKELY(zn != NULL)) {
		*bp++ = '\t';
		bp += xstrlcpy(bp, zn, ep - bp);
	}
	*bp++ = '\n';
	__io_write(gbuf, bp - gbuf, stdout);
	return (bp > gbuf) - 1;
}

static int
dz_write_prtr(struct zrng_s r, zif_t UNUSED(z), const char *zn)
{
	char *restrict bp = gbuf;
	const char *const ep = gbuf + sizeof(gbuf);

	if (r.trno >= 1) {
		/* there's one before that */
		struct ztrdtl_s zd = zif_trdtl(z, r.trno - 1);

		bp += dz_strftr(bp, ep - bp, (struct ztr_s){r.prev, zd.offs});
	} else {
		bp += xstrlcpy(bp, never, bp - ep);
	}
	/* append prev indicator */
	bp += xstrlcpy(bp, pindi, bp - ep);
	if (r.prev == INT_MIN) {
		bp += xstrlcpy(bp, never, bp - ep);
	} else {
		bp += dz_strftr(bp, ep - bp, (struct ztr_s){r.prev, r.offs});
	}

	/* append name */
	if (LIKELY(zn != NULL)) {
		*bp++ = '\t';
		bp += xstrlcpy(bp, zn, ep - bp);
	}
	*bp++ = '\n';
	__io_write(gbuf, bp - gbuf, stdout);
	return (bp > gbuf) - 1;
}


#include "dzone.yucc"

int
main(int argc, char *argv[])
{
	yuck_t argi[1U];
	int rc = 0;
	zif_t fromz = NULL;
	char **fmt;
	size_t nfmt;
	/* all them zones to consider */
	struct {
		zif_t zone;
		const char *name;
	} *z;
	size_t nz;
	/* all them datetimes to consider */
	struct dt_dt_s *d;
	size_t nd;
	bool trnsp = false;

	if (yuck_parse(argi, argc, argv)) {
		rc = 1;
		goto out;
	} else if (argi->nargs == 0U) {
		error("Need at least a ZONENAME or a DATE/TIME");
		rc = 1;
		goto out;
	}

	/* try and read the from and to time zones */
	if (argi->from_zone_arg) {
		fromz = dt_io_zone(argi->from_zone_arg);
	}
	if (argi->next_flag || argi->prev_flag) {
		trnsp = true;
	}

	/* very well then */
	fmt = argi->input_format_args;
	nfmt = argi->input_format_nargs;

	/* initially size the two beef arrays as large as there is input
	 * we'll then sort them by traversing the input args and ass'ing
	 * to the one or the other */
	nz = 0U;
	z = malloc(argi->nargs * sizeof(*z));
	nd = 0U;
	d = malloc(argi->nargs * sizeof(*d));

	for (size_t i = 0U; i < argi->nargs; i++) {
		const char *inp = argi->args[i];

		/* try dt_strp'ing the input or assume it's a zone  */
		if (!dt_unk_p(d[nd] = dt_io_strpdt(inp, fmt, nfmt, fromz))) {
			if (UNLIKELY(d[nd].fix) && !argi->quiet_flag) {
				rc = 2;
			}
			nd++;
		} else if ((z[nz].zone = dt_io_zone(inp)) != NULL) {
			z[nz].name = inp;
			nz++;
		} else if (!argi->quiet_flag) {
			/* just bollocks */
			error("\
Cannot use `%s', it does not appear to be a zonename\n\
nor a date/time corresponding to the given input formats", inp);
			rc = 2;
		}
	}
	/* operate with default zone UTC and default time now */
	if (nz == 0U) {
		z[nz].zone = NULL;
		z[nz].name = NULL;
		nz++;
	}
	if (nd == 0U && !trnsp) {
		d[nd++] = dt_datetime((dt_dttyp_t)DT_YMD);
	} else if (nd == 0U) {
		d[nd++] = dt_datetime((dt_dttyp_t)DT_SEXY);
	}

	/* just go through them all now */
	if (LIKELY(!trnsp)) {
		for (size_t i = 0U; !trnsp && i < nd; i++) {
			for (size_t j = 0U; j < nz; j++) {
				dz_io_write(d[i], z[j].zone, z[j].name);
			}
		}
	} else {
		/* otherwise traverse the zones and determine transitions */
		for (size_t i = 0U; i < nd; i++) {
			struct dt_dt_s di = dt_dtconv(DT_SEXY, d[i]);

			for (size_t j = 0U; j < nz; j++) {
				const zif_t zj = z[j].zone;
				const char *zn = z[j].name;
				struct zrng_s r;

				if (UNLIKELY(zj == NULL)) {
					/* don't bother */
					continue;
				}
				/* otherwise find the range */
				r = zif_find_zrng(zj, di.sexy);

				if (argi->next_flag) {
					dz_write_nxtr(r, zj, zn);
				}

				if (argi->prev_flag) {
					dz_write_prtr(r, zj, zn);
				}
			}
		}
	}

	/* release the zones */
	dt_io_clear_zones();
	/* release those arrays */
	free(z);
	free(d);

	if (argi->from_zone_arg) {
		zif_close(fromz);
	}

out:
	yuck_free(argi);
	return rc;
}

/* dzone.c ends here */
dateutils-0.3.1/src/dzone.yuck000066400000000000000000000026561241477753400163430ustar00rootroot00000000000000Usage: dzone [OPTION]... [ZONENAME]... [DATE/TIME]...

Convert DATE/TIMEs between timezones.
If DATE/TIME is omitted, it defaults to `now'.

DATE/TIME can also be one of the following specials
  - `now'           interpreted as the current (UTC) time stamp
  - `time'          the time part of the current (UTC) time stamp
  - `today'         the current date (according to UTC)
  - `tomo[rrow]'    tomorrow's date (according to UTC)
  - `y[ester]day'   yesterday's date (according to UTC)

  -q, --quiet                Suppress message about date/time or zonename
                             parser errors and fix-ups.
                             The default is to print a warning or the
                             fixed up value and return error code 2.

  -i, --input-format=STRING...  Input format, can be used multiple times.
                               Each date/time will be passed to the input
                               format parsers in the order they are given, if a
                               date/time can be read successfully with a given
                               input format specifier string, that value will
                               be used.

     --from-zone=ZONE       Interpret dates on stdin or the command line as
                               coming from the time zone ZONE.
  --next                    Show next transition from/to DST.
  --prev                    Show previous transition from/to DST.
dateutils-0.3.1/src/prchunk.c000066400000000000000000000264331241477753400161440ustar00rootroot00000000000000/*** prchunk.c -- guessing line oriented data formats
 *
 * Copyright (C) 2010-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of uterus.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/
#define PRCHUNK_C
#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#if defined MAP_ANON_NEEDS_DARWIN_SOURCE
# define _DARWIN_C_SOURCE
#endif	/* MAP_ANON_NEEDS_DARWIN_SOURCE */
#if defined MAP_ANON_NEEDS_ALL_SOURCE
# define _ALL_SOURCE
#endif	/* MAP_ANON_NEEDS_ALL_SOURCE */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "nifty.h"
#include "prchunk.h"

#define MAX_NLINES	(16384)
#define MAX_LLEN	(1024)

#if !defined MAP_ANONYMOUS && defined MAP_ANON
# define MAP_ANONYMOUS	(MAP_ANON)
#elif !defined MAP_ANON
# define MAP_ANON	(0x1000U)
#endif	/* MAP_ANON->MAP_ANONYMOUS */

#if defined __INTEL_COMPILER
# pragma warning(disable: 981)
#endif	/* __INTEL_COMPILER */

typedef uint32_t off32_t;
typedef uint16_t off16_t;

struct prch_ctx_s {
	/* file descriptor */
	int fd;
	/* buffer */
	char *buf;
	/* number of lines in the buffer */
	uint32_t tot_lno;
	/* number of columns per line */
	uint32_t tot_cno;
	/* number of bytes in the buffer */
	size_t bno;
	/* last known offset */
	size_t off;
	/* offsets */
	off32_t loff[MAX_NLINES];
	off32_t cur_lno;
	/* delimiter offsets */
	off16_t *soff;
};


/* error() impl */
static void
__attribute__((format(printf, 2, 3)))
error(int eno, const char *fmt, ...)
{
	va_list vap;
	va_start(vap, fmt);
	fputs("prchunk: ", stderr);
	vfprintf(stderr, fmt, vap);
	va_end(vap);
	if (eno) {
		fputc(':', stderr);
		fputc(' ', stderr);
		fputs(strerror(eno), stderr);
	}
	fputc('\n', stderr);
	return;
}

static inline void
set_loff(prch_ctx_t ctx, uint32_t lno, off32_t off)
{
	ctx->loff[lno] = off;
	ctx->loff[lno] <<= 1;
	return;
}

static inline off32_t
get_loff(prch_ctx_t ctx, uint32_t lno)
{
	off32_t res = ctx->loff[lno];
	return res >> 1;
}

/* return 0 if not \r terminated, 1 otherwise */
static inline int
lftermdp(prch_ctx_t ctx, uint32_t lno)
{
	return ctx->loff[lno] & 1;
}

static inline void
set_lftermd(prch_ctx_t ctx, uint32_t lno)
{
	ctx->loff[lno] |= 1;
	return;
}

static inline size_t
get_llen(prch_ctx_t ctx, uint32_t lno)
{
	if (UNLIKELY(lno == 0)) {
		return get_loff(ctx, 0) - lftermdp(ctx, 0);
	}
	return get_loff(ctx, lno) -
		lftermdp(ctx, lno) -
		get_loff(ctx, lno - 1) - 1;
}


/* internal operations */
FDEFU int
prchunk_fill(prch_ctx_t ctx)
{
/* this is a coroutine consisting of a line counter yielding the number of
 * lines read so far and a reader yielding a buffer fill and the number of
 * bytes read */
#define CHUNK_SIZE	(4096)
#define YIELD(x)	goto yield##x
	char *off = ctx->buf + 0;
	char *bno = ctx->buf + ctx->bno;
	ssize_t nrd;

	/* initial work, reset the line counters et al */
	ctx->tot_lno = 0;
	/* we just memcpy() the left over stuff to the front and restart
	 * from there, someone left us a note in __ctx with the left
	 * over offset */
	/* normally we'd use memmove() but we know there's little chance
	 * for overlapping regions */
	if (UNLIKELY(ctx->bno == 0)) {
		/* do nothing */
		;
	} else if (LIKELY(ctx->bno > ctx->off)) {
		size_t rsz = ctx->bno - ctx->off;
		/* move the top RSZ bytes to the beginning */
		memcpy(ctx->buf, ctx->buf + ctx->off, rsz);
		ctx->bno = rsz;
		bno = ctx->buf + rsz;
	} else if (UNLIKELY(ctx->bno == ctx->off)) {
		/* what are the odds? just reset the counters */
		ctx->bno = 0;
		bno = ctx->buf;
	} else {
		/* the user didn't see the end of the file */
		return -1;
	}

yield1:
	/* read CHUNK_SIZE bytes */
	bno += (nrd = read(ctx->fd, bno, CHUNK_SIZE));
	/* if we came from yield2 then off == __ctx->bno, and if we
	 * read 0 or less bytes then off >= __ctx->bno + nrd, so we
	 * can simply use that compact expression if the buffer has no
	 * more input.
	 * On the contrary if we came from the outside, i.e. fill_buffer()
	 * has been called, then off would be 0 and __ctx->bno would be
	 * the buffer filled so far, if no more bytes could be read then
	 * we'd proceed processing them (off < __ctx->bno + nrd */
	if (UNLIKELY(!nrd && off < bno && ctx->cur_lno <= ctx->tot_lno)) {
		/* last line then, unyielded :| */
		set_loff(ctx, 0, bno - ctx->buf);
		YIELD(4);
	} else if (UNLIKELY(nrd <= 0 && off == ctx->buf)) {
		/* special case, we worked our arses off and nothing's
		 * in the pipe line so just fuck off here */
		return -1;
	} else if (LIKELY(off < bno || off == ctx->buf)) {
		YIELD(2);
	}
	/* proceed to exit */
	YIELD(3);
yield2:
	while (off < bno) {
		size_t rsz = bno - off;
		char *p = memchr(off, '\n', rsz);
		if (UNLIKELY(p == NULL)) {
			if (LIKELY(nrd > 0)) {
				break;
			}
			/* fucking idiots didnt conclude with a \n */
			error(0, "ID:10T error");
			p = bno;
		}
		/* massage our status structures */
		set_loff(ctx, ctx->tot_lno, p - ctx->buf);
		if (UNLIKELY(p[-1] == '\r')) {
			/* oh god, when is this nightmare gonna end */
			p[-1] = '\0';
			set_lftermd(ctx, ctx->tot_lno);
		}
		*p = '\0';
		off = ++p;
		/* count it as line and check if we need more */
		if (++ctx->tot_lno >= MAX_NLINES) {
			YIELD(3);
		}
	}
	YIELD(1);
yield3:
	/* need clean up, something like unread(),
	 * in particular leave a note in __ctx with the left over offset */
	ctx->cur_lno = 0;
yield4:
	ctx->off = off - ctx->buf;
	ctx->bno = bno - ctx->buf;
#undef YIELD
#undef CHUNK_SIZE
	return 0;
}


/* public operations */
FDEFU prch_ctx_t
init_prchunk(int fd)
{
#define MAP_MEM		(MAP_ANONYMOUS | MAP_PRIVATE)
#define PROT_MEM	(PROT_READ | PROT_WRITE)
#define MAP_LEN		(MAX_NLINES * MAX_LLEN)
	static struct prch_ctx_s __ctx;

	__ctx.buf = mmap(NULL, MAP_LEN, PROT_MEM, MAP_MEM, -1, 0);
	if (__ctx.buf == MAP_FAILED) {
		return NULL;
	}

	/* bit of space for the rechunker */
	__ctx.soff = mmap(NULL, MAP_LEN, PROT_MEM, MAP_MEM, -1, 0);
	if (__ctx.soff == MAP_FAILED) {
		return NULL;
	}

	if ((__ctx.fd = fd) > STDIN_FILENO) {
#if defined POSIX_FADV_SEQUENTIAL
		/* give advice about our read pattern */
		int rc = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);

		if (UNLIKELY(rc < 0)) {
			munmap(__ctx.soff, MAP_LEN);
			return NULL;
		}
#endif	/* POSIX_FADV_SEQUENTIAL */
	}
	return &__ctx;
}

FDEFU void
free_prchunk(prch_ctx_t ctx)
{
	if (LIKELY(ctx->buf != NULL)) {
		munmap(ctx->buf, MAP_LEN);
		ctx->buf = NULL;
	}
	return;
}


/* accessors/iterators/et al. */
FDEFU size_t
prchunk_get_nlines(prch_ctx_t ctx)
{
	return ctx->tot_lno;
}

FDEFU size_t
prchunk_getlineno(prch_ctx_t ctx, char **p, int lno)
{
	if (UNLIKELY(lno <= 0)) {
		*p = ctx->buf;
		return get_llen(ctx, 0);
	} else if (UNLIKELY((size_t)lno >= prchunk_get_nlines(ctx))) {
		*p = NULL;
		return 0;
	}
	/* likely case last, what bollocks */
	*p = ctx->buf + get_loff(ctx, lno - 1) + 1;
	return get_llen(ctx, lno);
}

FDEFU size_t
prchunk_getline(prch_ctx_t ctx, char **p)
{
	return prchunk_getlineno(ctx, p, ctx->cur_lno++);
}

FDEFU void
prchunk_reset(prch_ctx_t ctx)
{
	ctx->cur_lno = 0;
	return;
}

FDEFU int
prchunk_haslinep(prch_ctx_t ctx)
{
/* the second condition is to allow unterminated last lines */
	return ctx->cur_lno < ctx->tot_lno || ctx->cur_lno == 0U;
}


static inline void
set_ncols(prch_ctx_t ctx, size_t ncols)
{
	ctx->tot_cno = ncols;
	return;
}

FDEFU size_t
prchunk_get_ncols(prch_ctx_t ctx)
{
	return ctx->tot_cno;
}

static inline void
set_col_off(prch_ctx_t ctx, size_t lno, size_t cno, size_t off)
{
	ctx->soff[lno * prchunk_get_ncols(ctx) + cno] = (off16_t)off;
	return;
}

static inline off16_t
get_col_off(prch_ctx_t ctx, size_t lno, size_t cno)
{
	return ctx->soff[lno * prchunk_get_ncols(ctx) + cno];
}

/* rechunker, chop the lines into smaller bits
 * Strategy is to go over all lines in the current chunk and
 * memchr() for the delimiter DELIM.
 * Store the offsets into __ctx->soff and bugger off leaving a \0
 * where the delimiter was. */
FDEFU void
prchunk_rechunk(prch_ctx_t ctx, char dlm, int ncols)
{
/* very naive implementation, we prefer prchunk_rechunk_by_dstfld()
 * where a distance histogram demarks possible places */
	size_t lno = 0;
	size_t cno = 0;
	char *line;
	char *off;
	char *p;
	char *bno = ctx->buf + ctx->off;
	size_t rsz;

	set_ncols(ctx, ncols);
	off = line = ctx->buf;
	rsz = bno - off;
	while ((p = memchr(off, dlm, rsz)) != NULL) {
		size_t co;
		size_t llen = get_llen(ctx, lno);
		while ((co = p - line) > llen) {
			/* last column offset equals the length of the line */
			set_col_off(ctx, lno, cno, llen);
			/* get the new line */
			line = ctx->buf + get_loff(ctx, lno++) + 1;
			cno = 0;
		}
		/* store the offset of the column within the line */
		set_col_off(ctx, lno, cno++, co);
		/* prepare the counters for the next round */
		*p = '\0';
		off = ++p;
		rsz = bno - off;
	}
	/* last column offset equals the length of the line */
	rsz = get_llen(ctx, lno);
	set_col_off(ctx, lno, cno, rsz);
	return;
}

FDEFU size_t
prchunk_getcolno(prch_ctx_t ctx, char **p, int lno, int cno)
{
	size_t co1, co2;

	if (UNLIKELY(cno < 0 || (size_t)cno >= prchunk_get_ncols(ctx))) {
		*p = NULL;
		return 0;
	}
	(void)prchunk_getlineno(ctx, p, lno);
	if (UNLIKELY(cno == 0)) {
		return get_col_off(ctx, lno, 0);
	}
	/* likely case last */
	co1 = get_col_off(ctx, lno, cno);
	co2 = get_col_off(ctx, lno, cno - 1);
	*p += co2 + 1;
	return co1 - co2 - 1;
}


#if defined STANDALONE
int
main(int argc, char *argv[])
{
	int fd;
	prch_ctx_t ctx;

	if (argc <= 1) {
		fd = STDIN_FILENO;
	} else if ((fd = open(argv[1], O_RDONLY)) < 0) {
		return 1;
	}
	/* get our prchunk up n running */
	if ((ctx = init_prchunk(fd)) == NULL) {
		error(errno, "Error: ctx NULL");
		return 1;
	}
	/* fill the buffer */
	while (!(prchunk_fill(ctx) < 0)) {
		char *l[1];
		size_t llen;
		int i = 0;

		while ((llen = prchunk_getline(ctx, l))) {
			fprintf(stderr, "%d (%zu) %s\n", i++, llen, l[0]);
		}
	}
	/* and out */
	free_prchunk(ctx);
	close(fd);
	return 0;
}
#endif	/* STANDALONE */

/* prchunk.c ends here */
dateutils-0.3.1/src/prchunk.h000066400000000000000000000047721241477753400161530ustar00rootroot00000000000000/*** prchunk.h -- guessing line oriented data formats
 *
 * Copyright (C) 2010-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of uterus.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/

#if !defined INCLUDED_prchunk_h_
#define INCLUDED_prchunk_h_

#if !defined STATIC_GUTS
# define FDECL		extern
# define FDEFU
#else  /* STATIC_GUTS */
# define FDECL		static
# define FDEFU		static
#endif	/* !STATIC_GUTS */

typedef struct prch_ctx_s *prch_ctx_t;

/* non-reentrant! */
FDECL prch_ctx_t init_prchunk(int fd);
FDECL void free_prchunk(prch_ctx_t);

FDECL int prchunk_fill(prch_ctx_t ctx);

FDECL size_t prchunk_get_nlines(prch_ctx_t);
FDECL size_t prchunk_get_ncols(prch_ctx_t);

FDECL size_t prchunk_getlineno(prch_ctx_t ctx, char **p, int lno);
FDECL size_t prchunk_getline(prch_ctx_t ctx, char **p);
FDECL void prchunk_reset(prch_ctx_t ctx);
FDECL int prchunk_haslinep(prch_ctx_t ctx);

FDECL void prchunk_rechunk(prch_ctx_t ctx, char delim, int ncols);
FDECL size_t prchunk_getcolno(prch_ctx_t ctx, char **p, int lno, int cno);

#endif	/* INCLUDED_prchunk_h_ */
dateutils-0.3.1/src/strpdt-special.gperf000066400000000000000000000007101241477753400202770ustar00rootroot00000000000000%{
%}
%7bit
%readonly-tables
%switch=1
%ignore-case
%enum
%struct-type
%define slot-name special
%define hash-function-name ____strpdt_special
%define lookup-function-name __strpdt_special
%null-strings

struct dt_strpdt_special_s {
	const char *special;
	dt_strpdt_special_t e;
};

%%
now, STRPDT_NOW
today, STRPDT_DATE
date, STRPDT_DATE
tomo, STRPDT_TOMO
tomorrow, STRPDT_TOMO
yday, STRPDT_YDAY
yest, STRPDT_YDAY
yesterday, STRPDT_YDAY
time, STRPDT_TIME
dateutils-0.3.1/src/strptime.c000066400000000000000000000110321241477753400163260ustar00rootroot00000000000000/*** strptime.c -- a shell interface to strptime(3)
 *
 * Copyright (C) 2011-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of dateutils.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/

#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "dt-io.h"
#include "prchunk.h"

const char *prog = "strptime";


static int
pars_line(struct tm *tm, const char *const *fmt, size_t nfmt, const char *line)
{
	for (size_t i = 0; i < nfmt; i++) {
		if (strptime(line, fmt[i], tm) != NULL) {
			return 0;
		}
	}
	return -1;
}

static void
prnt_line(const char *ofmt, struct tm *tm)
{
	char res[256];
	strftime(res, sizeof(res), ofmt, tm);
	fputs(res, stdout);
	return;
}

static inline __attribute__((pure, const)) struct tm
__tm_initialiser(void)
{
#if defined HAVE_SLOPPY_STRUCTS_INIT
	static const struct tm res = {};
#else
	static const struct tm res;
#endif	/* HAVE_SLOPPY_STRUCTS_INIT */
	return res;
}

static void
proc_line(
	const char *ln, const char *const *fmt, size_t nfmt,
	const char *ofmt,
	int quietp)
{
	struct tm tm = __tm_initialiser();

	if (pars_line(&tm, fmt, nfmt, ln) < 0) {
		if (!quietp) {
			dt_io_warn_strpdt(ln);
		}
	} else {
		prnt_line(ofmt, &tm);
	}
	return;
}

static void
proc_lines(const char *const *fmt, size_t nfmt, const char *ofmt, int quietp)
{
	size_t lno = 0;
	void *pctx;

	/* using the prchunk reader now */
	if ((pctx = init_prchunk(STDIN_FILENO)) == NULL) {
		serror("Error: could not open stdin");
		return;
	}
	while (prchunk_fill(pctx) >= 0) {
		for (char *line; prchunk_haslinep(pctx); lno++) {
			(void)prchunk_getline(pctx, &line);
			/* check if line matches */
			proc_line(line, fmt, nfmt, ofmt, quietp);
		}
	}
	/* get rid of resources */
	free_prchunk(pctx);
	return;
}


#include "strptime.yucc"

int
main(int argc, char *argv[])
{
	static char dflt_fmt[] = "%Y-%m-%d\n\0H:%M:%S %Z\n";
	yuck_t argi[1U];
	char *outfmt = dflt_fmt;
	char **infmt;
	size_t ninfmt;
	char **input;
	size_t ninput;
	int quietp;
	int res = 0;

	if (yuck_parse(argi, argc, argv)) {
		res = 1;
		goto out;
	}

	if (argi->format_arg) {
		outfmt = argi->format_arg;
		/* unescape sequences, maybe */
		if (argi->backslash_escapes_flag) {
			dt_io_unescape(outfmt);
		}
	} else if (argi->time_flag) {
		outfmt[8] = ' ';
		outfmt[9] = '%';
	}

	if (!argi->input_format_nargs) {
		infmt = argi->args;
		ninfmt = argi->nargs;
		input = NULL;
		ninput = 0;
	} else {
		infmt = argi->input_format_args;
		ninfmt = argi->input_format_nargs;
		input = argi->args;
		ninput = argi->nargs;
	}
	/* get quiet predicate */
	quietp = argi->quiet_flag;

	/* get lines one by one, apply format string and print date/time */
	if (ninput == 0) {
		/* read from stdin */
		proc_lines((const char*const*)infmt, ninfmt, outfmt, quietp);
	} else {
		const char *const *cinfmt = (const char*const*)infmt;
		for (size_t i = 0; i < ninput; i++) {
			proc_line(input[i], cinfmt, ninfmt, outfmt, quietp);
		}
	}

out:
	yuck_free(argi);
	return res;
}

/* strptime.c ends here */
dateutils-0.3.1/src/strptime.yuck000066400000000000000000000030271241477753400170640ustar00rootroot00000000000000Usage: strptime [OPTION]... [INPUT]...

Parse input from stdin according to one of the given formats FORMATs.
The format string specifiers are the same as for strptime(3).

  -h, --help                 Print help and exit
  -V, --version              Print version and exit
  -t, --time                 also display time in the output, default is to
                               display the date
  -q, --quiet                Suppress message about date/time and duration
                               parser errors.
  -f, --format=STRING        Output format.  This can either be a specifier
                               string (similar to strftime()'s FMT) or the name
                               of a calendar.
  -i, --input-format=STRING...  Input format, can be used multiple times.
                               Each date/time will be passed to the input
                               format parsers in the order they are given, if a
                               date/time can be read successfully with a given
                               input format specifier string, that value will
                               be used.
  -e, --backslash-escapes    Enable interpretation of backslash escapes in the
                               output and input format specifier strings.
  -S, --sed-mode             Copy parts from the input before and after a
                               matching date/time.
                               Note that all occurrences of date/times within a
                               line will be processed.
dateutils-0.3.1/test/000077500000000000000000000000001241477753400145065ustar00rootroot00000000000000dateutils-0.3.1/test/Makefile.am000066400000000000000000000542461241477753400165550ustar00rootroot00000000000000# Help the Developers and yourself. Just use the C locale and settings
# for the compilation. They can still be overriden by make LANG=
# but that is general a not very good idea
include $(top_builddir)/version.mk

LANG = C
LC_ALL = C

libdir = $(abs_top_srcdir)/lib

AM_CPPFLAGS = -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
AM_CPPFLAGS += -DTEST -I"$(libdir)" -I"$(abs_top_builddir)/lib"

EXTRA_DIST =
EXTRA_DIST += $(dt_tests)
EXTRA_DIST += $(batch_tests)
EXTRA_DIST += $(built_dist_sources)
TESTS = $(bin_tests) $(dt_tests) $(batch_tests)
TESTS_ENVIRONMENT =
TEST_EXTENSIONS =
BUILT_SOURCES = $(built_dist_sources) $(built_nodist_sources)
built_dist_sources =
built_nodist_sources =
dt_tests =
bin_tests =
batch_tests =
check_PROGRAMS =
CLEANFILES = $(check_PROGRAMS)
DISTCLEANFILES = $(built_nodist_sources)
SUFFIXES =

DT_LIBS = $(top_builddir)/lib/libdut.a

TEST_EXTENSIONS += .clit
TESTS_ENVIRONMENT += root=$(top_srcdir)
CLIT_LOG_COMPILER = $(builddir)/clittool
AM_CLIT_LOG_FLAGS = -v --builddir "$(top_builddir)/src" --timeout 20

TESTS_ENVIRONMENT += GPERF=$(GPERF)
TESTS_ENVIRONMENT += GDATE=$(GDATE)
TESTS_ENVIRONMENT += have_gdate="$(have_gdate)"

dt_tests += dseq.01.clit
dt_tests += dseq.02.clit
dt_tests += dseq.03.clit
dt_tests += dseq.04.clit
dt_tests += dseq.05.clit
dt_tests += dseq.06.clit
dt_tests += dseq.07.clit
dt_tests += dseq.08.clit
dt_tests += dseq.09.clit
dt_tests += dseq.10.clit
dt_tests += dseq.11.clit
dt_tests += dseq.12.clit
dt_tests += dseq.13.clit
dt_tests += dseq.14.clit
dt_tests += dseq.15.clit
dt_tests += dseq.16.clit
dt_tests += dseq.17.clit
dt_tests += dseq.18.clit
dt_tests += dseq.19.clit
dt_tests += dseq.20.clit
dt_tests += dseq.21.clit
dt_tests += dseq.22.clit
dt_tests += dseq.23.clit
dt_tests += dseq.24.clit
dt_tests += dseq.25.clit
dt_tests += dseq.26.clit
dt_tests += dseq.27.clit
dt_tests += dseq.28.clit
dt_tests += dseq.29.clit
dt_tests += dseq.30.clit
dt_tests += dseq.31.clit
dt_tests += dseq.32.clit
dt_tests += dseq.33.clit
dt_tests += dseq.34.clit
dt_tests += dseq.35.clit
dt_tests += dseq.36.clit
dt_tests += dseq.37.clit
dt_tests += dseq.38.clit
dt_tests += dseq.39.clit
dt_tests += dseq.40.clit
dt_tests += dseq.41.clit
dt_tests += dseq.42.clit

dt_tests += dconv.001.clit
dt_tests += dconv.002.clit
dt_tests += dconv.003.clit
dt_tests += dconv.004.clit
dt_tests += dconv.005.clit
dt_tests += dconv.006.clit
dt_tests += dconv.007.clit
dt_tests += dconv.008.clit
dt_tests += dconv.009.clit
dt_tests += dconv.010.clit
dt_tests += dconv.011.clit
dt_tests += dconv.012.clit
dt_tests += dconv.013.clit
dt_tests += dconv.014.clit
dt_tests += dconv.015.clit
dt_tests += dconv.016.clit
dt_tests += dconv.017.clit
dt_tests += dconv.018.clit
dt_tests += dconv.019.clit
dt_tests += dconv.020.clit
dt_tests += dconv.021.clit
dt_tests += dconv.022.clit
dt_tests += dconv.023.clit
dt_tests += dconv.024.clit
dt_tests += dconv.025.clit
dt_tests += dconv.026.clit
dt_tests += dconv.027.clit
dt_tests += dconv.028.clit
dt_tests += dconv.029.clit
dt_tests += dconv.030.clit
dt_tests += dconv.031.clit
dt_tests += dconv.032.clit
dt_tests += dconv.033.clit
dt_tests += dconv.034.clit
dt_tests += dconv.035.clit
dt_tests += dconv.036.clit
dt_tests += dconv.037.clit
dt_tests += dconv.038.clit
dt_tests += dconv.039.clit
dt_tests += dconv.040.clit
dt_tests += dconv.041.clit
dt_tests += dconv.042.clit
dt_tests += dconv.043.clit
dt_tests += dconv.044.clit
dt_tests += dconv.045.clit
dt_tests += dconv.046.clit
dt_tests += dconv.047.clit
dt_tests += dconv.048.clit
dt_tests += dconv.049.clit
dt_tests += dconv.050.clit
dt_tests += dconv.051.clit
dt_tests += dconv.052.clit
dt_tests += dconv.053.clit
dt_tests += dconv.054.clit
dt_tests += dconv.055.clit
dt_tests += dconv.056.clit
dt_tests += dconv.057.clit
dt_tests += dconv.058.clit
dt_tests += dconv.059.clit
dt_tests += dconv.060.clit
dt_tests += dconv.061.clit
dt_tests += dconv.062.clit
dt_tests += dconv.063.clit
dt_tests += dconv.064.clit
dt_tests += dconv.065.clit
dt_tests += dconv.066.clit
dt_tests += dconv.067.clit
dt_tests += dconv.068.clit
dt_tests += dconv.069.clit
dt_tests += dconv.070.clit
dt_tests += dconv.071.clit
dt_tests += dconv.072.clit
dt_tests += dconv.073.clit
dt_tests += dconv.074.clit
dt_tests += dconv.075.clit
dt_tests += dconv.076.clit
dt_tests += dconv.077.clit
dt_tests += dconv.078.clit
dt_tests += dconv.079.clit
dt_tests += dconv.080.clit
dt_tests += dconv.081.clit
dt_tests += dconv.082.clit
dt_tests += dconv.083.clit
dt_tests += dconv.084.clit
dt_tests += dconv.085.clit
dt_tests += dconv.086.clit
dt_tests += dconv.087.clit
dt_tests += dconv.088.clit
dt_tests += dconv.089.clit
dt_tests += dconv.090.clit
dt_tests += dconv.091.clit
dt_tests += dconv.092.clit
dt_tests += dconv.093.clit
dt_tests += dconv.094.clit
dt_tests += dconv.095.clit
dt_tests += dconv.096.clit
dt_tests += dconv.097.clit
dt_tests += dconv.098.clit
dt_tests += dconv.099.clit
dt_tests += dconv.100.clit
dt_tests += dconv.101.clit
dt_tests += dconv.102.clit
dt_tests += dconv.103.clit
dt_tests += dconv.104.clit
dt_tests += dconv.105.clit
dt_tests += dconv.106.clit
dt_tests += dconv.107.clit
dt_tests += dconv.108.clit
dt_tests += dconv.109.clit
dt_tests += dconv.110.clit
dt_tests += dconv.111.clit
dt_tests += dconv.112.clit
dt_tests += dconv.113.clit
dt_tests += dconv.114.clit
dt_tests += dconv.115.clit
dt_tests += dconv.116.clit
dt_tests += dconv.117.clit
dt_tests += dconv.118.clit

dt_tests += dadd.001.clit
dt_tests += dadd.002.clit
dt_tests += dadd.003.clit
dt_tests += dadd.004.clit
dt_tests += dadd.005.clit
dt_tests += dadd.006.clit
dt_tests += dadd.007.clit
dt_tests += dadd.008.clit
dt_tests += dadd.009.clit
dt_tests += dadd.010.clit
dt_tests += dadd.011.clit
dt_tests += dadd.012.clit
dt_tests += dadd.013.clit
dt_tests += dadd.014.clit
dt_tests += dadd.015.clit
dt_tests += dadd.016.clit
dt_tests += dadd.017.clit
dt_tests += dadd.018.clit
dt_tests += dadd.019.clit
dt_tests += dadd.020.clit
dt_tests += dadd.021.clit
dt_tests += dadd.022.clit
dt_tests += dadd.023.clit
dt_tests += dadd.024.clit
dt_tests += dadd.025.clit
dt_tests += dadd.026.clit
dt_tests += dadd.027.clit
dt_tests += dadd.028.clit
dt_tests += dadd.029.clit
dt_tests += dadd.030.clit
dt_tests += dadd.031.clit
dt_tests += dadd.032.clit
dt_tests += dadd.033.clit
dt_tests += dadd.034.clit
dt_tests += dadd.035.clit
dt_tests += dadd.036.clit
dt_tests += dadd.037.clit
dt_tests += dadd.038.clit
dt_tests += dadd.039.clit
dt_tests += dadd.040.clit
dt_tests += dadd.041.clit
dt_tests += dadd.042.clit
dt_tests += dadd.043.clit
dt_tests += dadd.044.clit
dt_tests += dadd.045.clit
dt_tests += dadd.046.clit
dt_tests += dadd.047.clit
dt_tests += dadd.048.clit
dt_tests += dadd.049.clit
dt_tests += dadd.050.clit
dt_tests += dadd.051.clit
dt_tests += dadd.052.clit
dt_tests += dadd.053.clit
dt_tests += dadd.054.clit
dt_tests += dadd.055.clit
dt_tests += dadd.056.clit
dt_tests += dadd.057.clit
dt_tests += dadd.058.clit
dt_tests += dadd.059.clit
dt_tests += dadd.060.clit
dt_tests += dadd.061.clit
dt_tests += dadd.062.clit
dt_tests += dadd.063.clit
dt_tests += dadd.064.clit
dt_tests += dadd.065.clit
dt_tests += dadd.066.clit
dt_tests += dadd.067.clit
dt_tests += dadd.068.clit
dt_tests += dadd.069.clit
dt_tests += dadd.070.clit
dt_tests += dadd.071.clit
dt_tests += dadd.072.clit
dt_tests += dadd.073.clit
dt_tests += dadd.074.clit
dt_tests += dadd.075.clit
dt_tests += dadd.076.clit
dt_tests += dadd.077.clit
dt_tests += dadd.078.clit
dt_tests += dadd.079.clit
dt_tests += dadd.080.clit
dt_tests += dadd.081.clit
dt_tests += dadd.082.clit
dt_tests += dadd.083.clit
dt_tests += dadd.084.clit
dt_tests += dadd.085.clit
dt_tests += dadd.086.clit
dt_tests += dadd.087.clit
dt_tests += dadd.088.clit

dt_tests += dtest.001.clit
dt_tests += dtest.002.clit
dt_tests += dtest.003.clit
dt_tests += dtest.004.clit
dt_tests += dtest.005.clit
dt_tests += dtest.006.clit
dt_tests += dtest.007.clit
dt_tests += dtest.008.clit
dt_tests += dtest.009.clit

dt_tests += ddiff.001.clit
dt_tests += ddiff.002.clit
dt_tests += ddiff.003.clit
dt_tests += ddiff.004.clit
dt_tests += ddiff.005.clit
dt_tests += ddiff.006.clit
dt_tests += ddiff.007.clit
dt_tests += ddiff.008.clit
dt_tests += ddiff.009.clit
dt_tests += ddiff.010.clit
dt_tests += ddiff.011.clit
dt_tests += ddiff.012.clit
dt_tests += ddiff.013.clit
dt_tests += ddiff.014.clit
dt_tests += ddiff.015.clit
dt_tests += ddiff.016.clit
dt_tests += ddiff.017.clit
dt_tests += ddiff.018.clit
dt_tests += ddiff.019.clit
dt_tests += ddiff.020.clit
dt_tests += ddiff.021.clit
dt_tests += ddiff.022.clit
dt_tests += ddiff.023.clit
dt_tests += ddiff.024.clit
dt_tests += ddiff.025.clit
dt_tests += ddiff.026.clit
dt_tests += ddiff.027.clit
dt_tests += ddiff.028.clit
dt_tests += ddiff.029.clit
dt_tests += ddiff.030.clit
dt_tests += ddiff.031.clit
dt_tests += ddiff.032.clit
dt_tests += ddiff.033.clit
dt_tests += ddiff.034.clit
dt_tests += ddiff.035.clit
dt_tests += ddiff.036.clit
dt_tests += ddiff.037.clit
dt_tests += ddiff.038.clit
dt_tests += ddiff.039.clit
dt_tests += ddiff.040.clit
dt_tests += ddiff.041.clit
dt_tests += ddiff.042.clit
dt_tests += ddiff.043.clit
dt_tests += ddiff.044.clit
dt_tests += ddiff.045.clit
dt_tests += ddiff.046.clit
dt_tests += ddiff.047.clit
dt_tests += ddiff.048.clit
dt_tests += ddiff.049.clit
dt_tests += ddiff.050.clit
dt_tests += ddiff.051.clit
dt_tests += ddiff.052.clit
dt_tests += ddiff.053.clit
dt_tests += ddiff.054.clit
dt_tests += ddiff.055.clit
dt_tests += ddiff.056.clit
dt_tests += ddiff.057.clit
dt_tests += ddiff.058.clit
dt_tests += ddiff.059.clit
dt_tests += ddiff.060.clit
dt_tests += ddiff.061.clit
dt_tests += ddiff.062.clit
dt_tests += ddiff.063.clit
dt_tests += ddiff.064.clit
dt_tests += ddiff.065.clit
dt_tests += ddiff.066.clit
dt_tests += ddiff.067.clit
dt_tests += ddiff.068.clit

dt_tests += dgrep.001.clit
dt_tests += dgrep.002.clit
dt_tests += dgrep.003.clit
dt_tests += dgrep.004.clit
dt_tests += dgrep.005.clit
dt_tests += dgrep.006.clit
dt_tests += dgrep.007.clit
dt_tests += dgrep.008.clit
dt_tests += dgrep.009.clit
dt_tests += dgrep.010.clit
dt_tests += dgrep.011.clit
dt_tests += dgrep.012.clit
dt_tests += dgrep.013.clit
dt_tests += dgrep.014.clit
dt_tests += dgrep.015.clit
dt_tests += dgrep.016.clit
dt_tests += dgrep.017.clit
dt_tests += dgrep.018.clit
dt_tests += dgrep.019.clit
dt_tests += dgrep.020.clit
dt_tests += dgrep.021.clit
dt_tests += dgrep.022.clit
dt_tests += dgrep.023.clit
dt_tests += dgrep.024.clit
dt_tests += dgrep.025.clit
dt_tests += dgrep.026.clit
dt_tests += dgrep.027.clit
dt_tests += dgrep.028.clit
dt_tests += dgrep.029.clit
dt_tests += dgrep.030.clit
dt_tests += dgrep.031.clit
dt_tests += dgrep.032.clit
dt_tests += dgrep.033.clit
dt_tests += dgrep.034.clit
dt_tests += dgrep.035.clit
dt_tests += dgrep.036.clit
dt_tests += dgrep.037.clit
dt_tests += dgrep.038.clit
dt_tests += dgrep.039.clit
dt_tests += dgrep.040.clit

dt_tests += dround.001.clit
dt_tests += dround.002.clit
dt_tests += dround.003.clit
dt_tests += dround.004.clit
dt_tests += dround.005.clit
dt_tests += dround.006.clit
dt_tests += dround.007.clit
dt_tests += dround.008.clit
dt_tests += dround.009.clit
dt_tests += dround.010.clit
dt_tests += dround.011.clit
dt_tests += dround.012.clit
dt_tests += dround.013.clit
dt_tests += dround.014.clit
dt_tests += dround.015.clit
dt_tests += dround.016.clit
dt_tests += dround.017.clit
dt_tests += dround.018.clit
dt_tests += dround.019.clit
dt_tests += dround.020.clit
dt_tests += dround.021.clit
dt_tests += dround.022.clit
dt_tests += dround.023.clit
dt_tests += dround.024.clit
dt_tests += dround.025.clit
dt_tests += dround.026.clit
dt_tests += dround.027.clit
dt_tests += dround.028.clit


dt_tests += tseq.01.clit
dt_tests += tseq.02.clit
dt_tests += tseq.03.clit
dt_tests += tseq.04.clit
dt_tests += tseq.05.clit
dt_tests += tseq.06.clit
dt_tests += tseq.07.clit
dt_tests += tseq.08.clit
dt_tests += tseq.09.clit
dt_tests += tseq.10.clit
dt_tests += tseq.11.clit
dt_tests += tseq.12.clit
dt_tests += tseq.13.clit
dt_tests += tseq.14.clit
dt_tests += tseq.15.clit
dt_tests += tseq.16.clit
dt_tests += tseq.17.clit
dt_tests += tseq.18.clit
dt_tests += tseq.19.clit

dt_tests += tdiff.001.clit
dt_tests += tdiff.002.clit
dt_tests += tdiff.003.clit
dt_tests += tdiff.004.clit
dt_tests += tdiff.005.clit
dt_tests += tdiff.006.clit
dt_tests += tdiff.007.clit
dt_tests += tdiff.008.clit
dt_tests += tdiff.009.clit
dt_tests += tdiff.010.clit
dt_tests += tdiff.011.clit
dt_tests += tdiff.012.clit
dt_tests += tdiff.013.clit

dt_tests += tadd.001.clit
dt_tests += tadd.002.clit
dt_tests += tadd.003.clit
dt_tests += tadd.004.clit
dt_tests += tadd.005.clit
dt_tests += tadd.006.clit
dt_tests += tadd.007.clit
dt_tests += tadd.008.clit
dt_tests += tadd.009.clit
dt_tests += tadd.010.clit

dt_tests += tgrep.001.clit
dt_tests += tgrep.002.clit
dt_tests += tgrep.003.clit

dt_tests += ttest.001.clit
dt_tests += ttest.002.clit
dt_tests += ttest.003.clit
dt_tests += ttest.004.clit
dt_tests += ttest.005.clit
dt_tests += ttest.006.clit
dt_tests += ttest.007.clit

dt_tests += tconv.001.clit
dt_tests += tconv.002.clit
dt_tests += tconv.003.clit
dt_tests += tconv.004.clit
dt_tests += tconv.005.clit
dt_tests += tconv.006.clit

dt_tests += tround.001.clit
dt_tests += tround.002.clit
dt_tests += tround.003.clit
dt_tests += tround.004.clit


dt_tests += dtconv.001.clit
dt_tests += dtconv.002.clit
dt_tests += dtconv.003.clit
dt_tests += dtconv.004.clit
dt_tests += dtconv.005.clit
dt_tests += dtconv.006.clit
dt_tests += dtconv.007.clit
dt_tests += dtconv.008.clit
dt_tests += dtconv.009.clit
dt_tests += dtconv.010.clit
dt_tests += dtconv.011.clit
dt_tests += dtconv.012.clit
dt_tests += dtconv.013.clit
dt_tests += dtconv.014.clit
dt_tests += dtconv.015.clit
dt_tests += dtconv.016.clit
dt_tests += dtconv.017.clit
dt_tests += dtconv.018.clit
dt_tests += dtconv.019.clit
dt_tests += dtconv.020.clit
dt_tests += dtconv.021.clit
dt_tests += dtconv.022.clit
dt_tests += dtconv.023.clit
if ZONEINFO_UTC_RIGHT
dt_tests += dtconv.024.clit
dt_tests += dtconv.025.clit
dt_tests += dtconv.026.clit
dt_tests += dtconv.027.clit
dt_tests += dtconv.028.clit
dt_tests += dtconv.029.clit
dt_tests += dtconv.030.clit
dt_tests += dtconv.031.clit
dt_tests += dtconv.032.clit
dt_tests += dtconv.033.clit
endif  ZONEINFO_UTC_RIGHT
dt_tests += dtconv.034.clit
dt_tests += dtconv.035.clit
dt_tests += dtconv.036.clit
dt_tests += dtconv.037.clit
dt_tests += dtconv.038.clit
dt_tests += dtconv.039.clit
dt_tests += dtconv.040.clit
dt_tests += dtconv.041.clit
dt_tests += dtconv.042.clit
dt_tests += dtconv.043.clit
dt_tests += dtconv.044.clit
dt_tests += dtconv.045.clit
dt_tests += dtconv.046.clit
dt_tests += dtconv.047.clit
dt_tests += dtconv.048.clit
dt_tests += dtconv.049.clit
dt_tests += dtconv.050.clit
dt_tests += dtconv.051.clit
dt_tests += dtconv.052.clit
dt_tests += dtconv.053.clit
dt_tests += dtconv.054.clit
dt_tests += dtconv.055.clit
dt_tests += dtconv.056.clit
dt_tests += dtconv.057.clit
dt_tests += dtconv.058.clit
dt_tests += dtconv.059.clit
dt_tests += dtconv.060.clit
dt_tests += dtconv.061.clit
dt_tests += dtconv.062.clit
dt_tests += dtconv.063.clit
dt_tests += dtconv.064.clit
dt_tests += dtconv.065.clit
dt_tests += dtconv.066.clit
dt_tests += dtconv.067.clit
dt_tests += dtconv.068.clit

dt_tests += convt.ymcw-ymd.clit
dt_tests += convt.ymcw-ywd.clit
dt_tests += convt.ymd-ymcw.clit
dt_tests += convt.ymd-ywd.clit
dt_tests += convt.ywd-ymcw.clit
dt_tests += convt.ywd-ymd.clit

dt_tests += dtseq.01.clit
dt_tests += dtseq.02.clit
dt_tests += dtseq.03.clit
dt_tests += dtseq.04.clit
dt_tests += dtseq.05.clit
dt_tests += dtseq.06.clit
dt_tests += dtseq.07.clit
dt_tests += dtseq.08.clit

dt_tests += dtadd.001.clit
dt_tests += dtadd.002.clit
dt_tests += dtadd.003.clit
dt_tests += dtadd.004.clit
dt_tests += dtadd.005.clit
dt_tests += dtadd.006.clit
dt_tests += dtadd.007.clit
dt_tests += dtadd.008.clit
dt_tests += dtadd.009.clit
dt_tests += dtadd.010.clit
dt_tests += dtadd.011.clit
dt_tests += dtadd.012.clit
dt_tests += dtadd.013.clit
dt_tests += dtadd.014.clit
dt_tests += dtadd.015.clit
dt_tests += dtadd.016.clit
dt_tests += dtadd.017.clit
dt_tests += dtadd.018.clit
dt_tests += dtadd.019.clit
dt_tests += dtadd.020.clit
dt_tests += dtadd.021.clit
dt_tests += dtadd.022.clit
dt_tests += dtadd.023.clit
dt_tests += dtadd.024.clit
dt_tests += dtadd.025.clit
dt_tests += dtadd.026.clit
dt_tests += dtadd.027.clit
dt_tests += dtadd.028.clit
dt_tests += dtadd.029.clit
if WITH_LEAP_SECONDS
dt_tests += dtadd.030.clit
dt_tests += dtadd.031.clit
endif  ## WITH_LEAP_SECONDS
dt_tests += dtadd.032.clit
dt_tests += dtadd.033.clit
if WITH_LEAP_SECONDS
dt_tests += dtadd.034.clit
dt_tests += dtadd.035.clit
endif  ## WITH_LEAP_SECONDS
dt_tests += dtadd.036.clit
dt_tests += dtadd.037.clit
dt_tests += dtadd.038.clit
dt_tests += dtadd.039.clit
dt_tests += dtadd.040.clit
## multi-sed
dt_tests += dtadd.041.clit
dt_tests += dtadd.042.clit
dt_tests += dtadd.043.clit
dt_tests += dtadd.044.clit
dt_tests += dtadd.045.clit
dt_tests += dtadd.046.clit
dt_tests += dtadd.047.clit
dt_tests += dtadd.048.clit

dt_tests += dtgrep.001.clit
dt_tests += dtgrep.002.clit
dt_tests += dtgrep.003.clit
dt_tests += dtgrep.004.clit
dt_tests += dtgrep.005.clit
dt_tests += dtgrep.006.clit
dt_tests += dtgrep.007.clit
dt_tests += dtgrep.008.clit
dt_tests += dtgrep.009.clit
dt_tests += dtgrep.010.clit
dt_tests += dtgrep.011.clit
dt_tests += dtgrep.012.clit
dt_tests += dtgrep.013.clit
dt_tests += dtgrep.014.clit

dt_tests += dttest.001.clit
dt_tests += dttest.002.clit
dt_tests += dttest.003.clit
dt_tests += dttest.004.clit
dt_tests += dttest.005.clit
dt_tests += dttest.006.clit
dt_tests += dttest.007.clit
dt_tests += dttest.008.clit
dt_tests += dttest.009.clit
dt_tests += dttest.010.clit

dt_tests += dtdiff.001.clit
dt_tests += dtdiff.002.clit
dt_tests += dtdiff.003.clit
dt_tests += dtdiff.004.clit
dt_tests += dtdiff.005.clit
dt_tests += dtdiff.006.clit
dt_tests += dtdiff.007.clit
dt_tests += dtdiff.008.clit
dt_tests += dtdiff.009.clit
dt_tests += dtdiff.010.clit
dt_tests += dtdiff.011.clit
dt_tests += dtdiff.012.clit
dt_tests += dtdiff.013.clit
dt_tests += dtdiff.014.clit
dt_tests += dtdiff.015.clit
dt_tests += dtdiff.016.clit
dt_tests += dtdiff.017.clit
dt_tests += dtdiff.018.clit
if WITH_LEAP_SECONDS
dt_tests += dtdiff.019.clit
dt_tests += dtdiff.020.clit
dt_tests += dtdiff.021.clit
dt_tests += dtdiff.022.clit
endif  ## WITH_LEAP_SECONDS
dt_tests += dtdiff.023.clit
dt_tests += dtdiff.024.clit
dt_tests += dtdiff.025.clit
dt_tests += dtdiff.026.clit
dt_tests += dtdiff.027.clit
dt_tests += dtdiff.028.clit
dt_tests += dtdiff.029.clit
dt_tests += dtdiff.030.clit
dt_tests += dtdiff.031.clit
dt_tests += dtdiff.032.clit
dt_tests += dtdiff.033.clit
dt_tests += dtdiff.034.clit
dt_tests += dtdiff.035.clit
dt_tests += dtdiff.036.clit
dt_tests += dtdiff.037.clit
dt_tests += dtdiff.038.clit
dt_tests += dtdiff.039.clit
dt_tests += dtdiff.040.clit
dt_tests += dtdiff.041.clit
dt_tests += dtdiff.042.clit
dt_tests += dtdiff.043.clit
dt_tests += dtdiff.044.clit
dt_tests += dtdiff.045.clit
dt_tests += dtdiff.046.clit

dt_tests += dtround.001.clit
dt_tests += dtround.002.clit
dt_tests += dtround.003.clit
dt_tests += dtround.004.clit
dt_tests += dtround.005.clit
dt_tests += dtround.006.clit
dt_tests += dtround.007.clit
dt_tests += dtround.008.clit
dt_tests += dtround.009.clit
dt_tests += dtround.010.clit
dt_tests += dtround.011.clit
dt_tests += dtround.012.clit
dt_tests += dtround.013.clit
dt_tests += dtround.014.clit

dt_tests += dzone.001.clit
dt_tests += dzone.002.clit
dt_tests += dzone.003.clit
dt_tests += dzone.004.clit
dt_tests += dzone.005.clit
dt_tests += dzone.006.clit
dt_tests += dzone.007.clit
dt_tests += dzone.008.clit

dt_tests += dsort.001.clit
dt_tests += dsort.002.clit
dt_tests += dsort.003.clit
dt_tests += dsort.004.clit
dt_tests += dsort.005.clit
dt_tests += dsort.006.clit
EXTRA_DIST += caev_01.txt
EXTRA_DIST += caev_02.txt

dt_tests += strptime.001.clit
dt_tests += strptime.002.clit

## testing the prchunker
dt_tests += prchunk.001.clit
dt_tests += prchunk.002.clit
dt_tests += prchunk.003.clit
dt_tests += prchunk.004.clit
dt_tests += prchunk.005.clit
dt_tests += prchunk.006.clit

## testing tzmaps, regardless if the official ones are here or not
EXTRA_DIST += dummy.tzmap
built_nodist_sources += dummy.tzmcc
TESTS_ENVIRONMENT += TZMAP_DIR=$(builddir)
dt_tests += tzmap.001.clit
dt_tests += tzmap.002.clit
dt_tests += tzmap.003.clit
dt_tests += tzmap.004.clit

## make sure our the maps we ship are clean
dt_tests += tzmap_check_01.clit
dt_tests += tzmap_check_02.clit
TESTS_ENVIRONMENT += TZMAP=$(top_builddir)/lib/tzmap


## we should check if the zones in these tests actually exist
## also failing tests here should be soft-fails because that could
## easily be an outdated zoneinfo file
dt_tests += dtz.001.clit
dt_tests += dtz.002.clit

check_PROGRAMS += struct-1
check_PROGRAMS += struct-2
check_PROGRAMS += struct-3
check_PROGRAMS += struct-4
check_PROGRAMS += struct-5
check_PROGRAMS += struct-6
check_PROGRAMS += struct-7
check_PROGRAMS += struct-8
check_PROGRAMS += struct-9
check_PROGRAMS += enum-1
check_PROGRAMS += dtcore-strp
check_PROGRAMS += dtcore-conv
check_PROGRAMS += dtcore-add
check_PROGRAMS += time-core-add
check_PROGRAMS += basic_ymd_get_wday
check_PROGRAMS += basic_get_jan01_wday
check_PROGRAMS += basic_md_get_yday
check_PROGRAMS += basic_get_dom_wday

bin_tests += struct-1
bin_tests += struct-2
bin_tests += struct-3
bin_tests += struct-4
bin_tests += struct-5
bin_tests += struct-6
bin_tests += struct-7
bin_tests += struct-8
bin_tests += struct-9
bin_tests += enum-1
bin_tests += dtcore-strp
bin_tests += dtcore-conv
bin_tests += dtcore-add
bin_tests += time-core-add
bin_tests += basic_ymd_get_wday
bin_tests += basic_get_jan01_wday
bin_tests += basic_get_dom_wday
bin_tests += basic_md_get_yday

dtcore_strp_LDADD = $(DT_LIBS)
dtcore_conv_LDADD = $(DT_LIBS)
dtcore_add_LDADD = $(DT_LIBS)
time_core_add_LDADD = $(DT_LIBS)

## batch checks
batch_tests += dseq-cnt.1.sh
if HAVE_GDATE
TESTS_ENVIRONMENT += have_gdate_2039="$(have_gdate_2039)"
batch_tests += dseq-cnt.2.sh
batch_tests += dseq-cnt.3.sh
batch_tests += dconv-batch.1.sh
batch_tests += dconv-batch.2.sh
endif  HAVE_GDATE


check_PROGRAMS += clittool
clittool_CPPFLAGS = $(AM_CPPFLAGS)
clittool_CPPFLAGS += -D_GNU_SOURCE
EXTRA_DIST += clittool.yuck
built_dist_sources += clittool.yucc


## ggo rule
SUFFIXES += .yuck
SUFFIXES += .yucc
.yuck.yucc:
	$(AM_V_GEN) PATH=$(top_builddir)/build-aux:"$${PATH}" \
		yuck$(EXEEXT) gen -o $@ $<

## tzmcc rule
SUFFIXES += .tzmap
SUFFIXES += .tzmcc
.tzmap.tzmcc:
	-$(AM_V_GEN) $(top_builddir)/lib/tzmap cc -o $@ $<

clean-local:
	-rm -rf *.tmpd

## Makefile.am ends here
dateutils-0.3.1/test/basic_get_dom_wday.c000066400000000000000000000013161241477753400204560ustar00rootroot00000000000000#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include "strops.h"
#include "strops.c"
#include "token.h"
#include "token.c"
#include "date-core.h"
#include "date-core.c"

static unsigned int
super(void)
{
	unsigned int res = 0;

	for (int y = 1917; y < 2199; y++) {
		for (int m = 1; m <= 12; m ++) {
			for (int d = 1; d <= 28; d++) {
				dt_dow_t w = __get_dom_wday(y, m, d);
				res += y * m * (w == DT_SUNDAY ? 0 : w) + d;
			}
		}
	}
	return res;
}

int
main(void)
{
	unsigned int supersum = 0;

	for (size_t i = 0; i < 512; i++) {
		supersum += super();
	}
	printf("super %u\n", supersum);
	if (supersum != 1486417920U) {
		return 1;
	}
	return 0;
}

/* basic_get_wday.c ends here */
dateutils-0.3.1/test/basic_get_jan01_wday.c000066400000000000000000000011761241477753400206140ustar00rootroot00000000000000#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include "strops.h"
#include "strops.c"
#include "token.h"
#include "token.c"
#include "date-core.h"
#include "date-core.c"

static unsigned int
super(unsigned int res)
{
	for (int y = 1917; y < 2199; y++) {
		dt_dow_t w;
		w = __get_jan01_wday(y);
		res += y * (w == DT_SUNDAY ? 0 : w);
	}
	return res;
}

int
main(void)
{
	unsigned int supersum = 0;

	for (size_t i = 0; i < 1024 * 1024; i++) {
		supersum += super(supersum);
	}
	printf("super %u\n", supersum);
	if (supersum != 4293232620U) {
		return 1;
	}
	return 0;
}

/* basic_get_jan01_wday.c ends here */
dateutils-0.3.1/test/basic_md_get_yday.c000066400000000000000000000017741241477753400203110ustar00rootroot00000000000000#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include "strops.h"
#include "strops.c"
#include "token.h"
#include "token.c"
#include "date-core.h"
#include "date-core.c"

static unsigned int
super(unsigned int res)
{
	for (int y = 1917; y < 2299; y++) {
		for (int m = 1; m <= 12; m++) {
			for (int d = 0; d < 32; d++) {
				unsigned int yd;
				yd = __md_get_yday(y, m, d);
				res += y * m * yd + d;
			}
		}
	}
	return res;
}

#if 0
static unsigned int
hyper(unsigned int hyper)
{
	dt_ymd_t x;
	for (int y = 1917; y < 4096; y++) {
		for (int m = 1; m <= 12; m++) {
			for (int d = 0; d < 32; d++) {
				unsigned int yd;
				x.y = y;
				x.m = m;
				x.d = d;
				yd = __ymd_get_yday(x);
				hyper += yd;
			}
		}
	}
	return hyper;
}
#endif

int
main(void)
{
	unsigned int supersum = 0;

	for (size_t i = 0; i < 4096; i++) {
		supersum += super(supersum);
	}
	printf("super %u\n", supersum);
	if (supersum != 2780223808U) {
		return 1;
	}
	return 0;
}

/* basic_md_get_yday.c ends here */
dateutils-0.3.1/test/basic_ymd_get_wday.c000066400000000000000000000014151241477753400204700ustar00rootroot00000000000000#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include "strops.h"
#include "strops.c"
#include "token.h"
#include "token.c"
#include "date-core.h"
#include "date-core.c"

static unsigned int
super(void)
{
	dt_ymd_t x = {0};
	unsigned int res = 0;

	for (int y = 1917; y < 2199; y++) {
		for (int m = 1; m <= 12; m ++) {
			for (int d = 1; d <= 28; d++) {
				dt_dow_t w;
				x.y = y;
				x.m = m;
				x.d = d;
				w = __ymd_get_wday(x);
				res += y * m * (w == DT_SUNDAY ? 0 : w) + d;
			}
		}
	}
	return res;
}

int
main(void)
{
	unsigned int supersum = 0;

	for (size_t i = 0; i < 512; i++) {
		supersum += super();
	}
	printf("super %u\n", supersum);
	if (supersum != 1486417920U) {
		return 1;
	}
	return 0;
}

/* basic_ymd_get_wday.c ends here */
dateutils-0.3.1/test/caev_01.txt000066400000000000000000000007371241477753400164740ustar00rootroot000000000000002009-06-03 caev="DVCA" secu="VOD" exch="XLON" xdte="2009-06-03" nett/GBX="5.2"
2011-11-16 caev="DVCA" secu="VOD" exch="XLON" xdte="2011-11-16" nett/GBX="3.05"
2013-11-20 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-11-20" nett/GBX="3.53"
2012-06-06 caev="DVCA" secu="VOD" exch="XLON" xdte="2012-06-06" nett/GBX="6.47"
2013-06-12 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-06-12" nett/GBX="6.92"
2010-11-17 caev="DVCA" secu="VOD" exch="XLON" xdte="2010-11-17" nett/GBX="2.85"
dateutils-0.3.1/test/caev_02.txt000066400000000000000000000010371241477753400164670ustar00rootroot000000000000002009-06-03 caev="DVCA" secu="VOD" exch="XLON" xdte="2009-06-03" nett/GBX="5.2"
2011-11-16 caev="DVCA" secu="VOD" exch="XLON" xdte="2011-11-16" nett/GBX="3.05"
2013-11-20 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-11-20" nett/GBX="3.53"
2010-11-17 caev="XXXX" secu="VOD" exch="XLON" xdte="2010-11-17"
2012-06-06 caev="DVCA" secu="VOD" exch="XLON" xdte="2012-06-06" nett/GBX="6.47"
2013-06-12 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-06-12" nett/GBX="6.92"
2010-11-17 caev="DVCA" secu="VOD" exch="XLON" xdte="2010-11-17" nett/GBX="2.85"
dateutils-0.3.1/test/clittool.c000066400000000000000000000750331241477753400165130ustar00rootroot00000000000000/*** clittool.c -- command-line-interface tester or is it?
 *
 * Copyright (C) 2013-2014 Sebastian Freundt
 *
 * Author:  Sebastian Freundt 
 *
 * This file is part of clitoris.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the author nor the names of any contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***/
#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#define _ALL_SOURCE
#define _NETBSD_SOURCE
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#if defined HAVE_PTY_H
# include 
#endif	/* HAVE_PTY_H */
/* check for me */
#include 

#if !defined LIKELY
# define LIKELY(_x)	__builtin_expect((_x), 1)
#endif	/* !LIKELY */
#if !defined UNLIKELY
# define UNLIKELY(_x)	__builtin_expect((_x), 0)
#endif	/* UNLIKELY */

#if !defined countof
# define countof(x)	(sizeof(x) / sizeof(*x))
#endif	/* !countof */

#if !defined with
# define with(args...)	for (args, *__ep__ = (void*)1; __ep__; __ep__ = 0)
#endif	/* !with */

#if !defined PATH_MAX
# define PATH_MAX	256U
#endif	/* !PATH_MAX */

typedef struct clitf_s clitf_t;
typedef struct clit_buf_s clit_buf_t;
typedef struct clit_bit_s clit_bit_t;
typedef struct clit_tst_s *clit_tst_t;

struct clitf_s {
	size_t z;
	void *d;
};

struct clit_buf_s {
	size_t z;
	const char *d;
};

/**
 * A clit bit can be an ordinary memory buffer (z > 0 && d),
 * a file descriptor (fd != 0 && d == NULL), or a file name (z == -1UL && fn) */
struct clit_bit_s {
	size_t z;
	const char *d;
};

struct clit_chld_s {
	int pin;
	int pou;
	int per;

	pid_t chld;
	pid_t diff;
	pid_t feed;

	unsigned int test_id;

	unsigned int verbosep:1;
	unsigned int ptyp:1;
	unsigned int keep_going_p:1;

	unsigned int timeo;
};

/* a test is the command (inlcuding stdin), stdout result, and stderr result */
struct clit_tst_s {
	clit_bit_t cmd;
	clit_bit_t out;
	clit_bit_t err;
	clit_bit_t rest;

	/* specific per-test flags */
	/** don't fail when the actual output differs from th expected output */
	unsigned int ign_out:1;
	/** don't fail when the command returns non-SUCCESS */
	unsigned int ign_ret:1;

	/** don't pass the output on to external differ */
	unsigned int supp_diff:1;
	/** expand the proto-output as though it was a shell here-document */
	unsigned int xpnd_proto:1;

	/* padding */
	unsigned int:5;

	/** expect this return code, or any but 0 if all bits are set */
	unsigned int exp_ret:8;
};


static sigset_t fatal_signal_set[1];
static sigset_t empty_signal_set[1];

static const char dflt_diff[] = "diff";
static const char *cmd_diff = dflt_diff;


static void
__attribute__((format(printf, 1, 2)))
error(const char *fmt, ...)
{
	va_list vap;
	va_start(vap, fmt);
	vfprintf(stderr, fmt, vap);
	va_end(vap);
	if (errno) {
		fputs(": ", stderr);
		fputs(strerror(errno), stderr);
	}
	fputc('\n', stderr);
	return;
}

static inline __attribute__((const, pure, always_inline)) char*
deconst(const char *s)
{
	union {
		const char *c;
		char *p;
	} x = {s};
	return x.p;
}


/* imported code */
/*** fast_strstr.c
 *
 * This algorithm is licensed under the open-source BSD3 license
 *
 * Copyright (c) 2014, Raphael Javaux
 * All rights reserved.
 *
 * Licence text, see above.
 *
 * The code has been modified to mimic memmem().
 *
 **/
/**
* Finds the first occurrence of the sub-string needle in the string haystack.
* Returns NULL if needle was not found.
*/
static char*
xmemmem(const char *hay, const size_t hayz, const char *ndl, const size_t ndlz)
{
	const char *const eoh = hay + hayz;
	const char *const eon = ndl + ndlz;
	const char *hp;
	const char *np;
	const char *cand;
	unsigned int hsum;
	unsigned int nsum;
	unsigned int eqp;

	/* trivial checks first
         * a 0-sized needle is defined to be found anywhere in haystack
         * then run strchr() to find a candidate in HAYSTACK (i.e. a portion
         * that happens to begin with *NEEDLE) */
	if (ndlz == 0UL) {
		return deconst(hay);
	} else if ((hay = memchr(hay, *ndl, hayz)) == NULL) {
		/* trivial */
		return NULL;
	}

	/* First characters of haystack and needle are the same now. Both are
	 * guaranteed to be at least one character long.  Now computes the sum
	 * of characters values of needle together with the sum of the first
	 * needle_len characters of haystack. */
	for (hp = hay + 1U, np = ndl + 1U, hsum = *hay, nsum = *hay, eqp = 1U;
	     hp < eoh && np < eon;
	     hsum ^= *hp, nsum ^= *np, eqp &= *hp == *np, hp++, np++);

	/* HP now references the (NZ + 1)-th character. */
	if (np < eon) {
		/* haystack is smaller than needle, :O */
		return NULL;
	} else if (eqp) {
		/* found a match */
		return deconst(hay);
	}

	/* now loop through the rest of haystack,
	 * updating the sum iteratively */
	for (cand = hay; hp < eoh; hp++) {
		hsum ^= *cand++;
		hsum ^= *hp;

		/* Since the sum of the characters is already known to be
		 * equal at that point, it is enough to check just NZ - 1
		 * characters for equality,
		 * also CAND is by design < HP, so no need for range checks */
		if (hsum == nsum && memcmp(cand, ndl, ndlz - 1U) == 0) {
			return deconst(cand);
		}
	}
	return NULL;
}


/* clit bit handling */
#define CLIT_BIT_FD(x)	(clit_bit_fd_p(x) ? (int)(x).z : -1)

static inline __attribute__((const, pure)) bool
clit_bit_buf_p(clit_bit_t x)
{
	return x.z != -1UL && x.d != NULL;
}

static inline __attribute__((const, pure)) bool
clit_bit_fd_p(clit_bit_t x)
{
	return x.d == NULL;
}

static inline __attribute__((const, pure)) bool
clit_bit_fn_p(clit_bit_t x)
{
	return x.z == -1UL && x.d != NULL;
}

/* ctors */
static inline __attribute__((unused)) clit_bit_t
clit_make_fd(int fd)
{
	return (clit_bit_t){.z = fd};
}

static inline clit_bit_t
clit_make_fn(const char *fn)
{
	return (clit_bit_t){.z = -1UL, .d = fn};
}

static const char*
bufexp(const char src[static 1], size_t ssz)
{
	static char *buf;
	static size_t bsz;
	wordexp_t xp[1];

	if (UNLIKELY(ssz == 0)) {
		return NULL;
	}

#define CHKBSZ(x)						   \
	if ((x) >= bsz) {					   \
		bsz = ((x) / 256U + 1U) * 256U;			   \
		if (UNLIKELY((buf = realloc(buf, bsz)) == NULL)) { \
			/* well we'll leak XP here */		   \
			return NULL;				   \
		}						   \
	}

	/* get our own copy for deep vein massages */
	CHKBSZ(ssz);
	memcpy(buf, src, ssz);
	buf[ssz] = '\0';

	switch (wordexp(buf, xp, WRDE_UNDEF)) {
	case 0:
		if (xp->we_wordc > 0) {
			/* everything's fine */
			break;
		}
	case WRDE_NOSPACE:
		wordfree(xp);
	default:
		return NULL;
	}

	/* copy the first `argument', back into BUF,
	 * which is hopefully big enough */
	with (size_t wz = strlen(xp->we_wordv[0])) {
		CHKBSZ(wz);
		memcpy(buf, xp->we_wordv[0], wz);
		buf[wz] = '\0';
	}

	wordfree(xp);
	return buf;
}


static clitf_t
mmap_fd(int fd, size_t fz)
{
	void *p;

	if ((p = mmap(NULL, fz, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
		return (clitf_t){.z = 0U, .d = NULL};
	}
	return (clitf_t){.z = fz, .d = p};
}

static int
munmap_fd(clitf_t map)
{
	return munmap(map.d, map.z);
}

static void
block_sigs(void)
{
	(void)sigprocmask(SIG_BLOCK, fatal_signal_set, (sigset_t*)NULL);
	return;
}

static void
unblock_sigs(void)
{
	sigprocmask(SIG_SETMASK, empty_signal_set, (sigset_t*)NULL);
	return;
}

static void
unblock_sig(int sig)
{
	static sigset_t unblk_set[1];

	sigemptyset(unblk_set);
	sigaddset(unblk_set, sig);
	(void)sigprocmask(SIG_UNBLOCK, unblk_set, (sigset_t*)NULL);
	return;
}

#if defined HAVE_PTY_H
static pid_t
pfork(int *pty)
{
	if (UNLIKELY(pty == NULL)) {
		errno = ENOMEM;
		return -1;
	}
	return forkpty(pty, NULL, NULL, NULL);
}
#else  /* !HAVE_PTY_H */
static pid_t
pfork(int *pty)
{
	fputs("pseudo-tty not supported\n", stderr);
	return *pty = -1;
}
#endif	/* HAVE_PTY_H */


static const char *
find_shtok(const char *bp, size_t bz)
{
/* finds a (lone) occurrence of $ at the beginning of a line */
	for (const char *res;
	     (res = memchr(bp, '$', bz)) != NULL;
	     bz -= (res + 1 - bp), bp = res + 1) {
		/* we're actually after a "\n$" or
		 * a "$" at the beginning of the buffer pointer (bp)
		 * now check that either the buffer ends there or
		 * the $ is followed by a newline, or the $ is followed
		 * by a space, which is the line-to-exec indicator */
		if ((res == bp || res[-1] == '\n') &&
		    (bz <= 1U || (res[1] == '\n' || res[1] == ' '))) {
			return res;
		}
	}
	return NULL;
}

static clit_bit_t
find_cmd(const char *bp, size_t bz)
{
	clit_bit_t resbit = {0U};
	clit_bit_t tok;

	/* find the bit where it says '$ ' */
	with (const char *res) {
		if (UNLIKELY((res = find_shtok(bp, bz)) == NULL)) {
			return (clit_bit_t){0U};
		} else if (UNLIKELY(res[1] != ' ')) {
			return (clit_bit_t){0U};
		}
		/* otherwise */
		resbit.d = res += 2U;
		bz -= res - bp;
		bp = res;
	}

	/* find the new line bit */
	for (const char *res;
	     (res = memchr(bp, '\n', bz)) != NULL;
	     bz -= (res + 1U - bp), bp = res + 1U) {
		size_t lz = (res + 1U - bp);

		/* check for trailing \ or <cmd.d, *const ec = cmd + tst->cmd.z) {
		static char tok_ign[] = "ignore";
		static char tok_out[] = "output";
		static char tok_ret[] = "return";

		if (strncmp(cmd, tok_ign, sizeof(tok_ign) - 1U)) {
			/* don't bother */
			break;
		}
		/* fast-forward a little */
		cmd += sizeof(tok_ign) - 1U;

		if (isspace(*cmd)) {
			/* it's our famous ignore token it seems */
			tst->ign_out = tst->ign_ret = 1U;
		} else if (*cmd++ != '-') {
			/* unknown token then */
			break;
		} else if (!strncmp(cmd, tok_out, sizeof(tok_out) - 1U)) {
			/* ignore-output it is */
			tst->ign_out = 1U;
			cmd += sizeof(tok_out) - 1U;
		} else if (!strncmp(cmd, tok_ret, sizeof(tok_ret) - 1U)) {
			/* ignore-return it is */
			tst->ign_ret = 1U;
			cmd += sizeof(tok_ret) - 1U;
		} else {
			/* don't know what's going on */
			break;
		}

		/* now, fast-forward to the actual command, and reass */
		while (++cmd < ec && isspace(*cmd));
		tst->cmd.z -= (cmd - tst->cmd.d);
		tst->cmd.d = cmd;
		return 0;
	}
	return -1;
}

static int
find_negexp(struct clit_tst_s tst[static 1])
{
	with (const char *cmd = tst->cmd.d, *const ec = cmd + tst->cmd.z) {
		unsigned int exp = 0U;

		switch (*cmd) {
		case '!'/*NEG*/:
			exp = 255U;
			break;
		case '?'/*EXP*/:;
			char *p;
			exp = strtoul(cmd + 1U, &p, 10);
			cmd = cmd + (p - cmd);
			if (isspace(*cmd)) {
				break;
			}
		default:
			return -1;
		}

		/* now, fast-forward to the actual command, and reass */
		while (++cmd < ec && isspace(*cmd));
		tst->cmd.z -= (cmd - tst->cmd.d);
		tst->cmd.d = cmd;
		tst->exp_ret = exp;
	}
	return 0;
}

static int
find_suppdiff(struct clit_tst_s tst[static 1])
{
	with (const char *cmd = tst->cmd.d, *const ec = cmd + tst->cmd.z) {
		switch (*cmd) {
		case '@':
			break;
		default:
			return -1;
		}

		/* now, fast-forward to the actual command, and reass */
		while (++cmd < ec && isspace(*cmd));
		tst->cmd.z -= (cmd - tst->cmd.d);
		tst->cmd.d = cmd;
		tst->supp_diff = 1U;
		tst->ign_out = 1U;
	}
	return 0;
}

static int
find_xpnd_proto(struct clit_tst_s tst[static 1])
{
	with (const char *cmd = tst->cmd.d, *const ec = cmd + tst->cmd.z) {
		switch (*cmd) {
		case '$':
			break;
		default:
			return -1;
		}

		/* now, fast-forward to the actual command, and reass */
		while (++cmd < ec && isspace(*cmd));
		tst->cmd.z -= (cmd - tst->cmd.d);
		tst->cmd.d = cmd;
		tst->xpnd_proto = 1U;
	}
	return 0;
}

static int
find_tst(struct clit_tst_s tst[static 1], const char *bp, size_t bz)
{
	if (UNLIKELY(!(tst->cmd = find_cmd(bp, bz)).z)) {
		goto fail;
	}
	/* reset bp and bz */
	bz = bz - (tst->cmd.d + tst->cmd.z - bp);
	bp = tst->cmd.d + tst->cmd.z;
	if (UNLIKELY((tst->rest.d = find_shtok(bp, bz)) == NULL)) {
		goto fail;
	}
	/* otherwise set the rest bit already */
	tst->rest.z = bz - (tst->rest.d - bp);

	/* now the stdout bit must be in between (or 0) */
	with (size_t outz = tst->rest.d - bp) {
		if (outz &&
		    /* prefixed '< '? */
		    UNLIKELY(bp[0] == '<' && bp[1] == ' ')) {
			/* it's a < FILE comparison */
			const char *fn;

			if ((fn = bufexp(bp + 2, outz - 2U - 1U)) != NULL) {
				tst->out = clit_make_fn(fn);
			} else {
				error("expansion failed");
				goto fail;
			}
		} else {
			tst->out = (clit_bit_t){.z = outz, bp};
		}
	}

	while (
		/* oh let's see if we should ignore things */
		!find_ignore(tst) ||

		/* check for suppress diff */
		!find_suppdiff(tst) ||

		/* check for expect and negate operators */
		!find_negexp(tst) ||

		/* check for proto-output expander */
		!find_xpnd_proto(tst) ||

		0);

	tst->err = (clit_bit_t){0U};
	return 0;
fail:
	memset(tst, 0, sizeof(*tst));
	return -1;
}

static int
find_opt(struct clit_chld_s ctx[static 1], const char *bp, size_t bz)
{
	static const char magic[] = "setopt ";

	for (const char *mp;
	     (mp = xmemmem(bp, bz, magic, sizeof(magic) - 1U)) != NULL;
	     bz -= (mp + 1U) - bp, bp = mp + 1U) {
		unsigned int opt;

		/* check if it's setopt or unsetopt */
		if (mp == bp || LIKELY(mp[-1] == '\n')) {
			/* yay, it's a genuine setopt */
			opt = 1U;
		} else if (mp >= bp + 2U && mp[-2] == 'u' && mp[-1] == 'n' &&
			   (mp == bp + 2U || mp > bp + 2U && mp[-3] == '\n')) {
			/* it's a genuine unsetopt */
			opt = 0U;
		} else {
			/* found rubbish then */
			mp += sizeof(magic) - 1U;
			continue;
		}
#define CMP(x, lit)	(strncmp((x), (lit), sizeof(lit) - 1))
		/* parse the option value */
		if ((mp += sizeof(magic) - 1U) == NULL) {
			;
		} else if (CMP(mp, "verbose\n") == 0) {
			ctx->verbosep = opt;
		} else if (CMP(mp, "pseudo-tty\n") == 0) {
			ctx->ptyp = opt;
		} else if (CMP(mp, "timeout") == 0) {
			const char *arg = mp + sizeof("timeout");
			char *p;
			long unsigned int timeo;

			if ((timeo = strtoul(arg, &p, 0), *p == '\n')) {
				ctx->timeo = (unsigned int)timeo;
			}
		} else if (CMP(mp, "keep-going\n") == 0) {
			ctx->keep_going_p = opt;
		}
#undef CMP
	}
	return 0;
}

static int
init_chld(struct clit_chld_s ctx[static 1] __attribute__((unused)))
{
	/* set up the set of fatal signals */
	sigemptyset(fatal_signal_set);
	sigaddset(fatal_signal_set, SIGHUP);
	sigaddset(fatal_signal_set, SIGQUIT);
	sigaddset(fatal_signal_set, SIGINT);
	sigaddset(fatal_signal_set, SIGTERM);
	sigaddset(fatal_signal_set, SIGXCPU);
	sigaddset(fatal_signal_set, SIGXFSZ);
	/* also the empty set */
	sigemptyset(empty_signal_set);
	return 0;
}

static int
fini_chld(struct clit_chld_s ctx[static 1] __attribute__((unused)))
{
	return 0;
}

static char*
mkfifofn(const char *key, unsigned int tid)
{
	size_t len = strlen(key) + 9U + 8U + 1U;
	char *buf;

	if ((buf = malloc(len)) != NULL) {
		snprintf(buf, len, "%s output  %x", key, tid);
	}
	return buf;
}

static pid_t
feeder(clit_bit_t exp, int expfd)
{
	pid_t feed;

	switch ((feed = fork())) {
	case -1:
		/* ah good then */
		break;
	case 0:;
		/* i am the child */
		ssize_t nwr;

		while (exp.z > 0 &&
		       (nwr = write(expfd, exp.d, exp.z)) > 0) {
			exp.d += nwr;
			if ((size_t)nwr <= exp.z) {
				exp.z -= nwr;
			} else {
				exp.z = 0;
			}
		}

		/* we're done */
		close(expfd);

		/* and out, always succeed */
		exit(EXIT_SUCCESS);
	default:
		/* i'm the parent */
		break;
	}
	return feed;
}

static pid_t
xpnder(clit_bit_t exp, int expfd)
{
	pid_t feed;

	switch ((feed = fork())) {
	case -1:
		/* ah good then */
		break;
	case 0:;
		/* i am the child */
		ssize_t nwr;
		int xin[2U];
		pid_t sh;

		if (UNLIKELY(pipe(xin) < 0)) {
		fail:
			/* whatever */
			exit(EXIT_FAILURE);
		}

		switch ((sh = fork())) {
			static char *const sh_args[] = {"sh", "-s", NULL};
		case -1:
			/* big fucking problem */
			goto fail;
		case 0:
			/* close write end of pipe */
			close(xin[1U]);
			/* redir xin[0U] -> stdin */
			dup2(xin[0U], STDIN_FILENO);
			/* close read end of pipe */
			close(xin[0U]);

			/* redir stdout -> expfd */
			dup2(expfd, STDOUT_FILENO);
			/* close expfd */
			close(expfd);

			/* child again */
			execv("/bin/sh", sh_args);
			exit(EXIT_SUCCESS);
		default:
			/* parent i am */
			close(xin[0U]);
			/* also forget about expfd */
			close(expfd);
			break;
		}

		if (write(xin[1U], "cat < 0 &&
		       (nwr = write(xin[1U], exp.d, exp.z)) > 0) {
			exp.d += nwr;
			if ((size_t)nwr <= exp.z) {
				exp.z -= nwr;
			} else {
				exp.z = 0;
			}
		}
		if (write(xin[1U], "EOF\n", 4U) < 4) {
			goto fail;
		}

		/* we're done */
		close(xin[1U]);

		/* wait for child process */
		with (int st) {
			while (waitpid(sh, &st, 0) != sh);
		}

		/* and out, always succeed */
		exit(EXIT_SUCCESS);
	default:
		/* i'm the parent */
		break;
	}
	return feed;
}

static pid_t
differ(struct clit_chld_s ctx[static 1], clit_bit_t exp, bool xpnd_proto_p)
{
	char *expfn;
	char *actfn;
	pid_t difftool = -1;

	assert(!clit_bit_fd_p(exp));

	if (clit_bit_fn_p(exp)) {
		expfn = malloc(strlen(exp.d) + 1U);
		if (UNLIKELY(expfn == NULL || strcpy(expfn, exp.d) == NULL)) {
			error("cannot prepare in file `%s'", exp.d);
			goto out;
		}
	} else {
		expfn = mkfifofn("expected", ctx->test_id);
		if (expfn == NULL || mkfifo(expfn, 0666) < 0) {
			error("cannot create fifo `%s'", expfn);
			goto out;
		}
	}
	actfn = mkfifofn("actual", ctx->test_id);
	if (actfn == NULL || mkfifo(actfn, 0666) < 0) {
		error("cannot create fifo `%s'", actfn);
		goto out;
	}

	block_sigs();

	switch ((difftool = vfork())) {
	case -1:
		/* i am an error */
		error("vfork for diff failed");
		break;

	case 0: {
		/* i am the child */
		char *const diff_opt[] = {
			"diff",
			"-u",
			expfn, actfn, NULL,
		};

		unblock_sigs();

		/* don't allow input at all */
		close(STDIN_FILENO);

		/* diff stdout -> stderr */
		dup2(STDERR_FILENO, STDOUT_FILENO);

		execvp(cmd_diff, diff_opt);

		/* just unlink the files the WRONLY is waiting for
		 * ACTFN is always something that we create and unlink,
		 * so delete that one now to trigger an error in the
		 * parent's open() code below */
		unlink(actfn);
		/* EXPFN is opened in the parent code below if it's
		 * a fifo created by us, unlink that one to break the hang */
		if (clit_bit_buf_p(exp)) {
			unlink(expfn);
		}
		_exit(EXIT_FAILURE);
	}
	default:;
		/* i am the parent */
		static const int ofl = O_WRONLY;
		int expfd = -1;
		int actfd = -1;

		/* clean up descriptors */
		if (clit_bit_buf_p(exp) &&
		    (expfd = open(expfn, ofl, 0666)) < 0) {
			goto clobrk;
		} else if ((actfd = open(actfn, ofl, 0666)) < 0) {
			goto clobrk;
		}

		/* assign actfd as out descriptor */
		ctx->pou = actfd;

		/* fork out the feeder guy */
		if (clit_bit_buf_p(exp)) {
			/* check if we need the expander */
			if (LIKELY(!xpnd_proto_p)) {
				ctx->feed = feeder(exp, expfd);
			} else {
				ctx->feed = xpnder(exp, expfd);
			}
			/* forget about expfd lest we leak it */
			close(expfd);
		} else {
			/* best to let everyone know that we chose
			 * not to use a feeder */
			ctx->feed = -1;
		}
		break;
	clobrk:
		error("exec'ing %s failed", cmd_diff);
		if (expfd >= 0) {
			close(expfd);
		}
		if (actfd >= 0) {
			close(actfd);
		}
		kill(difftool, SIGTERM);
		difftool = -1;
		break;
	}

	unblock_sigs();
out:
	if (expfn) {
		if (!clit_bit_fn_p(exp)) {
			unlink(expfn);
		}
		free(expfn);
	}
	if (actfn) {
		unlink(actfn);
		free(actfn);
	}
	return difftool;
}

static int
init_tst(struct clit_chld_s ctx[static 1], struct clit_tst_s tst[static 1])
{
/* set up a connection with /bin/sh to pipe to and read from */
	int pty;
	int pin[2];
	int per[2];

	/* obtain a test id */
	with (struct timeval tv[1]) {
		(void)gettimeofday(tv, NULL);
		ctx->test_id = (unsigned int)(tv->tv_sec ^ tv->tv_usec);
	}

	if (!tst->supp_diff) {
		ctx->diff = differ(ctx, tst->out, tst->xpnd_proto);
	} else {
		ctx->diff = -1;
		ctx->feed = -1;
		ctx->pou = -1;
	}

	if (0) {
		;
	} else if (UNLIKELY(pipe(pin) < 0)) {
		ctx->chld = -1;
		return -1;
	} else if (UNLIKELY(ctx->ptyp && pipe(per) < 0)) {
		ctx->chld = -1;
		return -1;
	}

	block_sigs();
	switch ((ctx->chld = LIKELY(!ctx->ptyp) ? vfork() : pfork(&pty))) {
	case -1:
		/* i am an error */
		unblock_sigs();
		return -1;

	case 0:
		/* i am the child */
		unblock_sigs();
		if (UNLIKELY(ctx->ptyp)) {
			/* in pty mode connect child's stderr to parent's */
			;
		}

		/* read from pin and write to pou */
		if (LIKELY(!ctx->ptyp)) {
			/* pin[0] ->stdin */
			dup2(pin[0], STDIN_FILENO);
		} else {
			dup2(per[1], STDERR_FILENO);
			close(per[0]);
			close(per[1]);
		}
		close(pin[0]);
		close(pin[1]);

		/* stdout -> pou[1] */
		if (!tst->supp_diff) {
			dup2(ctx->pou, STDOUT_FILENO);
			close(ctx->pou);
		}

		execl("/bin/sh", "sh", NULL);
		error("exec'ing /bin/sh failed");
		_exit(EXIT_FAILURE);

	default:
		/* i am the parent, clean up descriptors */
		close(pin[0]);
		if (UNLIKELY(ctx->ptyp)) {
			close(pin[1]);
		}
		if (LIKELY(ctx->pou >= 0)) {
			close(ctx->pou);
		}
		ctx->pou = -1;

		/* assign desc, write end of pin */
		if (LIKELY(!ctx->ptyp)) {
			ctx->pin = pin[1];
		} else {
			ctx->pin = pty;
			ctx->per = per[0];
			close(per[1]);
		}
		break;
	}
	return 0;
}

static int
run_tst(struct clit_chld_s ctx[static 1], struct clit_tst_s tst[static 1])
{
	int rc = 0;
	int st;

	if (UNLIKELY(init_tst(ctx, tst) < 0)) {
		rc = -1;
		if (ctx->feed > 0) {
			kill(ctx->feed, SIGTERM);
		}
		if (ctx->diff > 0) {
			kill(ctx->diff, SIGTERM);
		}
		goto wait;
	}
	with (const char *p = tst->cmd.d, *const ep = tst->cmd.d + tst->cmd.z) {
		for (ssize_t nwr;
		     p < ep && (nwr = write(ctx->pin, p, ep - p)) > 0;
		     p += nwr);
	}
	unblock_sigs();

	if (LIKELY(!ctx->ptyp) ||
	    write(ctx->pin, "exit $?\n", 8U) < 8) {
		/* indicate we're not writing anymore on the child's stdin
		 * or in case of a pty, send exit command and keep fingers
		 * crossed the pty will close itself */
		close(ctx->pin);
	}

	/* wait for the beef child */
	while (ctx->chld > 0 && waitpid(ctx->chld, &st, 0) != ctx->chld);
	if (LIKELY(ctx->chld > 0 && WIFEXITED(st))) {
		rc = WEXITSTATUS(st);

		if (tst->exp_ret == rc) {
			rc = 0;
		} else if (tst->exp_ret == 255U && rc) {
			rc = 0;
		} else {
			rc = 1;
		}
	} else {
		rc = 1;
	}

wait:
	/* wait for the feeder */
	while (ctx->feed > 0 && waitpid(ctx->feed, &st, 0) != ctx->feed);
	if (LIKELY(ctx->feed > 0 && WIFEXITED(st))) {
		int tmp_rc = WEXITSTATUS(st);

		if (tst->ign_out) {
			/* don't worry */
			;
		} else if (tmp_rc > rc) {
			rc = tmp_rc;
		}
	}

	/* finally wait for the differ */
	while (ctx->diff > 0 && waitpid(ctx->diff, &st, 0) != ctx->diff);
	if (LIKELY(ctx->diff > 0 && WIFEXITED(st))) {
		int tmp_rc = WEXITSTATUS(st);

		if (tst->ign_out) {
			/* don't worry */
			;
		} else if (tmp_rc > rc) {
			rc = tmp_rc;
		}
	}

	/* and after all, if we ignore the rcs just reset them to zero */
	if (tst->ign_ret) {
		rc = 0;
	}

#if defined HAVE_PTY_H
	if (UNLIKELY(ctx->ptyp)) {
		/* also close child's stdin here */
		close(ctx->pin);
	}

	/* also connect per's out end with stderr */
	if (UNLIKELY(ctx->ptyp)) {
# if defined HAVE_SPLICE
#  if !defined SPLICE_F_MOVE
#   define SPLICE_F_MOVE		(0)
#  endif  /* SPLICE_F_MOVE */
		for (ssize_t nsp;
		     (nsp = splice(
			      ctx->per, NULL, STDERR_FILENO, NULL,
			      4096U, SPLICE_F_MOVE)) == 4096U;);
# endif	/* HAVE_SPLICE */
		close(ctx->per);
	}
#endif	/* HAVE_PTY_H */
	return rc;
}

static void
set_timeout(unsigned int tdiff)
{
	if (UNLIKELY(tdiff == 0U)) {
		return;
	}

	/* unblock just this one signal */
	unblock_sig(SIGALRM);
	alarm(tdiff);
	return;
}

static void
prepend_path(const char *p)
{
#define free_path()	prepend_path(NULL);
	static char *paths;
	static size_t pathz;
	static char *restrict pp;
	size_t pz;

	if (UNLIKELY(p == NULL)) {
		/* freeing */
		if (paths == NULL) {
			free(paths);
			paths = pp = NULL;
		}
		return;
	}
	/* otherwise it'd be safe to compute the strlen() methinks */
	pz = strlen(p);

	if (UNLIKELY(paths == NULL)) {
		char *envp;

		if (LIKELY((envp = getenv("PATH")) != NULL)) {
			const size_t envz = strlen(envp);

			/* get us a nice big cushion */
			pathz = ((envz + pz + 1U/*\nul*/) / 256U + 2U) * 256U;
			if (UNLIKELY((paths = malloc(pathz)) == NULL)) {
				/* don't bother then */
				return;
			}
			/* set pp for further reference */
			pp = (paths + pathz) - (envz + 1U/*\nul*/);
			/* glue the current path at the end of the array */
			memccpy(pp, envp, '\0', envz);
			/* terminate pp at least at the very end */
			pp[envz] = '\0';
		} else {
			/* just alloc space for P */
			pathz = ((pz + 1U/*\nul*/) / 256U + 2U) * 256U;
			if (UNLIKELY((paths = malloc(pathz)) == NULL)) {
				/* don't bother then */
				return;
			}
			/* set pp for further reference */
			pp = (paths + pathz) - (pz + 1U/*\nul*/);
			/* copy P and then exit */
			memcpy(pp, p, pz + 1U/*\nul*/);
			goto out;
		}
	}

	/* calc prepension pointer */
	pp -= pz + 1U/*:*/;

	if (UNLIKELY(pp < paths)) {
		/* awww, not enough space, is there */
		ptrdiff_t ppoff = pp - paths;
		size_t newsz = ((pathz + pz + 1U/*:*/) / 256U + 1U) * 256U;

		if (UNLIKELY((paths = realloc(paths, newsz)) == NULL)) {
			/* just leave things be */
			return;
		}
		/* memmove to the back */
		memmove(paths + (newsz - pathz), paths, pathz);
		/* recalc paths pointer */
		pp = paths + (newsz - pathz) + ppoff;
		pathz = newsz;
	}

	/* actually prepend now */
	memcpy(pp, p, pz);
	pp[pz] = ':';
out:
	setenv("PATH", pp, 1);
	return;
}


static int verbosep;
static int ptyp;
static int keep_going_p;
static unsigned int timeo;

static int
test_f(clitf_t tf)
{
	static struct clit_chld_s ctx[1];
	static struct clit_tst_s tst[1];
	const char *bp = tf.d;
	size_t bz = tf.z;
	int rc = 0;

	if (UNLIKELY(init_chld(ctx) < 0)) {
		return -1;
	}

	/* preset options */
	if (verbosep) {
		ctx->verbosep = 1U;
	}
	if (ptyp) {
		ctx->ptyp = 1U;
	}
	if (keep_going_p) {
		ctx->keep_going_p = 1U;
	}
	ctx->timeo = timeo;

	/* find options in the test script */
	find_opt(ctx, bp, bz);

	/* prepare */
	if (ctx->timeo > 0) {
		set_timeout(ctx->timeo);
	}
	for (; find_tst(tst, bp, bz) == 0; bp = tst->rest.d, bz = tst->rest.z) {
		if (ctx->verbosep) {
			fputs("$ ", stderr);
			fwrite(tst->cmd.d, sizeof(char), tst->cmd.z, stderr);
		}
		with (int tst_rc = run_tst(ctx, tst)) {
			if (ctx->verbosep) {
				fprintf(stderr, "$? %d\n", tst_rc);
			}
			rc = rc ?: tst_rc;
		}
		if (rc && !ctx->keep_going_p) {
			break;
		}
	}
	if (UNLIKELY(fini_chld(ctx)) < 0) {
		rc = -1;
	}
	return rc;
}

static int
test(const char *testfile)
{
	int fd;
	struct stat st;
	clitf_t tf;
	int rc = -1;

	if ((fd = open(testfile, O_RDONLY)) < 0) {
		error("Error: cannot open file `%s'", testfile);
		goto out;
	} else if (fstat(fd, &st) < 0) {
		error("Error: cannot stat file `%s'", testfile);
		goto clo;
	} else if ((tf = mmap_fd(fd, st.st_size)).d == NULL) {
		error("Error: cannot map file `%s'", testfile);
		goto clo;
	}
	/* yaay, perform the test */
	rc = test_f(tf);

	/* and out we are */
	munmap_fd(tf);
clo:
	close(fd);
out:
	return rc;
}


#include "clittool.yucc"

int
main(int argc, char *argv[])
{
	yuck_t argi[1U];
	int rc = 99;

	if (yuck_parse(argi, argc, argv)) {
		goto out;
	} else if (argi->nargs != 1U) {
		yuck_auto_help(argi);
		goto out;
	}

	if (argi->builddir_arg) {
		setenv("builddir", argi->builddir_arg, 1);
	}
	if (argi->srcdir_arg) {
		setenv("srcdir", argi->srcdir_arg, 1);
	}
	if (argi->hash_arg) {
		setenv("hash", argi->hash_arg, 1);
	}
	if (argi->husk_arg) {
		setenv("husk", argi->husk_arg, 1);
	}
	if (argi->verbose_flag) {
		verbosep = 1U;
	}
	if (argi->pseudo_tty_flag) {
		ptyp = 1U;
	}
	if (argi->timeout_arg) {
		timeo = strtoul(argi->timeout_arg, NULL, 10);
	}
	if (argi->keep_going_flag) {
		keep_going_p = 1U;
	}
	if (argi->diff_arg) {
		cmd_diff = argi->diff_arg;
	} else if (getenv("DIFF") != NULL) {
		cmd_diff = getenv("DIFF");
	}

	/* prepend our current directory and our argv[0] directory */
	with (char *arg0 = argv[0]) {
		char *dir0;
		if ((dir0 = strrchr(arg0, '/')) != NULL) {
			*dir0 = '\0';
			prepend_path(arg0);
		}
	}
	prepend_path(".");
	/* also bang builddir to path */
	with (char *blddir = getenv("builddir")) {
		if (LIKELY(blddir != NULL)) {
			/* use at most 256U bytes for blddir */
			char _blddir[256U];

			memccpy(_blddir, blddir, '\0', sizeof(_blddir) - 1U);
			_blddir[sizeof(_blddir) - 1U] = '\0';
			prepend_path(_blddir);
		}
	}

	/* just to be clear about this */
#if defined WORDS_BIGENDIAN
	setenv("endian", "big", 1);
#else  /* !WORDS_BIGENDIAN */
	setenv("endian", "little", 1);
#endif	/* WORDS_BIGENDIAN */

	if ((rc = test(argi->args[0U])) < 0) {
		rc = 99;
	}

	/* resource freeing */
	free_path();
out:
	yuck_free(argi);
	return rc;
}

/* clittool.c ends here */
dateutils-0.3.1/test/clittool.yuck000066400000000000000000000012411241477753400172320ustar00rootroot00000000000000Usage: clitoris [OPTION]... TEST_FILE

Run .clit regression test files.

  --builddir=DIR  Specify where the compiled binaries can be found.
  --srcdir=DIR  Specify where the source tree resides.
  --hash=PROG  Use hasher PROG instead of md5sum.
  --husk=PROG  Use husk around tool, e.g. 'valgrind -v'
  --shell-bits=SCRIPT  Use SCRIPT as shell part of the test

  -v, --verbose  Repeat execution steps on stderr.
  -t, --pseudo-tty  Allocate a pseudo-tty for the tests to run in.

  --timeout=SECS  Time out after SECS seconds.

  -k, --keep-going  Don't break on the first failure or differing output

  --diff=CMD  Use specified diff command instead of the one in PATH.
dateutils-0.3.1/test/convt.ymcw-ymd.clit000066400000000000000000000003701241477753400202610ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq "1917-01-01" "2399-12-31" -f "ymcw" > "convt.ymcw-ymd.ref"
$ dconv -f "ymd" < "convt.ymcw-ymd.ref" | dconv -f "ymcw"
< "convt.ymcw-ymd.ref"
$ rm -- "convt.ymcw-ymd.ref"
$

## convt.ymcw-ymd.clit
dateutils-0.3.1/test/convt.ymcw-ywd.clit000066400000000000000000000003701241477753400202730ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq "1917-01-01" "2399-12-31" -f "ymcw" > "convt.ymcw-ywd.ref"
$ dconv -f "ywd" < "convt.ymcw-ywd.ref" | dconv -f "ymcw"
< "convt.ymcw-ywd.ref"
$ rm -- "convt.ymcw-ywd.ref"
$

## convt.ymcw-ywd.clit
dateutils-0.3.1/test/convt.ymd-ymcw.clit000066400000000000000000000003671241477753400202670ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq "1917-01-01" "2399-12-31" -f "ymd" > "convt.ymd-ymcw.ref"
$ dconv -f "ymcw" < "convt.ymd-ymcw.ref" | dconv -f "ymd"
< "convt.ymd-ymcw.ref"
$ rm -- "convt.ymd-ymcw.ref"
$

## convt.ymd-ymcw.clit
dateutils-0.3.1/test/convt.ymd-ywd.clit000066400000000000000000000003611241477753400201050ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq "1917-01-01" "2399-12-31" -f "ymd" > "convt.ymd-ywd.ref"
$ dconv -f "ywd" < "convt.ymd-ywd.ref" | dconv -f "ymd"
< "convt.ymd-ywd.ref"
$ rm -- "convt.ymd-ywd.ref"
$

## convt.ymd-ywd.clit
dateutils-0.3.1/test/convt.ywd-ymcw.clit000066400000000000000000000003671241477753400203010ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq "1917-01-01" "2399-12-31" -f "ywd" > "convt.ywd-ymcw.ref"
$ dconv -f "ymcw" < "convt.ywd-ymcw.ref" | dconv -f "ywd"
< "convt.ywd-ymcw.ref"
$ rm -- "convt.ywd-ymcw.ref"
$

## convt.ywd-ymcw.clit
dateutils-0.3.1/test/convt.ywd-ymd.clit000066400000000000000000000003611241477753400201050ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq "1917-01-01" "2399-12-31" -f "ywd" > "convt.ywd-ymd.ref"
$ dconv -f "ymd" < "convt.ywd-ymd.ref" | dconv -f "ywd"
< "convt.ywd-ymd.ref"
$ rm -- "convt.ywd-ymd.ref"
$

## convt.ywd-ymd.clit
dateutils-0.3.1/test/dadd.001.clit000066400000000000000000000001541241477753400165560ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dadd 2012-03-01 1d
2012-03-02
$

## dadd.001.clit ends here
dateutils-0.3.1/test/dadd.002.clit000066400000000000000000000001541241477753400165570ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dadd 2012-03-01 1m
2012-04-01
$

## dadd.002.clit ends here
dateutils-0.3.1/test/dadd.003.clit000066400000000000000000000001541241477753400165600ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dadd 2012-03-31 1m
2012-04-30
$

## dadd.003.clit ends here
dateutils-0.3.1/test/dadd.004.clit000066400000000000000000000003201241477753400165540ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dadd 2w2d < "${foo}"
for y in `seq ${BEG} ${END}`; do
	"${GDATE}" -d "${y}-01-01" '+%F	%a'
done > "${bar}"

diff "${foo}" "${bar}"
rc=${?}

rm -f "${foo}" "${bar}"

exit ${rc}
dateutils-0.3.1/test/dconv-batch.2.sh000077500000000000000000000010401241477753400173700ustar00rootroot00000000000000#!/bin/sh

BEG="1917"
END="4095"
if test "${have_gdate_2039}" != "yes"; then
	BEG="1970"
	END="2037"
fi

if test "${have_gdate}" != "yes"; then
	## SKIP in new automake
	exit 77
fi

TOOLDIR="$(pwd)/../src"

DCONV="${TOOLDIR}/dconv"

foo=`mktemp "/tmp/tmp.XXXXXXXXXX"`
bar=`mktemp "/tmp/tmp.XXXXXXXXXX"`

for y in `seq ${BEG} ${END}`; do
	"${DCONV}" "${y}-12-31" -f '%F	%a'
done > "${foo}"
for y in `seq ${BEG} ${END}`; do
	"${GDATE}" -d "${y}-12-31" '+%F	%a'
done > "${bar}"

diff "${foo}" "${bar}"
rc=${?}

rm -f "${foo}" "${bar}"

exit ${rc}
dateutils-0.3.1/test/dconv.001.clit000066400000000000000000000001511241477753400167700ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dconv 2012-03-01
2012-03-01
$

## dconv.1.clit ends here
dateutils-0.3.1/test/dconv.002.clit000066400000000000000000000001661241477753400167770ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dconv -i "%d/%b/%y" 01/Mar/12
2012-03-01
$

## dconv.2.clit ends here
dateutils-0.3.1/test/dconv.003.clit000066400000000000000000000001661241477753400170000ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dconv -f "%d/%b/%y" 2012-03-01
01/Mar/12
$

## dconv.3.clit ends here
dateutils-0.3.1/test/dconv.004.clit000066400000000000000000000002201241477753400167700ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dconv -f "%d/%b/%y" -i "%OY %Om %Od" "MCMXCVIII IX XVII"
17/Sep/98
$

## dconv.4.clit ends here
dateutils-0.3.1/test/dconv.005.clit000066400000000000000000000002161241477753400167760ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dconv -i "%d/%b/%y" -f "%OY %Om %Od" 17/Sep/98
MCMXCVIII IX XVII
$

## dconv.5.clit ends here
dateutils-0.3.1/test/dconv.006.clit000066400000000000000000000001671241477753400170040ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dconv -f "%Y-%jb" "2010-03-01b"
2010-042b
$

## dconv.6.clit ends here
dateutils-0.3.1/test/dconv.007.clit000066400000000000000000000001671241477753400170050ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dconv -f "%Y-%jb" "2012-03-02b"
2012-045b
$

## dconv.7.clit ends here
dateutils-0.3.1/test/dconv.008.clit000066400000000000000000000001671241477753400170060ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dconv -f "%Y-%jb" "2012-05-02b"
2012-088b
$

## dconv.8.clit ends here
dateutils-0.3.1/test/dconv.009.clit000066400000000000000000000043341241477753400170070ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dconv -f "ymd" -S -i "%d/%b/%Y" <2012-03-01 <=2012-03-01 <=2012-11-01' -i "%B/%d/%y" <2012-03-01 <=2012-03-01 <=2012-11-01' -i "%B/%d/%y" < "${foo}"

## strip month and dom from BEG and END in a way that works on dash
BEG=`echo ${BEG} | sed 's/-.*//'`
END=`echo ${END} | sed 's/-.*//'`
for y in `seq ${BEG} ${END}`; do
	"${GDATE}" -d "${y}-01-01" '+%F	%a'
done > "${bar}"

diff "${foo}" "${bar}"
rc=${?}

rm -f "${foo}" "${bar}"

exit ${rc}
dateutils-0.3.1/test/dseq-cnt.3.sh000077500000000000000000000012401241477753400167210ustar00rootroot00000000000000#!/bin/sh

BEG="1917-12-31"
END="4095-12-31"
if test "${have_gdate_2039}" != "yes"; then
	BEG="1970-12-31"
	END="2037-12-31"
fi

if test "${have_gdate}" != "yes"; then
	## SKIP in new automake
	exit 77
fi

TOOLDIR="$(pwd)/../src"

DSEQ="${TOOLDIR}/dseq"

foo=`mktemp "/tmp/tmp.XXXXXXXXXX"`
bar=`mktemp "/tmp/tmp.XXXXXXXXXX"`

"${DSEQ}" "${BEG}" +1y "${END}" -f '%F	%a' > "${foo}"

## strip month and dom from BEG and END in a way that works on dash
BEG=`echo ${BEG} | sed 's/-.*//'`
END=`echo ${END} | sed 's/-.*//'`
for y in `seq ${BEG} ${END}`; do
	"${GDATE}" -d "${y}-12-31" '+%F	%a'
done > "${bar}"

diff "${foo}" "${bar}"
rc=${?}

rm -f "${foo}" "${bar}"

exit ${rc}
dateutils-0.3.1/test/dseq.01.clit000066400000000000000000000006611241477753400165410ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2012-02-01 2012-03-01
2012-02-01
2012-02-02
2012-02-03
2012-02-04
2012-02-05
2012-02-06
2012-02-07
2012-02-08
2012-02-09
2012-02-10
2012-02-11
2012-02-12
2012-02-13
2012-02-14
2012-02-15
2012-02-16
2012-02-17
2012-02-18
2012-02-19
2012-02-20
2012-02-21
2012-02-22
2012-02-23
2012-02-24
2012-02-25
2012-02-26
2012-02-27
2012-02-28
2012-02-29
2012-03-01
$

## dseq.1.clit ends here
dateutils-0.3.1/test/dseq.02.clit000066400000000000000000000007451241477753400165450ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2001-02-03 2001-03-03 --skip sat -f "%F %a"
2001-02-04 Sun
2001-02-05 Mon
2001-02-06 Tue
2001-02-07 Wed
2001-02-08 Thu
2001-02-09 Fri
2001-02-11 Sun
2001-02-12 Mon
2001-02-13 Tue
2001-02-14 Wed
2001-02-15 Thu
2001-02-16 Fri
2001-02-18 Sun
2001-02-19 Mon
2001-02-20 Tue
2001-02-21 Wed
2001-02-22 Thu
2001-02-23 Fri
2001-02-25 Sun
2001-02-26 Mon
2001-02-27 Tue
2001-02-28 Wed
2001-03-01 Thu
2001-03-02 Fri
$

## dseq.2.clit ends here
dateutils-0.3.1/test/dseq.03.clit000066400000000000000000000007731241477753400165470ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq --compute-from-last 2001-02-03 1 2001-03-03 --skip sat -f "%F %a"
2001-02-04 Sun
2001-02-05 Mon
2001-02-06 Tue
2001-02-07 Wed
2001-02-08 Thu
2001-02-09 Fri
2001-02-11 Sun
2001-02-12 Mon
2001-02-13 Tue
2001-02-14 Wed
2001-02-15 Thu
2001-02-16 Fri
2001-02-18 Sun
2001-02-19 Mon
2001-02-20 Tue
2001-02-21 Wed
2001-02-22 Thu
2001-02-23 Fri
2001-02-25 Sun
2001-02-26 Mon
2001-02-27 Tue
2001-02-28 Wed
2001-03-01 Thu
2001-03-02 Fri
$

## dseq.3.clit ends here
dateutils-0.3.1/test/dseq.04.clit000066400000000000000000000003351241477753400165420ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2001-02-03 3 2001-03-03 --skip sat,fri -f "%F %a"
2001-02-06 Tue
2001-02-12 Mon
2001-02-15 Thu
2001-02-18 Sun
2001-02-21 Wed
2001-02-27 Tue
$

## dseq.4.clit ends here
dateutils-0.3.1/test/dseq.05.clit000066400000000000000000000004001241477753400165340ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq --compute-from-last 2001-02-03 3 2001-03-03 --skip sat,fri -f "%F %a"
2001-02-04 Sun
2001-02-07 Wed
2001-02-13 Tue
2001-02-19 Mon
2001-02-22 Thu
2001-02-25 Sun
2001-02-28 Wed
$

## dseq.5.clit ends here
dateutils-0.3.1/test/dseq.06.clit000066400000000000000000000003351241477753400165440ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2001-02-05 4 2001-03-04 -f "%F %a"
2001-02-05 Mon
2001-02-09 Fri
2001-02-13 Tue
2001-02-17 Sat
2001-02-21 Wed
2001-02-25 Sun
2001-03-01 Thu
$

## dseq.6.clit ends here
dateutils-0.3.1/test/dseq.07.clit000066400000000000000000000003611241477753400165440ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq --compute-from-last 2001-02-05 4 2001-03-04 -f "%F %a"
2001-02-08 Thu
2001-02-12 Mon
2001-02-16 Fri
2001-02-20 Tue
2001-02-24 Sat
2001-02-28 Wed
2001-03-04 Sun
$

## dseq.7.clit ends here
dateutils-0.3.1/test/dseq.08.clit000066400000000000000000000004101241477753400165400ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq --alt-inc 1d 2001-02-03 3 2001-03-03 --skip sat,fri -f "%F %a"
2001-02-04 Sun
2001-02-07 Wed
2001-02-11 Sun
2001-02-14 Wed
2001-02-18 Sun
2001-02-21 Wed
2001-02-25 Sun
2001-02-28 Wed
$

## dseq.8.clit ends here
dateutils-0.3.1/test/dseq.09.clit000066400000000000000000000004341241477753400165470ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq --compute-from-last --alt-inc 1d 2001-02-03 3 2001-03-03 --skip sat,fri -f "%F %a"
2001-02-04 Sun
2001-02-07 Wed
2001-02-11 Sun
2001-02-14 Wed
2001-02-18 Sun
2001-02-21 Wed
2001-02-25 Sun
2001-02-28 Wed
$

## dseq.9.clit ends here
dateutils-0.3.1/test/dseq.10.clit000066400000000000000000000002271241477753400165370ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2001-01-01 2d 2001-01-08
2001-01-01
2001-01-03
2001-01-05
2001-01-07
$

## dseq.10.clit ends here
dateutils-0.3.1/test/dseq.11.clit000066400000000000000000000002531241477753400165370ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq --compute-from-last 2001-01-01 2d 2001-01-08
2001-01-02
2001-01-04
2001-01-06
2001-01-08
$

## dseq.11.clit ends here
dateutils-0.3.1/test/dseq.12.clit000066400000000000000000000002301241477753400165330ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2001-01-08 -2d 2001-01-01
2001-01-08
2001-01-06
2001-01-04
2001-01-02
$

## dseq.12.clit ends here
dateutils-0.3.1/test/dseq.13.clit000066400000000000000000000002541241477753400165420ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq --compute-from-last 2001-01-08 -2d 2001-01-01
2001-01-07
2001-01-05
2001-01-03
2001-01-01
$

## dseq.13.clit ends here
dateutils-0.3.1/test/dseq.14.clit000066400000000000000000000002011241477753400165330ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2001-02-03 -1 2001-03-03 --skip sat -f "%F %a"
$

## dseq.14.clit ends here
dateutils-0.3.1/test/dseq.15.clit000066400000000000000000000002051241477753400165400ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2001-02-03 -3 2001-03-03 --skip sat,fri -f "%F %a"
$

## dseq.15.clit ends here
dateutils-0.3.1/test/dseq.16.clit000066400000000000000000000002051241477753400165410ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2001-02-03 -1 2001-02-03 -f "%F %a"
2001-02-03 Sat
$

## dseq.16.clit ends here
dateutils-0.3.1/test/dseq.17.clit000066400000000000000000000002051241477753400165420ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2001-02-05 -4 2001-02-05 -f "%F %a"
2001-02-05 Mon
$

## dseq.17.clit ends here
dateutils-0.3.1/test/dseq.18.clit000066400000000000000000000001661241477753400165510ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2001-01-08 2d 2001-01-08
2001-01-08
$

## dseq.18.clit ends here
dateutils-0.3.1/test/dseq.19.clit000066400000000000000000000002041241477753400165430ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2014-01-12 2014-01-13 -f '%rY-%V'
2014-02
2014-03
$

## dseq.19.clit ends here
dateutils-0.3.1/test/dseq.20.clit000066400000000000000000000002041241477753400165330ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2014-01-12 2014-01-13 -f '%rY-%W'
2014-01
2014-02
$

## dseq.20.clit ends here
dateutils-0.3.1/test/dseq.21.clit000066400000000000000000000002041241477753400165340ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2014-01-12 2014-01-13 -f '%rY-%U'
2014-02
2014-02
$

## dseq.21.clit ends here
dateutils-0.3.1/test/dseq.22.clit000066400000000000000000000002031241477753400165340ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2014-01-12 2014-01-13 -f '%G-%V'
2014-02
2014-03
$

## dseq.22.clit ends here
dateutils-0.3.1/test/dseq.23.clit000066400000000000000000000002031241477753400165350ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2014-01-12 2014-01-13 -f '%G-%W'
2014-01
2014-02
$

## dseq.23.clit ends here
dateutils-0.3.1/test/dseq.24.clit000066400000000000000000000002031241477753400165360ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2014-01-12 2014-01-13 -f '%G-%U'
2014-02
2014-02
$

## dseq.24.clit ends here
dateutils-0.3.1/test/dseq.25.clit000066400000000000000000000003171241477753400165450ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2014-08-18 2014-08-25 -f ywd
2014-W34-01
2014-W34-02
2014-W34-03
2014-W34-04
2014-W34-05
2014-W34-06
2014-W34-07
2014-W35-01
$

## dseq.25.clit ends here
dateutils-0.3.1/test/dseq.26.clit000066400000000000000000000003401241477753400165420ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2014-08-18 2014-08-25 -f ymcw
2014-08-03-01
2014-08-03-02
2014-08-03-03
2014-08-03-04
2014-08-04-05
2014-08-04-06
2014-08-04-00
2014-08-04-01
$

## dseq.26.clit ends here
dateutils-0.3.1/test/dseq.27.clit000066400000000000000000000001721241477753400165460ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

## range is empty
$ dseq 2001-02-03 2001-02-01
$

## dseq.27.clit ends here
dateutils-0.3.1/test/dseq.28.clit000066400000000000000000000001751241477753400165520ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

## range is empty
$ dseq 2001-02-01 -1 2001-02-04
$

## dseq.28.clit ends here
dateutils-0.3.1/test/dseq.29.clit000066400000000000000000000003051241477753400165460ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2012-02 2012-09 -i '%Y-%m'
2012-02-00
2012-03-00
2012-04-00
2012-05-00
2012-06-00
2012-07-00
2012-08-00
2012-09-00
$

## dseq.29.clit ends here
dateutils-0.3.1/test/dseq.30.clit000066400000000000000000000003001241477753400165310ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2012-02-00 2012-09-00
2012-02-00
2012-03-00
2012-04-00
2012-05-00
2012-06-00
2012-07-00
2012-08-00
2012-09-00
$

## dseq.30.clit ends here
dateutils-0.3.1/test/dseq.31.clit000066400000000000000000000002201241477753400165330ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2012 2015 -i '%Y'
2012-00-00
2013-00-00
2014-00-00
2015-00-00
$

## dseq.31.clit ends here
dateutils-0.3.1/test/dseq.32.clit000066400000000000000000000002241241477753400165400ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2012-00-00 2015-00-00
2012-00-00
2013-00-00
2014-00-00
2015-00-00
$

## dseq.32.clit ends here
dateutils-0.3.1/test/dseq.33.clit000066400000000000000000000003051241477753400165410ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2018-01-01 2018-12-30 -f ywd > "dseq.33.ref"
$ dseq 2018-W01-01 2018-W52-07
< dseq.33.ref
$ rm -f -- "dseq.33.ref"
$

## dseq.33.clit ends here
dateutils-0.3.1/test/dseq.34.clit000066400000000000000000000003151241477753400165430ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2018-01-01 2018-12-30 | dconv -f ywd > "dseq.34.ref"
$ dseq 2018-W01-01 2018-W52-07
< dseq.34.ref
$ rm -f -- "dseq.34.ref"
$

## dseq.34.clit ends here
dateutils-0.3.1/test/dseq.35.clit000066400000000000000000000003051241477753400165430ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2018-W01-01 2018-W52-07 -f ymd > "dseq.35.ref"
$ dseq 2018-01-01 2018-12-30
< dseq.35.ref
$ rm -f -- "dseq.35.ref"
$

## dseq.35.clit ends here
dateutils-0.3.1/test/dseq.36.clit000066400000000000000000000003151241477753400165450ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2018-W01-01 2018-W52-07 | dconv -f ymd > "dseq.36.ref"
$ dseq 2018-01-01 2018-12-30
< dseq.36.ref
$ rm -f -- "dseq.36.ref"
$

## dseq.36.clit ends here
dateutils-0.3.1/test/dseq.37.clit000066400000000000000000000003051241477753400165450ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2016-01-01 2017-01-01 -f ywd > "dseq.37.ref"
$ dseq 2015-W53-05 2016-W52-07
< dseq.37.ref
$ rm -f -- "dseq.37.ref"
$

## dseq.37.clit ends here
dateutils-0.3.1/test/dseq.38.clit000066400000000000000000000003151241477753400165470ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2016-01-01 2017-01-01 | dconv -f ywd > "dseq.38.ref"
$ dseq 2015-W53-05 2016-W52-07
< dseq.38.ref
$ rm -f -- "dseq.38.ref"
$

## dseq.38.clit ends here
dateutils-0.3.1/test/dseq.39.clit000066400000000000000000000003051241477753400165470ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2015-W53-05 2016-W52-07 -f ymd > "dseq.39.ref"
$ dseq 2016-01-01 2017-01-01
< dseq.39.ref
$ rm -f -- "dseq.39.ref"
$

## dseq.39.clit ends here
dateutils-0.3.1/test/dseq.40.clit000066400000000000000000000003151241477753400165400ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 2015-W53-05 2016-W52-07 | dconv -f ymd > "dseq.40.ref"
$ dseq 2016-01-01 2017-01-01
< dseq.40.ref
$ rm -f -- "dseq.40.ref"
$

## dseq.40.clit ends here
dateutils-0.3.1/test/dseq.41.clit000066400000000000000000000002321241477753400165370ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq Jan Dec -i '%b' -f '%b'
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec
$

## dseq.41.clit ends here
dateutils-0.3.1/test/dseq.42.clit000066400000000000000000000002371241477753400165450ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq Jan +1mo Dec -i '%b' -f '%b'
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec
$

## dseq.42.clit ends here
dateutils-0.3.1/test/dsort.001.clit000066400000000000000000000011161241477753400170140ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dsort < "${srcdir}/caev_01.txt"
2009-06-03 caev="DVCA" secu="VOD" exch="XLON" xdte="2009-06-03" nett/GBX="5.2"
2010-11-17 caev="DVCA" secu="VOD" exch="XLON" xdte="2010-11-17" nett/GBX="2.85"
2011-11-16 caev="DVCA" secu="VOD" exch="XLON" xdte="2011-11-16" nett/GBX="3.05"
2012-06-06 caev="DVCA" secu="VOD" exch="XLON" xdte="2012-06-06" nett/GBX="6.47"
2013-06-12 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-06-12" nett/GBX="6.92"
2013-11-20 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-11-20" nett/GBX="3.53"
$

## dsort.001.clit ends here
dateutils-0.3.1/test/dsort.002.clit000066400000000000000000000011141241477753400170130ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dsort "${srcdir}/caev_01.txt"
2009-06-03 caev="DVCA" secu="VOD" exch="XLON" xdte="2009-06-03" nett/GBX="5.2"
2010-11-17 caev="DVCA" secu="VOD" exch="XLON" xdte="2010-11-17" nett/GBX="2.85"
2011-11-16 caev="DVCA" secu="VOD" exch="XLON" xdte="2011-11-16" nett/GBX="3.05"
2012-06-06 caev="DVCA" secu="VOD" exch="XLON" xdte="2012-06-06" nett/GBX="6.47"
2013-06-12 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-06-12" nett/GBX="6.92"
2013-11-20 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-11-20" nett/GBX="3.53"
$

## dsort.002.clit ends here
dateutils-0.3.1/test/dsort.003.clit000066400000000000000000000011211241477753400170120ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dsort -r < "${srcdir}/caev_01.txt"
2013-11-20 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-11-20" nett/GBX="3.53"
2013-06-12 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-06-12" nett/GBX="6.92"
2012-06-06 caev="DVCA" secu="VOD" exch="XLON" xdte="2012-06-06" nett/GBX="6.47"
2011-11-16 caev="DVCA" secu="VOD" exch="XLON" xdte="2011-11-16" nett/GBX="3.05"
2010-11-17 caev="DVCA" secu="VOD" exch="XLON" xdte="2010-11-17" nett/GBX="2.85"
2009-06-03 caev="DVCA" secu="VOD" exch="XLON" xdte="2009-06-03" nett/GBX="5.2"
$

## dsort.003.clit ends here
dateutils-0.3.1/test/dsort.004.clit000066400000000000000000000011171241477753400170200ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dsort -r "${srcdir}/caev_01.txt"
2013-11-20 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-11-20" nett/GBX="3.53"
2013-06-12 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-06-12" nett/GBX="6.92"
2012-06-06 caev="DVCA" secu="VOD" exch="XLON" xdte="2012-06-06" nett/GBX="6.47"
2011-11-16 caev="DVCA" secu="VOD" exch="XLON" xdte="2011-11-16" nett/GBX="3.05"
2010-11-17 caev="DVCA" secu="VOD" exch="XLON" xdte="2010-11-17" nett/GBX="2.85"
2009-06-03 caev="DVCA" secu="VOD" exch="XLON" xdte="2009-06-03" nett/GBX="5.2"
$

## dsort.004.clit ends here
dateutils-0.3.1/test/dsort.005.clit000066400000000000000000000011011241477753400170120ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dsort -u < "${srcdir}/caev_02.txt"
2009-06-03 caev="DVCA" secu="VOD" exch="XLON" xdte="2009-06-03" nett/GBX="5.2"
2010-11-17 caev="XXXX" secu="VOD" exch="XLON" xdte="2010-11-17"
2011-11-16 caev="DVCA" secu="VOD" exch="XLON" xdte="2011-11-16" nett/GBX="3.05"
2012-06-06 caev="DVCA" secu="VOD" exch="XLON" xdte="2012-06-06" nett/GBX="6.47"
2013-06-12 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-06-12" nett/GBX="6.92"
2013-11-20 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-11-20" nett/GBX="3.53"
$

## dsort.005.clit ends here
dateutils-0.3.1/test/dsort.006.clit000066400000000000000000000010771241477753400170270ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dsort -u "${srcdir}/caev_02.txt"
2009-06-03 caev="DVCA" secu="VOD" exch="XLON" xdte="2009-06-03" nett/GBX="5.2"
2010-11-17 caev="XXXX" secu="VOD" exch="XLON" xdte="2010-11-17"
2011-11-16 caev="DVCA" secu="VOD" exch="XLON" xdte="2011-11-16" nett/GBX="3.05"
2012-06-06 caev="DVCA" secu="VOD" exch="XLON" xdte="2012-06-06" nett/GBX="6.47"
2013-06-12 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-06-12" nett/GBX="6.92"
2013-11-20 caev="DVCA" secu="VOD" exch="XLON" xdte="2013-11-20" nett/GBX="3.53"
$

## dsort.006.clit ends here
dateutils-0.3.1/test/dtadd.001.clit000066400000000000000000000001751241477753400167450ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dadd 2012-03-01T10:00:00 1d
2012-03-02T10:00:00
$

## dtadd.1.clit ends here
dateutils-0.3.1/test/dtadd.002.clit000066400000000000000000000001751241477753400167460ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dadd 2012-03-01T10:00:00 1m
2012-03-01T10:01:00
$

## dtadd.2.clit ends here
dateutils-0.3.1/test/dtadd.003.clit000066400000000000000000000001761241477753400167500ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dadd 2012-03-31T10:00:00 1mo
2012-04-30T10:00:00
$

## dtadd.3.clit ends here
dateutils-0.3.1/test/dtadd.004.clit000066400000000000000000000004511241477753400167450ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dadd 2w2d <
#include 
#include 
#include "dt-core.h"

#define CHECK_RES(rc, pred, args...)		\
	if (pred) {				\
		fprintf(stderr, args);		\
		res = rc;			\
	}

#define CHECK(pred, args...)			\
	CHECK_RES(1, pred, args)

#define CHECK_EQ(slot, val, args...)		\
	CHECK(slot != val, args, slot, val)

static int
add_d_only(void)
{
	static const char str[] = "2012-03-28";
	struct dt_dt_s d;
	struct dt_dt_s dur;
	int res = 0;

	/* 2012-03-28 (using no format) */
	fprintf(stderr, "testing %s +1d ...\n", str);
	d = dt_strpdt(str, NULL, NULL);

	/* we lack some lovely ctors for this */
	dur.t = dt_t_initialiser();
	dt_make_d_only(&dur, DT_DAISY);
	dur.dur = 1;
	dur.neg = 0;
	dur.d.daisy = 1;

	/* the actual addition */
	d = dt_dtadd(d, dur);

	CHECK(d.d.typ != DT_YMD,
	      "  TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)d.d.typ,
	      (unsigned int)DT_YMD);
	CHECK(d.t.u,
	      "  TIME COMPONENT NOT NAUGHT %" PRIu64 "\n",
	      (uint64_t)d.t.u);
	CHECK(d.dur, "  DURATION BIT SET\n");
	CHECK(d.neg, "  NEGATED BIT SET\n");
	CHECK(d.t.dur, "  TIME DURATION BIT SET\n");
	CHECK(d.t.neg, "  TIME NEGATED BIT SET\n");

	CHECK_EQ((unsigned int)d.d.ymd.y, 2012U,
		 "  YEAR %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.d.ymd.m, 3U,
		 "  MONTH %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.d.ymd.d, 29U,
		 "  DAY %u ... should be %u\n");
	/* make sure the padding leaves no garbage */
	CHECK_RES(res, d.d.ymd.u & ~0x1fffff,
		  "  PADDING NOT NAUGHT %x\n",
		  (unsigned int)(d.d.ymd.u & ~0x1fffff));
	return res;
}

static int
add_t_only(void)
{
	static const char str[] = "12:34:56";
	struct dt_dt_s d;
	struct dt_dt_s dur;
	int res = 0;

	/* 2012-03-28 (using no format) */
	fprintf(stderr, "testing %s +1h ...\n", str);
	d = dt_strpdt(str, NULL, NULL);

	/* we lack some lovely ctors for this */
	dur.d = dt_d_initialiser();
	dt_make_t_only(&dur, DT_TUNK);
	dur.dur = 1;
	dur.neg = 0;
	dur.t.dur = 1;
	dur.t.neg = 0;
	dur.t.sdur = 3600;

	/* the actual addition */
	d = dt_dtadd(d, dur);

	CHECK(d.typ != DT_SANDWICH_UNK,
	      "  TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)d.typ,
	      (unsigned int)DT_SANDWICH_UNK);
	CHECK(d.t.typ != DT_HMS,
	      "  TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)d.t.typ,
	      (unsigned int)DT_HMS);
	CHECK(d.d.u,
	      "  DATE COMPONENT NOT NAUGHT %" PRIu64 "\n",
	      (uint64_t)d.d.u);
	CHECK(d.dur, "  DURATION BIT SET\n");
	CHECK(d.neg, "  NEGATED BIT SET\n");
	CHECK(d.t.dur, "  TIME DURATION BIT SET\n");
	CHECK(d.t.neg, "  TIME NEGATED BIT SET\n");

	CHECK_EQ((unsigned int)d.t.hms.h, 13U,
		 "  HOUR %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.t.hms.m, 34U,
		 "  MINUTE %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.t.hms.s, 56U,
		 "  SECOND %u ... should be %u\n");
	/* make sure the padding leaves no garbage */
	CHECK_RES(res, d.t.hms.u & ~0x1f3f3f3fffffff,
		  "  PADDING NOT NAUGHT %x\n",
		  (unsigned int)(d.t.hms.u & ~0x1f3f3f3fffffff));
	return res;
}

static int
dt_add_d(void)
{
	static const char str[] = "2012-03-28T12:34:56";
	struct dt_dt_s d;
	struct dt_dt_s dur;
	int res = 0;

	fprintf(stderr, "testing %s +1d ...\n", str);
	d = dt_strpdt(str, NULL, NULL);

	/* we lack some lovely ctors for this */
	dur.t = dt_t_initialiser();
	dt_make_d_only(&dur, DT_DAISY);
	dur.dur = 1;
	dur.neg = 0;
	dur.d.daisy = 1;

	/* the actual addition */
	d = dt_dtadd(d, dur);

	CHECK(d.d.typ != DT_YMD,
	      "  TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)d.d.typ,
	      (unsigned int)DT_YMD);
	CHECK(d.dur, "  DURATION BIT SET\n");
	CHECK(d.neg, "  NEGATED BIT SET\n");
	CHECK(d.t.dur, "  TIME DURATION BIT SET\n");
	CHECK(d.t.neg, "  TIME NEGATED BIT SET\n");

	CHECK_EQ((unsigned int)d.d.ymd.y, 2012U,
		 "  YEAR %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.d.ymd.m, 3U,
		 "  MONTH %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.d.ymd.d, 29U,
		 "  DAY %u ... should be %u\n");

	CHECK_EQ((unsigned int)d.t.hms.h, 12U,
		 "  HOUR %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.t.hms.m, 34U,
		 "  MINUTE %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.t.hms.s, 56U,
		 "  SECOND %u ... should be %u\n");

	/* make sure the padding leaves no garbage */
	CHECK_RES(res, d.d.ymd.u & ~0x1fffff,
		  "  PADDING NOT NAUGHT %x\n",
		  (unsigned int)(d.d.ymd.u & ~0x1fffff));
	CHECK_RES(res, d.t.hms.u & ~0x1f3f3f3fffffff,
		  "  TIME PADDING NOT NAUGHT %x\n",
		  (unsigned int)(d.t.hms.u & ~0x1f3f3f3fffffff));
	return res;
}

static int
dt_add_t(void)
{
	static const char str[] = "2012-03-28T23:12:01";
	struct dt_dt_s d;
	struct dt_dt_s dur;
	int res = 0;

	fprintf(stderr, "testing %s +1h ...\n", str);
	d = dt_strpdt(str, NULL, NULL);

	/* we lack some lovely ctors for this */
	dur.d = dt_d_initialiser();
	dt_make_t_only(&dur, DT_TUNK);
	dur.dur = 1;
	dur.neg = 0;
	dur.t.dur = 1;
	dur.t.neg = 0;
	dur.t.sdur = 3600;

	/* the actual addition */
	d = dt_dtadd(d, dur);

	CHECK(d.d.typ != DT_YMD,
	      "  DATE TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)d.d.typ,
	      (unsigned int)DT_YMD);
	CHECK(d.t.typ != DT_HMS,
	      "  TIME TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)d.t.typ,
	      (unsigned int)DT_HMS);
	CHECK(d.dur, "  DURATION BIT SET\n");
	CHECK(d.neg, "  NEGATED BIT SET\n");
	CHECK(d.t.dur, "  TIME DURATION BIT SET\n");
	CHECK(d.t.neg, "  TIME NEGATED BIT SET\n");

	CHECK_EQ((unsigned int)d.d.ymd.y, 2012U,
		 "  YEAR %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.d.ymd.m, 3U,
		 "  MONTH %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.d.ymd.d, 29U,
		 "  DAY %u ... should be %u\n");

	CHECK_EQ((unsigned int)d.t.hms.h, 00U,
		 "  HOUR %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.t.hms.m, 12U,
		 "  MINUTE %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.t.hms.s, 01U,
		 "  SECOND %u ... should be %u\n");

	/* make sure the padding leaves no garbage */
	CHECK_RES(res, d.d.ymd.u & ~0x1fffff,
		  "  PADDING NOT NAUGHT %x\n",
		  (unsigned int)(d.d.ymd.u & ~0x1fffff));
	CHECK_RES(res, d.t.hms.u & ~0x1f3f3f3fffffff,
		  "  TIME PADDING NOT NAUGHT %x\n",
		  (unsigned int)(d.t.hms.u & ~0x1f3f3f3fffffff));
	return res;
}

static int
dt_add_dt(void)
{
	static const char str[] = "2012-03-28T23:55:55";
	struct dt_dt_s d;
	struct dt_dt_s dur;
	int res = 0;

	fprintf(stderr, "testing %s +1d1h ...\n", str);
	d = dt_strpdt(str, NULL, NULL);

	/* we lack some lovely ctors for this */
	dur = dt_dt_initialiser();
	dt_make_sandwich(&dur, DT_DAISY, DT_TUNK);
	dur.dur = 1;
	dur.neg = 0;
	dur.d.daisy = 1;
	dur.t.dur = 1;
	dur.t.neg = 0;
	dur.t.sdur = 3600;

	/* the actual addition */
	d = dt_dtadd(d, dur);

	CHECK(d.d.typ != DT_YMD,
	      "  DATE TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)d.d.typ,
	      (unsigned int)DT_YMD);
	CHECK(d.t.typ != DT_HMS,
	      "  TIME TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)d.t.typ,
	      (unsigned int)DT_HMS);
	CHECK(d.dur, "  DURATION BIT SET\n");
	CHECK(d.neg, "  NEGATED BIT SET\n");
	CHECK(d.t.dur, "  TIME DURATION BIT SET\n");
	CHECK(d.t.neg, "  TIME NEGATED BIT SET\n");

	CHECK_EQ((unsigned int)d.d.ymd.y, 2012U,
		 "  YEAR %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.d.ymd.m, 3U,
		 "  MONTH %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.d.ymd.d, 30U,
		 "  DAY %u ... should be %u\n");

	CHECK_EQ((unsigned int)d.t.hms.h, 00U,
		 "  HOUR %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.t.hms.m, 55U,
		 "  MINUTE %u ... should be %u\n");
	CHECK_EQ((unsigned int)d.t.hms.s, 55U,
		 "  SECOND %u ... should be %u\n");

	/* make sure the padding leaves no garbage */
	CHECK_RES(res, d.d.ymd.u & ~0x1fffff,
		  "  PADDING NOT NAUGHT %x\n",
		  (unsigned int)(d.d.ymd.u & ~0x1fffff));
	CHECK_RES(res, d.t.hms.u & ~0x1f3f3f3fffffff,
		  "  TIME PADDING NOT NAUGHT %x\n",
		  (unsigned int)(d.t.hms.u & ~0x1f3f3f3fffffff));
	return res;
}

int
main(void)
{
	int res = 0;

	/* we just assume the parser works */
	if (add_d_only() != 0) {
		res = 1;
	}

	if (add_t_only() != 0) {
		res = 1;
	}

	if (dt_add_d() != 0) {
		res = 1;
	}

	if (dt_add_t() != 0) {
		res = 1;
	}

	if (dt_add_dt() != 0) {
		res = 1;
	}

	return res;
}

/* dtcore-add.c ends here */
dateutils-0.3.1/test/dtcore-conv.c000066400000000000000000000052441241477753400171020ustar00rootroot00000000000000#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include "dt-core.h"

#define CHECK_RES(rc, pred, args...)		\
	if (pred) {				\
		fprintf(stderr, args);		\
		res = rc;			\
	}

#define CHECK(pred, args...)			\
	CHECK_RES(1, pred, args)

#define CHECK_EQ(slot, val, args...)		\
	CHECK(slot != val, args, slot, val)

static int
conv_chk(struct dt_dt_s tes, struct dt_dt_s ref)
{
	int res = 0;

	CHECK(tes.typ != ref.typ,
	      "  TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)tes.typ,
	      (unsigned int)ref.typ);

	if (!ref.dur) {
		CHECK(tes.dur, "  DURATION BIT SET\n");
	} else {
		CHECK(!tes.dur, "  DURATION BIT NOT SET\n");
	}
	if (!ref.neg) {
		CHECK(tes.neg, "  NEGATED BIT SET\n");
	} else {
		CHECK(!tes.neg, "  NEGATED BIT NOT SET\n");
	}

	if (tes.typ == DT_SEXY || tes.typ == DT_SEXYTAI) {
		/* make sure the padding leaves no garbage */
		CHECK_RES(1, tes.sexy != ref.sexy,
			  "  VALUES DIFFER %u v %u\n",
			  (unsigned int)tes.sexy, (unsigned int)ref.sexy);
	}
	return res;
}

int
main(void)
{
	int rc = 0;
	struct dt_dt_s t;
	struct dt_dt_s res;
	struct dt_dt_s chk;

	/* conv, then check */
	t = dt_dt_initialiser();
	t.sandwich = 1;
	t.d.typ = DT_YMD;
	t.d.ymd.y = 2012;
	t.d.ymd.m = 6;
	t.d.ymd.d = 30;

	t.t.typ = DT_HMS;
	t.t.hms.h = 23;
	t.t.hms.m = 59;
	t.t.hms.s = 59;

	chk = dt_dt_initialiser();
	chk.typ = DT_SEXY;
	chk.sexy = 1341100799;

	if (res = dt_dtconv(DT_SEXY, t), conv_chk(res, chk)) {
		rc = 1;
	}

	/* conv, then check */
	t = dt_dt_initialiser();
	t.sandwich = 1;
	t.d.typ = DT_YMD;
	t.d.ymd.y = 2012;
	t.d.ymd.m = 7;
	t.d.ymd.d = 1;

	t.t.typ = DT_HMS;
	t.t.hms.h = 00;
	t.t.hms.m = 00;
	t.t.hms.s = 00;

	chk = dt_dt_initialiser();
	chk.typ = DT_SEXY;
	chk.sexy = 1341100800;

	if (res = dt_dtconv(DT_SEXY, t), conv_chk(res, chk)) {
		rc = 1;
	}

#if defined WITH_LEAP_SECONDS
	/* conv, then check */
	t = dt_dt_initialiser();
	t.sandwich = 1;
	t.d.typ = DT_YMD;
	t.d.ymd.y = 2012;
	t.d.ymd.m = 6;
	t.d.ymd.d = 30;

	t.t.typ = DT_HMS;
	t.t.hms.h = 23;
	t.t.hms.m = 59;
	t.t.hms.s = 59;

	chk = dt_dt_initialiser();
	chk.typ = DT_SEXYTAI;
	chk.sexy = 1341100799 + 24;

	if (res = dt_dtconv(DT_SEXYTAI, t), conv_chk(res, chk)) {
		rc = 1;
	}

	/* conv, then check */
	t = dt_dt_initialiser();
	t.sandwich = 1;
	t.d.typ = DT_YMD;
	t.d.ymd.y = 2012;
	t.d.ymd.m = 7;
	t.d.ymd.d = 1;

	t.t.typ = DT_HMS;
	t.t.hms.h = 00;
	t.t.hms.m = 00;
	t.t.hms.s = 00;

	chk = dt_dt_initialiser();
	chk.typ = DT_SEXYTAI;
	chk.sexy = 1341100800 + 25;

	if (res = dt_dtconv(DT_SEXYTAI, t), conv_chk(res, chk)) {
		rc = 1;
	}
#endif	/* WITH_LEAP_SECONDS */
	return rc;
}

/* dtcore-conv.c ends here */
dateutils-0.3.1/test/dtcore-strp.c000066400000000000000000000116301241477753400171210ustar00rootroot00000000000000#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include 
#include 
#include "dt-core.h"

#define CHECK_RES(rc, pred, args...)		\
	if (pred) {				\
		fprintf(stderr, args);		\
		res = rc;			\
	}

#define CHECK(pred, args...)			\
	CHECK_RES(1, pred, args)

static int
test_d_only_no_fmt(void)
{
	static const char str[] = "2012-03-28";
	struct dt_dt_s d;
	int res = 0;

	/* 2012-03-28 (using no format) */
	fprintf(stderr, "testing %s ...\n", str);
	d = dt_strpdt(str, NULL, NULL);

	CHECK(d.sandwich,
	      "  IS A SANDWICH ... but should be not\n");
	CHECK(!dt_sandwich_only_d_p(d), "  TYPE is not a d-only\n");
	CHECK(d.d.typ != DT_YMD,
	      "  TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)d.d.typ,
	      (unsigned int)DT_YMD);
	CHECK(d.t.u,
	      "  TIME COMPONENT NOT NAUGHT %" PRIu64 "\n",
	      (uint64_t)d.t.u);
	CHECK(d.dur, "  DURATION BIT SET\n");
	CHECK(d.neg, "  NEGATED BIT SET\n");
	CHECK(d.t.dur, "  TIME DURATION BIT SET\n");
	CHECK(d.t.neg, "  TIME NEGATED BIT SET\n");

	CHECK(d.d.ymd.y != 2012,
	      "  YEAR %u ... should be 2012\n",
	      (unsigned int)d.d.ymd.y);
	CHECK(d.d.ymd.m != 3,
	      "  MONTH %u ... should be 3\n",
	      (unsigned int)d.d.ymd.m);
	CHECK(d.d.ymd.d != 28,
	      "  DAY %u ... should be 28\n",
	      (unsigned int)d.d.ymd.d);
	/* make sure the padding leaves no garbage, not fatal tho */
	CHECK_RES(res, d.d.ymd.u & ~0x1fffff,
		  "  PADDING NOT NAUGHT %x\n",
		  (unsigned int)(d.d.ymd.u & ~0x1fffff));
	return res;
}

static int
test_t_only_no_fmt(void)
{
	static const char str[] = "12:34:56";
	struct dt_dt_s d;
	int res = 0;

	/* 12:34:56 (using no format) */
	fprintf(stderr, "testing %s ...\n", str);
	d = dt_strpdt(str, NULL, NULL);

	CHECK(!d.sandwich,
	      "  NOT A SANDWICH ... but should be\n");
	CHECK(!dt_sandwich_only_t_p(d), "  TYPE is not a t-only\n");
	CHECK(d.typ != DT_SANDWICH_UNK,
	      "  TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)d.typ,
	      (unsigned int)DT_SANDWICH_UNK);
	CHECK(d.t.typ != DT_HMS,
	      "  TIME TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)d.t.typ,
	      (unsigned int)DT_HMS);
	CHECK(d.d.u,
	      "  DATE COMPONENT NOT NAUGHT %" PRIu64 "\n",
	      (uint64_t)d.d.u);
	CHECK(d.dur, "  DURATION BIT SET\n");
	CHECK(d.neg, "  NEGATED BIT SET\n");
	CHECK(d.t.dur, "  TIME DURATION BIT SET\n");
	CHECK(d.t.neg, "  TIME DURATION BIT SET\n");

	CHECK(d.t.hms.h != 12,
		"  HOUR %u ... should be 12\n",
	      (unsigned int)d.t.hms.h);
	CHECK(d.t.hms.m != 34,
	      "  MINUTE %u ... should be 34\n",
	      (unsigned int)d.t.hms.m);
	CHECK(d.t.hms.s != 56,
	      "  SECOND %u ... should be 56\n",
	      (unsigned int)d.t.hms.s);
	CHECK(d.t.hms.ns != 0,
	      "  NANOSECOND %u ... should be 0\n",
	      (unsigned int)d.t.hms.ns);
	/* make sure the padding leaves no garbage */
	CHECK_RES(res, d.t.hms.u & ~0x1f3f3f3fffffff,
		  "  PADDING NOT NAUGHT %x\n",
		  (unsigned int)(d.t.hms.u & ~0x1f3f3f3fffffff));
	return res;
}

static int
test_dt_no_fmt(void)
{
	static const char str[] = "2012-03-28 12:34:56";
	struct dt_dt_s d;
	int res = 0;

	fprintf(stderr, "testing %s ...\n", str);
	d = dt_strpdt(str, NULL, NULL);

	CHECK(!d.sandwich,
	      "  NOT A SANDWICH ... but should be\n");
	CHECK(!dt_sandwich_p(d), "  TYPE is not a sandwich\n");
	CHECK(d.d.typ != DT_YMD,
	      "  TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)d.d.typ,
	      (unsigned int)DT_YMD);
	CHECK(d.t.typ != DT_HMS,
	      "  TIME TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)d.t.typ,
	      (unsigned int)DT_HMS);

	CHECK(d.dur, "  DURATION BIT SET\n");
	CHECK(d.neg, "  NEGATED BIT SET\n");
	CHECK(d.t.dur, "  TIME DURATION BIT SET\n");
	CHECK(d.t.neg, "  TIME DURATION BIT SET\n");

	CHECK(d.d.ymd.y != 2012,
	      "  YEAR %u ... should be 2012\n",
	      (unsigned int)d.d.ymd.y);
	CHECK(d.d.ymd.m != 3,
	      "  MONTH %u ... should be 3\n",
	      (unsigned int)d.d.ymd.m);
	CHECK(d.d.ymd.d != 28,
	      "  DAY %u ... should be 28\n",
	      (unsigned int)d.d.ymd.d);

	CHECK(d.t.hms.h != 12,
		"  HOUR %u ... should be 12\n",
	      (unsigned int)d.t.hms.h);
	CHECK(d.t.hms.m != 34,
	      "  MINUTE %u ... should be 34\n",
	      (unsigned int)d.t.hms.m);
	CHECK(d.t.hms.s != 56,
	      "  SECOND %u ... should be 56\n",
	      (unsigned int)d.t.hms.s);
	CHECK(d.t.hms.ns != 0,
	      "  NANOSECOND %u ... should be 0\n",
	      (unsigned int)d.t.hms.ns);

	/* make sure the padding leaves no garbage */
	CHECK_RES(res, d.d.ymd.u & ~0x1fffff,
		  "  PADDING NOT NAUGHT %x\n",
		  (unsigned int)(d.d.ymd.u & ~0x1fffff));
	CHECK_RES(res, d.t.hms.u & ~0x1f3f3f3fffffff,
		  "  PADDING NOT NAUGHT %x\n",
		  (unsigned int)(d.t.hms.u & ~0x1f3f3f3fffffff));
	return res;
}

int
main(void)
{
	int res = 0;

	if (test_d_only_no_fmt() != 0) {
		res = 1;
	}

	if (test_t_only_no_fmt() != 0) {
		res = 1;
	}

	if (test_dt_no_fmt() != 0) {
		res = 1;
	}

	return res;
}

/* dtcore-strpd.c ends here */
dateutils-0.3.1/test/dtdiff.001.clit000066400000000000000000000002011241477753400171130ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-03-02T10:04:00 2012-03-02T10:14:00
600s
$

## dtdiff.1.clit ends here
dateutils-0.3.1/test/dtdiff.002.clit000066400000000000000000000002101241477753400171140ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-03-02T10:04:00 2012-03-02T10:14:00 -f '%S'
600
$

## dtdiff.2.clit ends here
dateutils-0.3.1/test/dtdiff.003.clit000066400000000000000000000002171241477753400171240ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-03-02T10:04:00 2012-03-02T10:14:00 -f '%M min'
10 min
$

## dtdiff.3.clit ends here
dateutils-0.3.1/test/dtdiff.004.clit000066400000000000000000000002021241477753400171170ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-03-02T10:14:00 2012-03-02T10:04:00
-600s
$

## dtdiff.4.clit ends here
dateutils-0.3.1/test/dtdiff.005.clit000066400000000000000000000001651241477753400171300ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-03-02T10:14:00 2012-03-03
1
$

## dtdiff.5.clit ends here
dateutils-0.3.1/test/dtdiff.006.clit000066400000000000000000000001761241477753400171330ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-03-02 2012-03-03T10:14:00 -f '%F'
1d
$

## dtdiff.6.clit ends here
dateutils-0.3.1/test/dtdiff.007.clit000066400000000000000000000001661241477753400171330ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-03-03T10:14:00 2012-03-02
-1
$

## dtdiff.7.clit ends here
dateutils-0.3.1/test/dtdiff.008.clit000066400000000000000000000001771241477753400171360ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-03-03 2012-03-02T10:14:00 -f '%F'
-1d
$

## dtdiff.8.clit ends here
dateutils-0.3.1/test/dtdiff.009.clit000066400000000000000000000001641241477753400171330ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ?2 ddiff 12:14:00 2012-03-02T10:14:00
$

## dtdiff.9.clit ends here
dateutils-0.3.1/test/dtdiff.010.clit000066400000000000000000000001541241477753400171220ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ?2 ddiff 2012-03-02 10:14:00
$

## dtdiff.10.clit ends here
dateutils-0.3.1/test/dtdiff.011.clit000066400000000000000000000002041241477753400171170ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-03-01T12:17:00 2012-03-02T14:00:00
92580s
$

## dtdiff.11.clit ends here
dateutils-0.3.1/test/dtdiff.012.clit000066400000000000000000000002611241477753400171230ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-03-01T12:17:00 2012-03-02T14:00:00 -f '%d days and %S seconds'
1 days and 6180 seconds
$

## dtdiff.12.clit ends here
dateutils-0.3.1/test/dtdiff.013.clit000066400000000000000000000002351241477753400171250ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-03-25T01:45:00 2012-03-25T03:15:00 --from-zone Europe/Berlin
1800s
$

## dtdiff.13.clit ends here
dateutils-0.3.1/test/dtdiff.014.clit000066400000000000000000000002351241477753400171260ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-03-25T01:45:00 2012-03-25T02:15:00 --from-zone Europe/Berlin
1800s
$

## dtdiff.14.clit ends here
dateutils-0.3.1/test/dtdiff.015.clit000066400000000000000000000002351241477753400171270ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-10-28T01:45:00 2012-10-28T02:15:00 --from-zone Europe/Berlin
5400s
$

## dtdiff.15.clit ends here
dateutils-0.3.1/test/dtdiff.016.clit000066400000000000000000000002351241477753400171300ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff 2012-10-28T01:45:00 2012-10-28T03:15:00 --from-zone Europe/Berlin
9000s
$

## dtdiff.16.clit ends here
dateutils-0.3.1/test/dtdiff.017.clit000066400000000000000000000002051241477753400171260ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff '2012-06-30 23:59:00' '2012-07-01 00:00:00'
60s
$

## dtdiff.17.clit ends here
dateutils-0.3.1/test/dtdiff.018.clit000066400000000000000000000002051241477753400171270ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff '2012-06-30 23:59:00' '2012-06-30 23:59:60'
60s
$

## dtdiff.18.clit ends here
dateutils-0.3.1/test/dtdiff.019.clit000066400000000000000000000002171241477753400171330ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff '2012-06-30 23:59:00' '2012-07-01 00:00:00' -f '%rSs'
61s
$

## dtdiff.19.clit ends here
dateutils-0.3.1/test/dtdiff.020.clit000066400000000000000000000002171241477753400171230ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff '2012-06-30 23:59:00' '2012-06-30 23:59:60' -f '%rSs'
60s
$

## dtdiff.20.clit ends here
dateutils-0.3.1/test/dtdiff.021.clit000066400000000000000000000002161241477753400171230ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff '2012-06-30 23:59:00' '2012-07-01 00:00:00' -f '%rT'
61s
$

## dtdiff.21.clit ends here
dateutils-0.3.1/test/dtdiff.022.clit000066400000000000000000000002161241477753400171240ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff '2012-06-30 23:59:00' '2012-06-30 23:59:60' -f '%rT'
60s
$

## dtdiff.22.clit ends here
dateutils-0.3.1/test/dtdiff.023.clit000066400000000000000000000002151241477753400171240ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff '2012-05-01 14:00:00' '2012-05-10 15:00:00' -f '%db'
7b
$

## dtdiff.23.clit ends here
dateutils-0.3.1/test/dtdiff.024.clit000066400000000000000000000002161241477753400171260ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff '2012-05-30 14:00:00' '2012-05-18 17:00:00' -f '%db'
-8b
$

## dtdiff.24.clit ends here
dateutils-0.3.1/test/dtdiff.025.clit000066400000000000000000000002311241477753400171240ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff '2012-05-30 14:00:00' '2012-05-18 17:00:00' -f 'bizsi'
-7bT21:00:00
$

## dtdiff.25.clit ends here
dateutils-0.3.1/test/dtdiff.026.clit000066400000000000000000000002301241477753400171240ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff '2012-05-01 14:00:00' '2012-05-10 15:00:00' -f 'bizsi'
7bT01:00:00
$

## dtdiff.26.clit ends here
dateutils-0.3.1/test/dtdiff.027.clit000066400000000000000000000002401241477753400171260ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff --from-zone Australia/Sydney 2013-04-15T08:30:00 2013-04-15T09:00:00
1800s
$

## dtdiff.27.clit ends here
dateutils-0.3.1/test/dtdiff.028.clit000066400000000000000000000002521241477753400171320ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ddiff --from-zone Australia/Sydney 2013-04-15T08:30:00 <16:00:00 <=11:00:00' < 2012-03-25T03:00:00+02:00	Europe/Berlin
$

## dzone.005.clit ends here
dateutils-0.3.1/test/dzone.006.clit000066400000000000000000000002721241477753400170070ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dzone --prev Europe/Berlin 2014-02-22
2013-10-27T03:00:00+02:00 <- 2013-10-27T02:00:00+01:00	Europe/Berlin
$

## dzone.006.clit ends here
dateutils-0.3.1/test/dzone.007.clit000066400000000000000000000002771241477753400170150ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

## Singapore stopped transitioning in 1982
$ dzone --next Asia/Singapore 2014-02-22
never -> never	Asia/Singapore
$

## dzone.007.clit ends here
dateutils-0.3.1/test/dzone.008.clit000066400000000000000000000002741241477753400170130ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dzone --prev Asia/Singapore 2014-02-22
1982-01-01T00:00:00+07:30 <- 1982-01-01T00:30:00+08:00	Asia/Singapore
$

## dzone.008.clit ends here
dateutils-0.3.1/test/enum-1.c000066400000000000000000000010411241477753400157500ustar00rootroot00000000000000#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include "dt-core.h"

int
main(void)
{
	int res = 0;

	if ((unsigned int)DT_PACK != (unsigned int)DT_NDTYP) {
		fprintf(stderr, "DT_PACK %u != DT_NDTYP %u\n",
			(unsigned int)DT_PACK, (unsigned int)DT_NDTYP);
		res = 1;
	}
	if ((unsigned int)DT_SEXY != (unsigned int)(DT_NDTYP + 1U)) {
		fprintf(stderr, "DT_SEXY %u != DT_NTYP + 1 %u\n",
			(unsigned int)DT_SEXY, (unsigned int)(DT_NDTYP + 1U));
		res = 1;
	}
	return res;
}

/* enum-1.c ends here */
dateutils-0.3.1/test/prchunk.001.clit000066400000000000000000000001531241477753400173330ustar00rootroot00000000000000#!/usr/bin/clitoris

$ printf "2014-08-08\n" | dconv
2014-08-08
$ printf "2014-08-08" | dconv
2014-08-08
$
dateutils-0.3.1/test/prchunk.002.clit000066400000000000000000000001571241477753400173400ustar00rootroot00000000000000#!/usr/bin/clitoris

$ printf "2014-08-08\n" | dadd +1
2014-08-09
$ printf "2014-08-08" | dadd +1
2014-08-09
$
dateutils-0.3.1/test/prchunk.003.clit000066400000000000000000000001571241477753400173410ustar00rootroot00000000000000#!/usr/bin/clitoris

$ printf "2014-08-08\n" | ddiff 2014-08-01
7
$ printf "2014-08-08" | ddiff 2014-08-01
7
$
dateutils-0.3.1/test/prchunk.004.clit000066400000000000000000000001651241477753400173410ustar00rootroot00000000000000#!/usr/bin/clitoris

$ printf "2014-08-08\n" | dround Mon
2014-08-11
$ printf "2014-08-08" | dround Mon
2014-08-11
$
dateutils-0.3.1/test/prchunk.005.clit000066400000000000000000000002071241477753400173370ustar00rootroot00000000000000#!/usr/bin/clitoris

$ printf "2014-08-08\n" | dgrep '>2014-01-01'
2014-08-08
$ printf "2014-08-08" | dgrep '>2014-01-01'
2014-08-08
$
dateutils-0.3.1/test/prchunk.006.clit000066400000000000000000000002011241477753400173320ustar00rootroot00000000000000#!/usr/bin/clitoris

$ printf "2014-08-08\n" | strptime -i '%F'
2014-08-08
$ printf "2014-08-08" | strptime -i '%F'
2014-08-08
$
dateutils-0.3.1/test/strptime.001.clit000066400000000000000000000002111241477753400175230ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ strptime -i '%a, %b-%d/%Y' 'Mon, May-01/2000'
2000-05-01
$

## strptime.1.clit ends here
dateutils-0.3.1/test/strptime.002.clit000066400000000000000000000002541241477753400175330ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ strptime -i '%a, %b-%d/%Y' <
#include 
#include "dt-core.h"

int
main(void)
{
	struct dt_dt_s dt;

	memset(&dt, 0, sizeof(dt));
	dt.sexy = 0x1fffffffffffff;
	if (dt.typ != DT_UNK || dt.dur || dt.neg) {
		return 1;
	}
	return 0;
}

/* struct-6.c ends here */
dateutils-0.3.1/test/struct-7.c000066400000000000000000000015601241477753400163440ustar00rootroot00000000000000#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include "dt-core.h"

int
main(void)
{
	int res = 0;
#if !defined __uint128_t_defined
	typedef struct {
		uint64_t l;
		uint64_t h;
	} uint128_t;
#define __uint128_t_defined
#endif	/* !uint128_t */
#if !defined __uint160_t_defined
	typedef struct {
		uint32_t l[5];
	} uint160_t;
#define __uint160_t_defined
#endif	/* !uint160_t */

#define CHECK_SIZE(x, y)						\
	if (sizeof(x) != sizeof(y)) {					\
		fprintf(						\
			stderr,						\
			"sizeof(" #x ") -> %zu\t"			\
			"sizeof(" #y ") -> %zu\n",			\
			sizeof(x), sizeof(y));				\
		res = 1;						\
	}

	CHECK_SIZE(struct dt_dt_s, uint128_t);
	CHECK_SIZE(struct dt_d_s, uint64_t);
	CHECK_SIZE(struct dt_t_s, uint64_t);
	CHECK_SIZE(dt_ymdhms_t, uint64_t);
	CHECK_SIZE(dt_sexy_t, uint64_t);
	return res;
}

/* struct-7.c ends here */
dateutils-0.3.1/test/struct-8.c000066400000000000000000000010451241477753400163430ustar00rootroot00000000000000#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include "date-core.h"

int
main(void)
{
	int res = 0;

#define CHECK_SIZE(x, y)						\
	if (sizeof(x) != sizeof(y)) {					\
		fprintf(stderr, "sizeof(" #x ") -> %zu\n", sizeof(x));	\
		res = 1;						\
	}

	CHECK_SIZE(struct dt_d_s, uint64_t);
	CHECK_SIZE(dt_ymd_t, uint32_t);
	CHECK_SIZE(dt_ymcw_t, uint32_t);
	CHECK_SIZE(dt_bizda_t, uint32_t);
	CHECK_SIZE(dt_md_t, uint32_t);
	CHECK_SIZE(dt_daisy_t, uint32_t);
	return res;
}

/* struct-8.c ends here */
dateutils-0.3.1/test/struct-9.c000066400000000000000000000007131241477753400163450ustar00rootroot00000000000000#if defined HAVE_CONFIG_H
# include "config.h"
#endif	/* HAVE_CONFIG_H */
#include 
#include "time-core.h"

int
main(void)
{
	int res = 0;

#define CHECK_SIZE(x, y)						\
	if (sizeof(x) != sizeof(y)) {					\
		fprintf(stderr, "sizeof(" #x ") -> %zu\n", sizeof(x));	\
		res = 1;						\
	}

	CHECK_SIZE(struct dt_t_s, uint64_t);
	CHECK_SIZE(dt_hms_t, struct {
		uint64_t foo:56;
	} __attribute__((packed)));
	return res;
}

/* struct-9.c ends here */
dateutils-0.3.1/test/tadd.001.clit000066400000000000000000000001501241477753400165720ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dadd 10:01:00 1h6m
11:07:00
$

## tadd.1.clit ends here
dateutils-0.3.1/test/tadd.002.clit000066400000000000000000000001511241477753400165740ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dadd 10:01:00 -1h6m
08:55:00
$

## tadd.2.clit ends here
dateutils-0.3.1/test/tadd.003.clit000066400000000000000000000001511241477753400165750ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dadd 10:01:00 3605s
11:01:05
$

## tadd.3.clit ends here
dateutils-0.3.1/test/tadd.004.clit000066400000000000000000000002031241477753400165740ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dadd 12m <=12:00:00' <=12:00:00' <
#include 
#include 
#include "time-core.h"

#define CHECK_RES(rc, pred, args...)		\
	if (pred) {				\
		fprintf(stderr, args);		\
		res = rc;			\
	}

#define CHECK(pred, args...)			\
	CHECK_RES(1, pred, args)

#define CHECK_EQ(slot, val, args...)		\
	CHECK(slot != val, args, slot, val)

static int
add_chk(struct dt_t_s tes, struct dt_t_s ref)
{
	int res = 0;

	CHECK(tes.typ != ref.typ,
	      "  TYPE DIFFERS %u ... should be %u\n",
	      (unsigned int)tes.typ,
	      (unsigned int)ref.typ);

	if (!ref.dur) {
		CHECK(tes.dur, "  DURATION BIT SET\n");
	} else {
		CHECK(!tes.dur, "  DURATION BIT NOT SET\n");
	}
	if (!ref.neg) {
		CHECK(tes.neg, "  NEGATED BIT SET\n");
	} else {
		CHECK(!tes.neg, "  NEGATED BIT NOT SET\n");
	}

	if (tes.typ == DT_HMS) {
		CHECK_EQ((unsigned int)tes.hms.h, (unsigned int)ref.hms.h,
			 "  HOUR %u ... should be %u\n");
		CHECK_EQ((unsigned int)tes.hms.m, (unsigned int)ref.hms.m,
			 "  MINUTE %u ... should be %u\n");
		CHECK_EQ((unsigned int)tes.hms.s, (unsigned int)ref.hms.s,
			 "  SECOND %u ... should be %u\n");
		/* make sure the padding leaves no garbage */
		CHECK_RES(res, tes.hms.u & ~0x1f3f3f3fffffff,
			  "  PADDING NOT NAUGHT %x\n",
			  (unsigned int)(tes.hms.u & ~0x1f3f3f3fffffff));
	}

	CHECK(tes.carry != ref.carry,
	      "  CARRY DIFFERS %d ... should be %d\n",
	      (signed int)tes.carry,
	      (signed int)ref.carry);
	return res;
}

int
main(void)
{
	int rc = 0;
	struct dt_t_s t;
	struct dt_t_s dur;
	struct dt_t_s res;
	struct dt_t_s chk;

	/* 12:34:56 + 17s */
	t = dt_t_initialiser();
	t.typ = DT_HMS;
	t.hms.h = 12;
	t.hms.m = 34;
	t.hms.s = 56;

	dur = dt_t_initialiser();
	dur.sdur = 17;
	dur.dur = 1;

	/* should be 12:35:13 */
	chk = dt_t_initialiser();
	chk.typ = DT_HMS;
	chk.hms.h = 12;
	chk.hms.m = 35;
	chk.hms.s = 13;

	/* add, then check */
	if (res = dt_tadd(t, dur, 0), add_chk(res, chk)) {
		rc = 1;
	}


	/* 12:34:56 + 11*3600s + 25*60s + 4s */
	t = dt_t_initialiser();
	t.typ = DT_HMS;
	t.hms.h = 12;
	t.hms.m = 34;
	t.hms.s = 56;

	dur = dt_t_initialiser();
	dur.sdur = 11 * 3600 + 25 * 60 + 4;
	dur.dur = 1;

	/* should be 00:00:00 */
	chk = dt_t_initialiser();
	chk.typ = DT_HMS;
	chk.hms.h = 00;
	chk.hms.m = 00;
	chk.hms.s = 00;
	chk.carry = 1;

	/* add, then check */
	if (res = dt_tadd(t, dur, 0), add_chk(res, chk)) {
		rc = 1;
	}


	/* 12:34:56 + 11*3600s + 25*60s + 4s on a leap day */
	t = dt_t_initialiser();
	t.typ = DT_HMS;
	t.hms.h = 12;
	t.hms.m = 34;
	t.hms.s = 56;

	dur = dt_t_initialiser();
	dur.sdur = 11 * 3600 + 25 * 60 + 4;
	dur.dur = 1;

	/* should be 00:00:00 */
	chk = dt_t_initialiser();
	chk.typ = DT_HMS;
	chk.hms.h = 23;
	chk.hms.m = 59;
	chk.hms.s = 60;
	chk.carry = 0;

	/* add, then check */
	if (res = dt_tadd(t, dur, 1), add_chk(res, chk)) {
		rc = 1;
	}


	/* 12:34:56 + 11*3600s + 25*60s + 3s on a -leap day */
	t = dt_t_initialiser();
	t.typ = DT_HMS;
	t.hms.h = 12;
	t.hms.m = 34;
	t.hms.s = 56;

	dur = dt_t_initialiser();
	dur.sdur = 11 * 3600 + 25 * 60 + 3;
	dur.dur = 1;

	/* should be 00:00:00 */
	chk = dt_t_initialiser();
	chk.typ = DT_HMS;
	chk.hms.h = 00;
	chk.hms.m = 00;
	chk.hms.s = 00;
	chk.carry = 1;

	/* add, then check */
	if (res = dt_tadd(t, dur, -1), add_chk(res, chk)) {
		rc = 1;
	}


	/* 12:34:56 + 11*3600s + 25*60s + 2s on a -leap day */
	t = dt_t_initialiser();
	t.typ = DT_HMS;
	t.hms.h = 12;
	t.hms.m = 34;
	t.hms.s = 56;

	dur = dt_t_initialiser();
	dur.sdur = 11 * 3600 + 25 * 60 + 2;
	dur.dur = 1;

	/* should be 00:00:00 */
	chk = dt_t_initialiser();
	chk.typ = DT_HMS;
	chk.hms.h = 23;
	chk.hms.m = 59;
	chk.hms.s = 58;
	chk.carry = 0;

	/* add, then check */
	if (res = dt_tadd(t, dur, -1), add_chk(res, chk)) {
		rc = 1;
	}


	/* 12:34:56 + 11*3600s + 25*60s + 3s on a +leap day */
	t = dt_t_initialiser();
	t.typ = DT_HMS;
	t.hms.h = 12;
	t.hms.m = 34;
	t.hms.s = 56;

	dur = dt_t_initialiser();
	dur.sdur = 11 * 3600 + 25 * 60 + 3;
	dur.dur = 1;

	/* should be 00:00:00 */
	chk = dt_t_initialiser();
	chk.typ = DT_HMS;
	chk.hms.h = 23;
	chk.hms.m = 59;
	chk.hms.s = 59;
	chk.carry = 0;

	/* add, then check */
	if (res = dt_tadd(t, dur, 1), add_chk(res, chk)) {
		rc = 1;
	}
	return rc;
}

/* time-core-add.c ends here */
dateutils-0.3.1/test/tround.001.clit000066400000000000000000000001521241477753400171730ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dround 17:04:00 1m
17:04:00
$

## tround.1.clit ends here
dateutils-0.3.1/test/tround.002.clit000066400000000000000000000001551241477753400171770ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dround -n 17:04:00 1m
17:05:00
$

## tround.2.clit ends here
dateutils-0.3.1/test/tround.003.clit000066400000000000000000000001521241477753400171750ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dround 17:04:00 5m
17:05:00
$

## tround.3.clit ends here
dateutils-0.3.1/test/tround.004.clit000066400000000000000000000001551241477753400172010ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dround -n 17:04:00 5m
17:05:00
$

## tround.4.clit ends here
dateutils-0.3.1/test/tseq.01.clit000066400000000000000000000002461241477753400165600ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 10:00:00 12m 11:20:00
10:00:00
10:12:00
10:24:00
10:36:00
10:48:00
11:00:00
11:12:00
$

## tseq.1.clit ends here
dateutils-0.3.1/test/tseq.02.clit000066400000000000000000000002721241477753400165600ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq --compute-from-last 10:00:00 12m 11:20:00
10:08:00
10:20:00
10:32:00
10:44:00
10:56:00
11:08:00
11:20:00
$

## tseq.2.clit ends here
dateutils-0.3.1/test/tseq.03.clit000066400000000000000000000002471241477753400165630ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 11:20:00 -12m 10:00:00
11:20:00
11:08:00
10:56:00
10:44:00
10:32:00
10:20:00
10:08:00
$

## tseq.3.clit ends here
dateutils-0.3.1/test/tseq.04.clit000066400000000000000000000002731241477753400165630ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq --compute-from-last 11:20:00 -12m 10:00:00
11:12:00
11:00:00
10:48:00
10:36:00
10:24:00
10:12:00
10:00:00
$

## tseq.4.clit ends here
dateutils-0.3.1/test/tseq.05.clit000066400000000000000000000011161241477753400165610ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 10:00:00 -12m 23:20:00
10:00:00
09:48:00
09:36:00
09:24:00
09:12:00
09:00:00
08:48:00
08:36:00
08:24:00
08:12:00
08:00:00
07:48:00
07:36:00
07:24:00
07:12:00
07:00:00
06:48:00
06:36:00
06:24:00
06:12:00
06:00:00
05:48:00
05:36:00
05:24:00
05:12:00
05:00:00
04:48:00
04:36:00
04:24:00
04:12:00
04:00:00
03:48:00
03:36:00
03:24:00
03:12:00
03:00:00
02:48:00
02:36:00
02:24:00
02:12:00
02:00:00
01:48:00
01:36:00
01:24:00
01:12:00
01:00:00
00:48:00
00:36:00
00:24:00
00:12:00
00:00:00
23:48:00
23:36:00
23:24:00
$

## tseq.5.clit ends here
dateutils-0.3.1/test/tseq.06.clit000066400000000000000000000011151241477753400165610ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 23:20:00 12m 10:00:00
23:20:00
23:32:00
23:44:00
23:56:00
00:08:00
00:20:00
00:32:00
00:44:00
00:56:00
01:08:00
01:20:00
01:32:00
01:44:00
01:56:00
02:08:00
02:20:00
02:32:00
02:44:00
02:56:00
03:08:00
03:20:00
03:32:00
03:44:00
03:56:00
04:08:00
04:20:00
04:32:00
04:44:00
04:56:00
05:08:00
05:20:00
05:32:00
05:44:00
05:56:00
06:08:00
06:20:00
06:32:00
06:44:00
06:56:00
07:08:00
07:20:00
07:32:00
07:44:00
07:56:00
08:08:00
08:20:00
08:32:00
08:44:00
08:56:00
09:08:00
09:20:00
09:32:00
09:44:00
09:56:00
$

## tseq.6.clit ends here
dateutils-0.3.1/test/tseq.07.clit000066400000000000000000000002701241477753400165630ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 23:20:00 20m 02:00:00
23:20:00
23:40:00
00:00:00
00:20:00
00:40:00
01:00:00
01:20:00
01:40:00
02:00:00
$

## tseq.7.clit ends here
dateutils-0.3.1/test/tseq.08.clit000066400000000000000000000002711241477753400165650ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 02:00:00 -20m 23:20:00
02:00:00
01:40:00
01:20:00
01:00:00
00:40:00
00:20:00
00:00:00
23:40:00
23:20:00
$

## tseq.8.clit ends here
dateutils-0.3.1/test/tseq.09.clit000066400000000000000000000003131241477753400165630ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 02:00:00 +30m 07:00:00
02:00:00
02:30:00
03:00:00
03:30:00
04:00:00
04:30:00
05:00:00
05:30:00
06:00:00
06:30:00
07:00:00
$

## tseq.9.clit ends here
dateutils-0.3.1/test/tseq.10.clit000066400000000000000000000002371241477753400165600ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 02:00:00 +60m 07:00:00
02:00:00
03:00:00
04:00:00
05:00:00
06:00:00
07:00:00
$

## tseq.10.clit ends here
dateutils-0.3.1/test/tseq.11.clit000066400000000000000000000002361241477753400165600ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 02:00:00 +1h 07:00:00
02:00:00
03:00:00
04:00:00
05:00:00
06:00:00
07:00:00
$

## tseq.11.clit ends here
dateutils-0.3.1/test/tseq.12.clit000066400000000000000000000004701241477753400165610ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 01:00:00 +60m 23:00:00
01:00:00
02:00:00
03:00:00
04:00:00
05:00:00
06:00:00
07:00:00
08:00:00
09:00:00
10:00:00
11:00:00
12:00:00
13:00:00
14:00:00
15:00:00
16:00:00
17:00:00
18:00:00
19:00:00
20:00:00
21:00:00
22:00:00
23:00:00
$

## tseq.12.clit ends here
dateutils-0.3.1/test/tseq.13.clit000066400000000000000000000004671241477753400165700ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 01:00:00 +1h 23:00:00
01:00:00
02:00:00
03:00:00
04:00:00
05:00:00
06:00:00
07:00:00
08:00:00
09:00:00
10:00:00
11:00:00
12:00:00
13:00:00
14:00:00
15:00:00
16:00:00
17:00:00
18:00:00
19:00:00
20:00:00
21:00:00
22:00:00
23:00:00
$

## tseq.13.clit ends here
dateutils-0.3.1/test/tseq.14.clit000066400000000000000000000004701241477753400165630ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 01:20:00 +60m 23:20:00
01:20:00
02:20:00
03:20:00
04:20:00
05:20:00
06:20:00
07:20:00
08:20:00
09:20:00
10:20:00
11:20:00
12:20:00
13:20:00
14:20:00
15:20:00
16:20:00
17:20:00
18:20:00
19:20:00
20:20:00
21:20:00
22:20:00
23:20:00
$

## tseq.14.clit ends here
dateutils-0.3.1/test/tseq.15.clit000066400000000000000000000004671241477753400165720ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 01:20:00 +1h 23:20:00
01:20:00
02:20:00
03:20:00
04:20:00
05:20:00
06:20:00
07:20:00
08:20:00
09:20:00
10:20:00
11:20:00
12:20:00
13:20:00
14:20:00
15:20:00
16:20:00
17:20:00
18:20:00
19:20:00
20:20:00
21:20:00
22:20:00
23:20:00
$

## tseq.15.clit ends here
dateutils-0.3.1/test/tseq.16.clit000066400000000000000000000005001241477753400165570ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 01:00:00 +1h 00:00:00
01:00:00
02:00:00
03:00:00
04:00:00
05:00:00
06:00:00
07:00:00
08:00:00
09:00:00
10:00:00
11:00:00
12:00:00
13:00:00
14:00:00
15:00:00
16:00:00
17:00:00
18:00:00
19:00:00
20:00:00
21:00:00
22:00:00
23:00:00
00:00:00
$

## tseq.16.clit ends here
dateutils-0.3.1/test/tseq.17.clit000066400000000000000000000005001241477753400165600ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 01:00:00 -1h 02:00:00
01:00:00
00:00:00
23:00:00
22:00:00
21:00:00
20:00:00
19:00:00
18:00:00
17:00:00
16:00:00
15:00:00
14:00:00
13:00:00
12:00:00
11:00:00
10:00:00
09:00:00
08:00:00
07:00:00
06:00:00
05:00:00
04:00:00
03:00:00
02:00:00
$

## tseq.17.clit ends here
dateutils-0.3.1/test/tseq.18.clit000066400000000000000000000005111241477753400165630ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 01:00:00 +1h 01:00:00
01:00:00
02:00:00
03:00:00
04:00:00
05:00:00
06:00:00
07:00:00
08:00:00
09:00:00
10:00:00
11:00:00
12:00:00
13:00:00
14:00:00
15:00:00
16:00:00
17:00:00
18:00:00
19:00:00
20:00:00
21:00:00
22:00:00
23:00:00
00:00:00
01:00:00
$

## tseq.18.clit ends here
dateutils-0.3.1/test/tseq.19.clit000066400000000000000000000005111241477753400165640ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dseq 01:00:00 -1h 01:00:00
01:00:00
00:00:00
23:00:00
22:00:00
21:00:00
20:00:00
19:00:00
18:00:00
17:00:00
16:00:00
15:00:00
14:00:00
13:00:00
12:00:00
11:00:00
10:00:00
09:00:00
08:00:00
07:00:00
06:00:00
05:00:00
04:00:00
03:00:00
02:00:00
01:00:00
$

## tseq.19.clit ends here
dateutils-0.3.1/test/ttest.001.clit000066400000000000000000000001761241477753400170310ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dtest 12:00:04 --gt 11:22:33 && echo "true"
true
$

## ttest.1.clit ends here
dateutils-0.3.1/test/ttest.002.clit000066400000000000000000000002001241477753400170160ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dtest 12:00:04 --lt 11:22:33 || echo "false"
false
$

## ttest.2.clit ends here
dateutils-0.3.1/test/ttest.003.clit000066400000000000000000000001721241477753400170270ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dtest 12:00:04 --cmp 11:22:33; echo "${?}"
1
$

## ttest.3.clit ends here
dateutils-0.3.1/test/ttest.004.clit000066400000000000000000000001721241477753400170300ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dtest --cmp 11:22:33 12:00:04; echo "${?}"
2
$

## ttest.4.clit ends here
dateutils-0.3.1/test/ttest.005.clit000066400000000000000000000001721241477753400170310ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dtest --cmp 11:22:33 11:22:33; echo "${?}"
0
$

## ttest.5.clit ends here
dateutils-0.3.1/test/ttest.006.clit000066400000000000000000000001761241477753400170360ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dtest --eq 11:22:33 11:22:33 && echo "true"
true
$

## ttest.6.clit ends here
dateutils-0.3.1/test/ttest.007.clit000066400000000000000000000002001241477753400170230ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dtest --ne 11:22:33 11:22:33 || echo "false"
false
$

## ttest.7.clit ends here
dateutils-0.3.1/test/tzmap.001.clit000066400000000000000000000002311241477753400170110ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dzone dummy:XETR 2012-03-04T12:04:11
2012-03-04T13:04:11+01:00	dummy:XETR
$

## tzmap.001.clit ends here
dateutils-0.3.1/test/tzmap.002.clit000066400000000000000000000002241241477753400170140ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dconv --from-zone dummy:XETR 2012-03-04T12:04:11
2012-03-04T11:04:11
$

## tzmap.002.clit ends here
dateutils-0.3.1/test/tzmap.003.clit000066400000000000000000000002601241477753400170150ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dzone dummy:XETR --from-zone dummy:XLON 2012-03-04T12:04:11
2012-03-04T13:04:11+01:00	dummy:XETR
$

## tzmap.003.clit ends here
dateutils-0.3.1/test/tzmap.004.clit000066400000000000000000000002541241477753400170210ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ dadd --zone dummy:XETR --from-zone Europe/London 2012-03-04T12:04:11 +1h
2012-03-04T14:04:11
$

## tzmap.004.clit ends here
dateutils-0.3.1/test/tzmap_check_01.clit000066400000000000000000000002671241477753400201600ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ ignore-return find "${root}/lib" "${TZMAP_DIR}/../lib" -name '*.tzmap' | \
	xargs "${TZMAP}" check
$

## tzmap_check_01.clit ends here
dateutils-0.3.1/test/tzmap_check_02.clit000066400000000000000000000002461241477753400201560ustar00rootroot00000000000000#!/usr/bin/clitoris  ## -*- shell-script -*-

$ find "${root}/lib" "${TZMAP_DIR}/../lib" -name '*.tzmcc' | xargs "${TZMAP}" check
$

## tzmap_check_02.clit ends here
dateutils-0.3.1/version.mk.in000066400000000000000000000001421241477753400161470ustar00rootroot00000000000000VERSION = YUCK_SCMVER_VERSION
PACKAGE_VERSION = $(VERSION)
PACKAGE_STRING = $(PACKAGE) $(VERSION)