1 /*** dseq.c -- like seq(1) but for dates
2 *
3 * Copyright (C) 2009 - 2011 Sebastian Freundt
4 *
5 * Author: Sebastian Freundt <freundt@ga-group.nl>
6 *
7 * This file is part of dateutils.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of the author nor the names of any contributors
21 * may be used to endorse or promote products derived from this
22 * software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
33 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
34 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 ***/
37
38 #if defined HAVE_CONFIG_H
39 # include "config.h"
40 #endif /* HAVE_CONFIG_H */
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <stdint.h>
44 #include <stdbool.h>
45 #include <time.h>
46 #include <string.h>
47
48 #include "dt-core.h"
49 #include "dt-io.h"
50 #include "dt-locale.h"
51 #include "tzraw.h"
52
53 typedef uint8_t __skipspec_t;
54
55 /* generic closure */
56 struct dseq_clo_s {
57 struct dt_dt_s fst;
58 struct dt_dt_s lst;
59 struct dt_dtdur_s *ite;
60 size_t nite;
61 struct dt_dtdur_s *altite;
62 __skipspec_t ss;
63 size_t naltite;
64 /* direction, >0 if increasing, <0 if decreasing, 0 if undefined */
65 int dir;
66 int flags;
67 #define CLO_FL_FREE_ITE (1)
68 };
69
70 const char *prog = "dseq";
71
72
73 /* skip system */
74 static int
skipp(__skipspec_t ss,struct dt_dt_s dt)75 skipp(__skipspec_t ss, struct dt_dt_s dt)
76 {
77 dt_dow_t dow;
78 /* common case first */
79 if (ss == 0) {
80 return 0;
81 }
82 dow = dt_get_wday(dt.d);
83 /* just check if the bit in the bitset `skip' is set */
84 return (ss & (1 << dow)) != 0;
85 }
86
87 #define SKIP_MON (1 << DT_MONDAY)
88 #define SKIP_TUE (1 << DT_TUESDAY)
89 #define SKIP_WED (1 << DT_WEDNESDAY)
90 #define SKIP_THU (1 << DT_THURSDAY)
91 #define SKIP_FRI (1 << DT_FRIDAY)
92 #define SKIP_SAT (1 << DT_SATURDAY)
93 #define SKIP_SUN (1 << DT_SUNDAY)
94
95 static inline int
__toupper(int c)96 __toupper(int c)
97 {
98 return c & ~0x20;
99 }
100
101 static dt_dow_t
__parse_wd(const char * str)102 __parse_wd(const char *str)
103 {
104 #define ILEA(a, b) (((a) << 8) | (b))
105 int s1 = __toupper(str[0]);
106 int s2 = __toupper(str[1]);
107
108 switch (ILEA(s1, s2)) {
109 case ILEA('M', 'O'):
110 case ILEA('M', 0):
111 /* monday */
112 return DT_MONDAY;
113 case ILEA('T', 'U'):
114 /* tuesday */
115 return DT_TUESDAY;
116 case ILEA('W', 'E'):
117 case ILEA('W', 0):
118 /* wednesday */
119 return DT_WEDNESDAY;
120 case ILEA('T', 'H'):
121 /* thursday */
122 return DT_THURSDAY;
123 case ILEA('F', 'R'):
124 case ILEA('F', 0):
125 /* friday */
126 return DT_FRIDAY;
127 case ILEA('S', 'A'):
128 case ILEA('A', 0):
129 /* saturday */
130 return DT_SATURDAY;
131 case ILEA('S', 'U'):
132 case ILEA('S', 0):
133 /* sunday */
134 return DT_SUNDAY;
135 default:
136 return DT_MIRACLEDAY;
137 }
138 }
139
140 static __skipspec_t
__skip_dow(__skipspec_t ss,unsigned int wd)141 __skip_dow(__skipspec_t ss, unsigned int wd)
142 {
143 if (wd > GREG_DAYS_P_WEEK) {
144 wd -= GREG_DAYS_P_WEEK;
145 }
146
147 switch (wd) {
148 case DT_MONDAY:
149 /* monday */
150 ss |= SKIP_MON;
151 break;
152 case DT_TUESDAY:
153 /* tuesday */
154 ss |= SKIP_TUE;
155 break;
156 case DT_WEDNESDAY:
157 /* wednesday */
158 ss |= SKIP_WED;
159 break;
160 case DT_THURSDAY:
161 /* thursday */
162 ss |= SKIP_THU;
163 break;
164 case DT_FRIDAY:
165 /* friday */
166 ss |= SKIP_FRI;
167 break;
168 case DT_SATURDAY:
169 /* saturday */
170 ss |= SKIP_SAT;
171 break;
172 case DT_SUNDAY:
173 /* sunday */
174 ss |= SKIP_SUN;
175 break;
176 default:
177 case DT_MIRACLEDAY:
178 break;
179 }
180 return ss;
181 }
182
183 static __skipspec_t
__skip_str(__skipspec_t ss,const char * str)184 __skip_str(__skipspec_t ss, const char *str)
185 {
186 dt_dow_t tmp;
187
188 if ((tmp = __parse_wd(str)) != DT_MIRACLEDAY) {
189 ss = __skip_dow(ss, tmp);
190 } else {
191 int s1 = __toupper(str[0]);
192 int s2 = __toupper(str[1]);
193
194 if (ILEA(s1, s2) == ILEA('S', 'S')) {
195 /* weekend */
196 ss |= SKIP_SAT;
197 ss |= SKIP_SUN;
198 }
199 }
200 return ss;
201 }
202
203 static __skipspec_t
__skip_1spec(__skipspec_t ss,char * spec)204 __skip_1spec(__skipspec_t ss, char *spec)
205 {
206 char *tmp;
207 dt_dow_t from, till;
208
209 if ((tmp = strchr(spec, '-')) == NULL) {
210 return __skip_str(ss, spec);
211 }
212 /* otherwise it's a range */
213 *tmp = '\0';
214 from = __parse_wd(spec);
215 till = __parse_wd(tmp + 1);
216 for (int d = from, e = till >= from ? till : till + 7; d <= e; d++) {
217 ss = __skip_dow(ss, d);
218 }
219 return ss;
220 }
221
222 static __skipspec_t
set_skip(__skipspec_t ss,char * spec)223 set_skip(__skipspec_t ss, char *spec)
224 {
225 char *tmp, *tm2;
226
227 if ((tmp = strchr(spec, ',')) == NULL) {
228 return __skip_1spec(ss, spec);
229 }
230 /* const violation */
231 *tmp++ = '\0';
232 ss = __skip_1spec(ss, spec);
233 while ((tmp = strchr(tm2 = tmp, ','))) {
234 *tmp++ = '\0';
235 ss = __skip_1spec(ss, tm2);
236 }
237 return __skip_1spec(ss, tm2);
238 }
239
240 static struct dt_dt_s
date_add(struct dt_dt_s d,struct dt_dtdur_s dur[],size_t ndur)241 date_add(struct dt_dt_s d, struct dt_dtdur_s dur[], size_t ndur)
242 {
243 int32_t carries = d.d.u;
244
245 for (size_t i = 0; i < ndur; i++) {
246 d = dt_dtadd(d, dur[i]);
247 /* keep track of carries */
248 carries += d.t.carry;
249 }
250 if (UNLIKELY(dt_sandwich_only_t_p(d))) {
251 d.d.u = carries;
252 }
253 return d;
254 }
255
256 static void
date_neg_dur(struct dt_dtdur_s dur[],size_t ndur)257 date_neg_dur(struct dt_dtdur_s dur[], size_t ndur)
258 {
259 for (size_t i = 0; i < ndur; i++) {
260 dur[i] = dt_neg_dtdur(dur[i]);
261 }
262 return;
263 }
264
265 static bool
__daisy_feasible_p(struct dt_dtdur_s dur[],size_t ndur)266 __daisy_feasible_p(struct dt_dtdur_s dur[], size_t ndur)
267 {
268 if (ndur != 1) {
269 return false;
270 }
271
272 switch (dur->d.durtyp) {
273 case DT_DURYMD:
274 return !(dur->d.ymd.y || dur->d.ymd.m);
275 case DT_DURBIZDA:
276 return !dur->d.bizda.bd;
277 case DT_DURD:
278 case DT_DURBD:
279 /* definitley, they're daisy already */
280 return true;
281 case DT_DURWK:
282 /* borderline, could be less efficient for ywd dates */
283 return true;
284 case DT_DURMO:
285 case DT_DURQU:
286 case DT_DURYR:
287 /* most definitely not */
288 default:
289 /* all the time durs make it infeasible as well */
290 return false;
291 }
292 /* not reached */
293 }
294
295 static bool
__dur_naught_p(struct dt_dtdur_s dur)296 __dur_naught_p(struct dt_dtdur_s dur)
297 {
298 /* we use the fact that dur.dv overlaps dur.d.dv */
299 return dur.dv == 0;
300 }
301
302 static bool
__durstack_naught_p(struct dt_dtdur_s dur[],size_t ndur)303 __durstack_naught_p(struct dt_dtdur_s dur[], size_t ndur)
304 {
305 if (ndur == 0) {
306 return true;
307 } else if (ndur == 1) {
308 return __dur_naught_p(dur[0]);
309 }
310 for (size_t i = 0; i < ndur; i++) {
311 if (!__dur_naught_p(dur[i])) {
312 return false;
313 }
314 }
315 return true;
316 }
317
318 static bool
__in_range_p(struct dt_dt_s now,const struct dseq_clo_s * clo)319 __in_range_p(struct dt_dt_s now, const struct dseq_clo_s *clo)
320 {
321 if (!dt_sandwich_only_t_p(now)) {
322 if (clo->dir > 0) {
323 return dt_dt_in_range_p(now, clo->fst, clo->lst) == 1;
324 } else if (clo->dir < 0) {
325 return dt_dt_in_range_p(now, clo->lst, clo->fst) == 1;
326 }
327 }
328 /* otherwise perform a simple range check */
329 if (clo->dir > 0) {
330 if (clo->fst.t.u < clo->lst.t.u) {
331 /* dseq A B with A < B */
332 return now.t.u >= clo->fst.t.u &&
333 now.t.u <= clo->lst.t.u;
334 } else {
335 /* dseq A B with A > B and wrap-around,
336 * carries have kindly been stored in d.u */
337 return now.t.u <= clo->lst.t.u || now.d.u == 0U;
338 }
339 } else if (clo->dir < 0) {
340 if (clo->fst.t.u > clo->lst.t.u) {
341 /* counting down from A to B */
342 return now.t.u <= clo->fst.t.u &&
343 now.t.u >= clo->lst.t.u;
344 } else {
345 /* count down from A to B with wrap around,
346 * carries have kindly been stored in d.u */
347 return now.t.u >= clo->lst.t.u || now.d.u == 0U;
348 }
349 }
350 return false;
351 }
352
353 static struct dt_dt_s
__seq_altnext(struct dt_dt_s now,const struct dseq_clo_s * clo)354 __seq_altnext(struct dt_dt_s now, const struct dseq_clo_s *clo)
355 {
356 do {
357 now = date_add(now, clo->altite, clo->naltite);
358 } while (skipp(clo->ss, now) && __in_range_p(now, clo));
359 return now;
360 }
361
362 static struct dt_dt_s
__seq_this(struct dt_dt_s now,const struct dseq_clo_s * clo)363 __seq_this(struct dt_dt_s now, const struct dseq_clo_s *clo)
364 {
365 /* if NOW is on a skip date, find the next date according to ALTITE, then ITE */
366 if (!skipp(clo->ss, now) && __in_range_p(now, clo)) {
367 return now;
368 } else if (clo->naltite > 0) {
369 return __seq_altnext(now, clo);
370 } else if (clo->nite) {
371 /* advance until it goes out of range */
372 for (;
373 skipp(clo->ss, now) && __in_range_p(now, clo);
374 now = date_add(now, clo->ite, clo->nite));
375 } else {
376 /* good question */
377 ;
378 }
379 return now;
380 }
381
382 static struct dt_dt_s
__seq_next(struct dt_dt_s now,const struct dseq_clo_s * clo)383 __seq_next(struct dt_dt_s now, const struct dseq_clo_s *clo)
384 {
385 /* advance NOW, then fix it */
386 struct dt_dt_s tmp = date_add(now, clo->ite, clo->nite);
387 return __seq_this(tmp, clo);
388 }
389
390 static int
__get_dir(struct dt_dt_s d,const struct dseq_clo_s * clo)391 __get_dir(struct dt_dt_s d, const struct dseq_clo_s *clo)
392 {
393 if (!dt_sandwich_only_t_p(d)) {
394 /* trial addition to to see where it goes */
395 struct dt_dt_s tmp = __seq_next(d, clo);
396 return dt_dtcmp(tmp, d);
397 }
398 if (clo->ite->dv > 0) {
399 return 1;
400 } else if (clo->ite->dv < 0) {
401 return -1;
402 }
403 return 0;
404 }
405
406 static struct dt_dt_s
__fixup_fst(struct dseq_clo_s * clo)407 __fixup_fst(struct dseq_clo_s *clo)
408 {
409 struct dt_dt_s tmp;
410 struct dt_dt_s old;
411
412 /* assume clo->dir has been computed already */
413 old = tmp = clo->lst;
414 date_neg_dur(clo->ite, clo->nite);
415 while (__in_range_p(tmp, clo)) {
416 old = tmp;
417 tmp = __seq_next(tmp, clo);
418 }
419 /* final checks */
420 old = __seq_this(old, clo);
421 date_neg_dur(clo->ite, clo->nite);
422 /* fixup again with negated dur */
423 old = __seq_this(old, clo);
424 return old;
425 }
426
427 static struct dt_dtdur_s
tseq_guess_ite(struct dt_t_s beg,struct dt_t_s end)428 tseq_guess_ite(struct dt_t_s beg, struct dt_t_s end)
429 {
430 struct dt_dtdur_s res = {(dt_dtdurtyp_t)DT_DURUNK};
431
432 if (beg.hms.h != end.hms.h &&
433 beg.hms.m == 0 && end.hms.m == 0 &&
434 beg.hms.s == 0 && end.hms.s == 0) {
435 res.durtyp = DT_DURH;
436 res.dv = (beg.u < end.u) ? 1 : -1;
437 } else if (beg.hms.m != end.hms.m &&
438 beg.hms.s == 0 && end.hms.s == 0) {
439 res.durtyp = DT_DURM;
440 res.dv = (beg.u < end.u) ? 1 : -1;
441 } else {
442 res.durtyp = DT_DURS;
443 res.dv = (beg.u < end.u) ? 1 : -1;
444 }
445 return res;
446 }
447
448
449 #include "dseq.yucc"
450
451 int
main(int argc,char * argv[])452 main(int argc, char *argv[])
453 {
454 static struct dt_dtdur_s ite_p1;
455 yuck_t argi[1U];
456 struct dt_dt_s tmp;
457 char **ifmt;
458 size_t nifmt;
459 char *ofmt;
460 dt_dttyp_t tgttyp;
461 int rc = 0;
462 struct dseq_clo_s clo = {
463 .ite = &ite_p1,
464 .nite = 1,
465 .altite = NULL,
466 .naltite = 0,
467 .ss = 0,
468 .dir = 0,
469 .flags = 0,
470 };
471
472 if (yuck_parse(argi, argc, argv)) {
473 rc = 1;
474 goto out;
475 }
476 /* assign ofmt/ifmt */
477 ofmt = argi->format_arg;
478 if (argi->backslash_escapes_flag) {
479 dt_io_unescape(ofmt);
480 }
481 nifmt = argi->input_format_nargs;
482 ifmt = argi->input_format_args;
483
484 if (argi->from_locale_arg) {
485 setilocale(argi->from_locale_arg);
486 }
487 if (argi->locale_arg) {
488 setflocale(argi->locale_arg);
489 }
490
491 if (argi->base_arg) {
492 struct dt_dt_s base = dt_strpdt(argi->base_arg, NULL, NULL);
493 dt_set_base(base);
494 }
495
496 for (size_t i = 0; i < argi->skip_nargs; i++) {
497 clo.ss = set_skip(clo.ss, argi->skip_args[i]);
498 }
499
500 if (argi->alt_inc_arg) {
501 struct __strpdtdur_st_s st = __strpdtdur_st_initialiser();
502
503 do {
504 if (dt_io_strpdtdur(&st, argi->alt_inc_arg) < 0) {
505 if (!argi->quiet_flag) {
506 error("Error: \
507 cannot parse duration string `%s'", argi->alt_inc_arg);
508 }
509 rc = 1;
510 goto out;
511 }
512 } while (__strpdtdur_more_p(&st));
513 /* assign values */
514 clo.altite = st.durs;
515 clo.naltite = st.ndurs;
516 }
517
518 switch (argi->nargs) {
519 struct dt_dt_s fst, lst;
520 default:
521 yuck_auto_help(argi);
522 rc = 1;
523 goto out;
524
525 case 2:
526 lst = dt_io_strpdt(argi->args[1U], ifmt, nifmt, NULL);
527 if (dt_unk_p(lst)) {
528 if (!argi->quiet_flag) {
529 dt_io_warn_strpdt(argi->args[1U]);
530 }
531 rc = 1;
532 goto out;
533 } else if (UNLIKELY(lst.fix) && !argi->quiet_flag) {
534 rc = 2;
535 }
536 /* fallthrough */
537 case 1:
538 fst = dt_io_strpdt(argi->args[0U], ifmt, nifmt, NULL);
539 if (dt_unk_p(fst)) {
540 if (!argi->quiet_flag) {
541 dt_io_warn_strpdt(argi->args[0U]);
542 }
543 rc = 1;
544 goto out;
545 } else if (UNLIKELY(fst.fix) && !argi->quiet_flag) {
546 rc = 2;
547 }
548
549 /* check the input arguments and do the sane thing now
550 * if it's all dates, use DURD iterator
551 * if it's all times, use DURS/DURM/DURH iterators
552 * if one of them is a dt, promote the other */
553 if (dt_sandwich_only_d_p(fst)) {
554 /* emulates old dseq(1) */
555 if (argi->nargs == 1U) {
556 lst.d = dt_date(fst.d.typ);
557 dt_make_d_only(&lst, fst.d.typ);
558 }
559 clo.ite->d = dt_make_ddur(DT_DURD, 1);
560 } else if (dt_sandwich_only_t_p(fst)) {
561 /* emulates old tseq(1) */
562 if (argi->nargs == 1U) {
563 lst.t = dt_time();
564 dt_make_t_only(&lst, DT_HMS);
565 }
566 } else if (dt_sandwich_p(fst)) {
567 if (argi->nargs == 1U) {
568 lst = dt_datetime(fst.typ);
569 dt_make_sandwich(&lst, fst.d.typ, DT_HMS);
570 }
571 clo.ite->d = dt_make_ddur(DT_DURD, 1);
572 } else {
573 error("\
574 don't know how to handle single argument case");
575 rc = 1;
576 goto out;
577 }
578 goto make_compat;
579
580 case 3: {
581 struct __strpdtdur_st_s st = __strpdtdur_st_initialiser();
582
583 /* get lower bound */
584 fst = dt_io_strpdt(argi->args[0U], ifmt, nifmt, NULL);
585 if (dt_unk_p(fst)) {
586 if (!argi->quiet_flag) {
587 dt_io_warn_strpdt(argi->args[0U]);
588 }
589 rc = 1;
590 goto out;
591 } else if (UNLIKELY(fst.fix) && !argi->quiet_flag) {
592 rc = 2;
593 }
594
595 /* get increment */
596 do {
597 if (dt_io_strpdtdur(&st, argi->args[1U]) < 0) {
598 error("Error: \
599 cannot parse duration string `%s'", argi->args[1U]);
600 rc = 1;
601 goto out;
602 }
603 } while (__strpdtdur_more_p(&st));
604 /* assign values */
605 clo.ite = st.durs;
606 clo.nite = st.ndurs;
607 clo.flags |= CLO_FL_FREE_ITE;
608
609 /* get upper bound */
610 lst = dt_io_strpdt(argi->args[2U], ifmt, nifmt, NULL);
611 if (dt_unk_p(lst)) {
612 if (!argi->quiet_flag) {
613 dt_io_warn_strpdt(argi->args[2U]);
614 }
615 rc = 1;
616 goto out;
617 } else if (UNLIKELY(lst.fix) && !argi->quiet_flag) {
618 rc = 2;
619 }
620 goto make_compat;
621 }
622
623 make_compat:
624 if (LIKELY(fst.typ == lst.typ)) {
625 clo.fst = fst;
626 clo.lst = lst;
627 } else {
628 clo.fst = fst;
629 clo.lst = dt_dtconv(fst.typ, lst);
630 }
631 break;
632 }
633
634 /* promote the args maybe */
635 if ((dt_sandwich_only_d_p(clo.fst) && dt_sandwich_only_t_p(clo.lst)) ||
636 (dt_sandwich_only_t_p(clo.fst) && dt_sandwich_only_d_p(clo.lst))) {
637 error("\
638 cannot mix dates and times as arguments");
639 rc = 1;
640 goto out;
641 } else if (dt_sandwich_only_d_p(clo.fst) && dt_sandwich_p(clo.lst)) {
642 /* promote clo.fst */
643 clo.fst.t = clo.lst.t;
644 dt_make_sandwich(&clo.fst, clo.fst.d.typ, clo.lst.t.typ);
645 } else if (dt_sandwich_p(clo.fst) && dt_sandwich_only_d_p(clo.lst)) {
646 /* promote clo.lst */
647 clo.lst.t = clo.fst.t;
648 dt_make_sandwich(&clo.lst, clo.lst.d.typ, clo.fst.t.typ);
649 } else if (dt_sandwich_only_t_p(clo.fst) && dt_sandwich_p(clo.lst)) {
650 /* promote clo.fst */
651 clo.fst.d = clo.lst.d;
652 dt_make_sandwich(&clo.fst, clo.fst.d.typ, clo.lst.t.typ);
653 } else if (dt_sandwich_p(clo.fst) && dt_sandwich_only_t_p(clo.lst)) {
654 /* promote clo.lst */
655 clo.lst.d = clo.fst.d;
656 dt_make_sandwich(&clo.lst, clo.lst.d.typ, clo.fst.t.typ);
657 }
658
659 #define _DAISY ((dt_dttyp_t)DT_DAISY)
660 tgttyp = clo.fst.typ;
661 if ((dt_sandwich_p(clo.fst) || dt_sandwich_only_d_p(clo.fst)) &&
662 clo.fst.d.typ == DT_YMD && clo.fst.d.ymd.m == 0) {
663 /* iterate year-wise */
664 clo.ite->d = dt_make_ddur(DT_DURYR, 1);
665 } else if ((dt_sandwich_p(clo.fst) || dt_sandwich_only_d_p(clo.fst)) &&
666 clo.fst.d.typ == DT_YMD && clo.fst.d.ymd.d == 0) {
667 /* iterate month-wise */
668 clo.ite->d = dt_make_ddur(DT_DURMO, 1);
669 } else if (dt_sandwich_only_d_p(clo.fst) &&
670 __daisy_feasible_p(clo.ite, clo.nite) &&
671 clo.fst.d.typ == DT_YMD &&
672 /* convert to daisies */
673 ((clo.fst = dt_dtconv(_DAISY, clo.fst)).d.typ != DT_DAISY ||
674 (clo.lst = dt_dtconv(_DAISY, clo.lst)).d.typ != DT_DAISY)) {
675 if (!argi->quiet_flag) {
676 error("\
677 cannot convert calendric system internally");
678 }
679 rc = 1;
680 goto out;
681 } else if (dt_sandwich_only_t_p(clo.fst) && clo.ite->dv == 0) {
682 *clo.ite = tseq_guess_ite(clo.fst.t, clo.lst.t);
683 }
684
685 if (__durstack_naught_p(clo.ite, clo.nite) ||
686 !(clo.dir = __get_dir(clo.fst, &clo))) {
687 if (!argi->quiet_flag) {
688 error("\
689 increment must not be naught");
690 }
691 rc = 1;
692 goto out;
693 } else if (argi->compute_from_last_flag) {
694 tmp = __fixup_fst(&clo);
695 } else {
696 tmp = __seq_this(clo.fst, &clo);
697 }
698
699 for (; __in_range_p(dt_fixup(tmp), &clo); tmp = __seq_next(tmp, &clo)) {
700 struct dt_dt_s tgt = tmp;
701
702 if (LIKELY(ofmt == NULL)) {
703 tgt = dt_dtconv(tgttyp, tmp);
704 }
705 dt_io_write(tgt, ofmt, NULL, '\n');
706 }
707
708 out:
709 /* free strpdur resources */
710 if (clo.ite && clo.flags & CLO_FL_FREE_ITE) {
711 free(clo.ite);
712 }
713 if (clo.altite != NULL) {
714 free(clo.altite);
715 }
716 if (argi->from_locale_arg) {
717 setilocale(NULL);
718 }
719 if (argi->locale_arg) {
720 setflocale(NULL);
721 }
722 yuck_free(argi);
723 return rc;
724 }
725
726 /* dseq.c ends here */
727