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; }
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, f**k 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, f**k 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 = str; goto out; } else if (*sp != ':') { goto eval_time; } 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; }
int main(int argc, char *argv[]) { static struct dt_dtdur_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; if (argi->from_locale_arg) { setilocale(argi->from_locale_arg); } if (argi->locale_arg) { setflocale(argi->locale_arg); } if (argi->base_arg) { struct dt_dt_s base = dt_strpdt(argi->base_arg, NULL, NULL); dt_set_base(base); } 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 DURD iterator * if it's all times, use DURS/DURM/DURH iterators * 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(fst.d.typ); dt_make_d_only(&lst, fst.d.typ); } clo.ite->d = dt_make_ddur(DT_DURD, 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); } } else if (dt_sandwich_p(fst)) { if (argi->nargs == 1U) { lst = dt_datetime(fst.typ); dt_make_sandwich(&lst, fst.d.typ, DT_HMS); } clo.ite->d = dt_make_ddur(DT_DURD, 1); } else { error("\ don't know how to handle single argument case"); rc = 1; goto out; } goto make_compat; 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; } goto make_compat; } make_compat: if (LIKELY(fst.typ == lst.typ)) { clo.fst = fst; clo.lst = lst; } else { clo.fst = fst; clo.lst = dt_dtconv(fst.typ, 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)) {