Commits

Sebastian Freundt committed 751ab4b Merge

Merge branch 'next'

* next:
minor, distribute libdudtcore and mention dtconv in the build summary
minor, extend group atoms to time specs in dt-io.h
minor, in dt_io_write_sed() definitely close the line by a newline character
minor, parse time component in dt_strpdt() when using standard input format
minor, redirect __strpdt_card() to `strpd' or `strpt' _card
cosmetics, fix up indentation cock-up in info page menu
minor, provide man and info pages for dtconv tool
minor, add (preliminary/trivial) tests for dtconv tool

Comments (0)

Files changed (10)

 pkgconfig_DATA =
 pkgconfig_DATA += libdudcore.pc
 pkgconfig_DATA += libdutcore.pc
+pkgconfig_DATA += libdudtcore.pc
 ## trivial, no special stuff needed
 dapps="dadd dconv ddiff dgrep dseq dtest"
 tapps="tadd tconv tdiff tgrep tseq ttest"
-dtapps=""
+dtapps="dtconv"
 miscapps="strptime"
 
 AC_CONFIG_FILES([Makefile])
 AC_CONFIG_FILES([test/Makefile])
 AC_CONFIG_FILES([libdudcore.pc])
 AC_CONFIG_FILES([libdutcore.pc])
+AC_CONFIG_FILES([libdudtcore.pc])
 AC_OUTPUT
 
 cat <<EOF
 dateutils_EXAMPLES += $(tconv_EXAMPLES)
 dateutils_H2M_EX += tconv.h2m
 
+dtconv_EXAMPLES =
+dtconv_EXAMPLES += $(top_srcdir)/test/dtconv.1.dt
+dtconv_EXAMPLES += $(top_srcdir)/test/dtconv.2.dt
+dateutils_EXAMPLES += $(dtconv_EXAMPLES)
+dateutils_H2M_EX += dtconv.h2m
+
 dateutils_H2M_EX += format.h2m
 
 EXTRA_DIST += author.h2m $(dateutils_H2M_EX)
 built_texis += tgrep.texi
 built_texis += ttest.texi
 built_texis += tconv.texi
+built_texis += dtconv.texi
 
 built_mans =
 built_mans += strptime.man
 built_mans += tgrep.man
 built_mans += ttest.man
 built_mans += tconv.man
+built_mans += dtconv.man
 
 EXTRA_DIST += $(man1_MANS)
 EXTRA_DIST += $(dateutils_TEXINFOS)

info/dateutils.texi

 * Introduction::        Motivation, background, etc.
 * Calendars::           Calendar concepts and format specs
 * strptime::            Command line version of the C function
-* dconv::                Convert dates between calendars
+* dconv::               Convert dates between calendars
 * dadd::                Add durations to dates
 * ddiff::               Compute durations from dates
 * dgrep::               Find date matches in input stream
 * dseq::                Generate sequences of dates
 * dtest::               Compare dates
-* tconv::                Convert time representations
+* tconv::               Convert time representations
 * tadd::                Add durations to times
 * tdiff::               Compute durations between times
 * tgrep::               Find time matches in input stream
 * tseq::                Generate sequences of times
 * ttest::               Compare times
+* dtconv::              Convert date/times
 @end menu
 
 
 @include tgrep.texi
 @include tseq.texi
 @include ttest.texi
+@include dtconv.texi
 
 @summarycontents
 @contents
 		break;
 	}
 	/* guess what we're doing */
-	res.d = __guess_dtyp(d.sd);
+	if ((res.d = __guess_dtyp(d.sd)).typ == DT_UNK) {
+		/* not much use parsing on */
+		goto out;
+	}
+	/* check for the d/t separator */
+	switch (*sp++) {
+	case 'T':
+	case ' ':
+	case '\t':
+		break;
+	default:
+		/* that's no good */
+		goto out;
+	}
+	/* and now parse the time */
+	d.st.h = strtoui_lim(sp, &sp, 0, 23);
+	*sp++;
+	d.st.m = strtoui_lim(sp, &sp, 0, 59);
+	*sp++;
+	d.st.s = strtoui_lim(sp, &sp, 0, 60);
+
+	if (d.st.h < -1U && d.st.m < -1U && d.st.s < -1U) {
+		res.t.hms.h = d.st.h;
+		res.t.hms.m = d.st.m;
+		res.t.hms.s = d.st.s;
+	}
 out:
 	if (ep) {
 		*ep = (char*)sp;
 	return res;
 }
 
+static 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_MDAY:
+	case DT_SPFL_N_CNT_WEEK:
+	case DT_SPFL_N_CNT_MON:
+	case DT_SPFL_S_WDAY:
+	case DT_SPFL_S_MON:
+	case DT_SPFL_S_QTR:
+	case DT_SPFL_N_QTR:
+	case DT_SPFL_N_CNT_YEAR:
+		res = __strpd_card(&d->sd, sp, s, ep);
+		break;
+
+	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);
+		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) {
+		*ep = (char*)sp;
+	}
+	return res;
+}
+
 static size_t
 __strfdt_card(
 	char *buf, size_t bsz, struct dt_spec_s s,
 			}
 		} else if (LIKELY(!spec.rom)) {
 			const char *sp_sav = sp;
-			if (__strpd_card(&d.sd, sp, spec, (char**)&sp) < 0) {
+			if (__strpdt_card(&d, sp, spec, (char**)&sp) < 0) {
 				sp = str;
 				goto out;
 			}

libdudtcore.pc.in

+prefix=@prefix@
+exec_prefix=@exec_prefix@
+includedir=@includedir@
+libdir=@libdir@
+libexecdir=@libexecdir@
+
+Name: libdudtcore
+Description: dateutils' date/time routines
+Version: @PACKAGE_VERSION@
+Libs:
+Cflags: -I${includedir} -DINCLUDE_DATETIME_CORE_IMPL
+
 #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;
 
 /* 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_s res = {0};
 	int8_t andl_idx = 0;
 	int8_t bndl_idx = 0;
+	int8_t pndl_idx = 0;
 	const char *fp = fmt;
 
 	/* init */
 				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;
 		}
 		case DT_SPFL_N_CNT_MON:
 		case DT_SPFL_N_QTR:
 		case DT_SPFL_N_MDAY:
+		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;
 		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;
 		}
 	}
 	if (res.needle == 0 && (res.pl.off_min || res.pl.off_max)) {
 			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 */
 #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)
 	}
 	__io_write(buf, n, stdout);
 	if (ep) {
-		__io_write(ep, line + llen - ep, stdout);
+		size_t eolen = line + llen - ep;
+		if (LIKELY(eolen > 0)) {
+			__io_write(ep, line + llen - ep, stdout);
+		} else {
+			__io_putc('\n', stdout);
+		}
 	}
 	return (n > 0 || sp < ep) - 1;
 }
 TESTS += tconv.1.dt
 TESTS += tconv.2.dt
 
+TESTS += dtconv.1.dt
+TESTS += dtconv.2.dt
+
 ## Makefile.am ends here
+## -*- shell-script -*-
+
+TOOL=dtconv
+CMDLINE="2012-03-01"
+
+## STDIN
+ 
+## STDOUT
+stdout=$(mktemp "/tmp/tmp.XXXXXXXXXX")
+cat > "${stdout}" <<EOF
+2012-03-01T00:00:00
+EOF
+
+## dtconv.1.dt ends here
+## -*- shell-script -*-
+
+TOOL=dtconv
+CMDLINE="2012-03-01T12:34:56"
+
+## STDIN
+ 
+## STDOUT
+stdout=$(mktemp "/tmp/tmp.XXXXXXXXXX")
+cat > "${stdout}" <<EOF
+2012-03-01T12:34:56
+EOF
+
+## dtconv.2.dt ends here