Skip to content

Commit

Permalink
strftime/strptime, and some neatening
Browse files Browse the repository at this point in the history
  • Loading branch information
johnkerl committed Nov 18, 2015
1 parent 16559a7 commit f4de252
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 75 deletions.
4 changes: 0 additions & 4 deletions c/lib/mlrutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,15 +247,11 @@ time_t mlr_timegm(struct tm* tm) {
char* tz;

tz = getenv("TZ");
if (tz) {
tz = mlr_strdup_or_die(tz);
}
setenv("TZ", "GMT0", 1);
tzset();
ret = mktime(tm);
if (tz) {
setenv("TZ", tz, 1);
free(tz);
} else {
unsetenv("TZ");
}
Expand Down
54 changes: 26 additions & 28 deletions c/mapping/lrec_evaluators.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,29 +152,29 @@ lrec_evaluator_t* lrec_evaluator_alloc_from_f_f_func(mv_unary_func_t* pfunc, lre
}

// ----------------------------------------------------------------
typedef struct _lrec_evaluator_n_n_state_t {
typedef struct _lrec_evaluator_x_n_state_t {
mv_unary_func_t* pfunc;
lrec_evaluator_t* parg1;
} lrec_evaluator_n_n_state_t;
} lrec_evaluator_x_n_state_t;

mv_t lrec_evaluator_n_n_func(lrec_t* prec, context_t* pctx, void* pvstate) {
lrec_evaluator_n_n_state_t* pstate = pvstate;
mv_t val1 = pstate->parg1->pevaluator_func(prec, pctx, pstate->parg1->pvstate);
mv_t lrec_evaluator_x_n_func(lrec_t* prec, context_t* pctx, void* pvstate) {
lrec_evaluator_x_n_state_t* pstate = pvstate;

mv_t val1 = pstate->parg1->pevaluator_func(prec, pctx, pstate->parg1->pvstate);
mt_get_number_nullable(&val1);
NULL_OR_ERROR_OUT(val1);

return pstate->pfunc(&val1);
}

lrec_evaluator_t* lrec_evaluator_alloc_from_n_n_func(mv_unary_func_t* pfunc, lrec_evaluator_t* parg1) {
lrec_evaluator_n_n_state_t* pstate = mlr_malloc_or_die(sizeof(lrec_evaluator_n_n_state_t));
lrec_evaluator_t* lrec_evaluator_alloc_from_x_n_func(mv_unary_func_t* pfunc, lrec_evaluator_t* parg1) {
lrec_evaluator_x_n_state_t* pstate = mlr_malloc_or_die(sizeof(lrec_evaluator_x_n_state_t));
pstate->pfunc = pfunc;
pstate->parg1 = parg1;

lrec_evaluator_t* pevaluator = mlr_malloc_or_die(sizeof(lrec_evaluator_t));
pevaluator->pvstate = pstate;
pevaluator->pevaluator_func = lrec_evaluator_n_n_func;
pevaluator->pevaluator_func = lrec_evaluator_x_n_func;

return pevaluator;
}
Expand Down Expand Up @@ -651,19 +651,17 @@ lrec_evaluator_t* lrec_evaluator_alloc_from_b_xx_func(mv_binary_func_t* pfunc,
}

// ----------------------------------------------------------------
typedef struct _lrec_evaluator_x_fs_state_t {
typedef struct _lrec_evaluator_x_ns_state_t {
mv_binary_func_t* pfunc;
lrec_evaluator_t* parg1;
lrec_evaluator_t* parg2;
} lrec_evaluator_x_fs_state_t;
} lrec_evaluator_x_ns_state_t;

mv_t lrec_evaluator_x_fs_func(lrec_t* prec, context_t* pctx, void* pvstate) {
lrec_evaluator_x_fs_state_t* pstate = pvstate;
mv_t lrec_evaluator_x_ns_func(lrec_t* prec, context_t* pctx, void* pvstate) {
lrec_evaluator_x_ns_state_t* pstate = pvstate;
mv_t val1 = pstate->parg1->pevaluator_func(prec, pctx, pstate->parg1->pvstate);
mt_get_float_nullable(&val1);
mt_get_number_nullable(&val1);
NULL_OR_ERROR_OUT(val1);
if (val1.type != MT_FLOAT)
return MV_ERROR;

mv_t val2 = pstate->parg2->pevaluator_func(prec, pctx, pstate->parg2->pvstate);
NULL_OR_ERROR_OUT(val2);
Expand All @@ -673,17 +671,17 @@ mv_t lrec_evaluator_x_fs_func(lrec_t* prec, context_t* pctx, void* pvstate) {
return pstate->pfunc(&val1, &val2);
}

lrec_evaluator_t* lrec_evaluator_alloc_from_x_fs_func(mv_binary_func_t* pfunc,
lrec_evaluator_t* lrec_evaluator_alloc_from_x_ns_func(mv_binary_func_t* pfunc,
lrec_evaluator_t* parg1, lrec_evaluator_t* parg2)
{
lrec_evaluator_x_fs_state_t* pstate = mlr_malloc_or_die(sizeof(lrec_evaluator_x_fs_state_t));
lrec_evaluator_x_ns_state_t* pstate = mlr_malloc_or_die(sizeof(lrec_evaluator_x_ns_state_t));
pstate->pfunc = pfunc;
pstate->parg1 = parg1;
pstate->parg2 = parg2;

lrec_evaluator_t* pevaluator = mlr_malloc_or_die(sizeof(lrec_evaluator_t));
pevaluator->pvstate = pstate;
pevaluator->pevaluator_func = lrec_evaluator_x_fs_func;
pevaluator->pevaluator_func = lrec_evaluator_x_ns_func;

return pevaluator;
}
Expand Down Expand Up @@ -1372,10 +1370,10 @@ void lrec_evaluator_function_usage(FILE* output_stream, char* function_name) {
// ================================================================
lrec_evaluator_t* lrec_evaluator_alloc_from_unary_func_name(char* fnnm, lrec_evaluator_t* parg1) {
if (streq(fnnm, "!")) { return lrec_evaluator_alloc_from_b_b_func(b_b_not_func, parg1);
} else if (streq(fnnm, "+")) { return lrec_evaluator_alloc_from_n_n_func(n_n_upos_func, parg1);
} else if (streq(fnnm, "-")) { return lrec_evaluator_alloc_from_n_n_func(n_n_uneg_func, parg1);
} else if (streq(fnnm, "+")) { return lrec_evaluator_alloc_from_x_n_func(n_n_upos_func, parg1);
} else if (streq(fnnm, "-")) { return lrec_evaluator_alloc_from_x_n_func(n_n_uneg_func, parg1);
} else if (streq(fnnm, "~")) { return lrec_evaluator_alloc_from_i_i_func(i_i_bitwise_not_func, parg1);
} else if (streq(fnnm, "abs")) { return lrec_evaluator_alloc_from_n_n_func(n_n_abs_func, parg1);
} else if (streq(fnnm, "abs")) { return lrec_evaluator_alloc_from_x_n_func(n_n_abs_func, parg1);
} else if (streq(fnnm, "acos")) { return lrec_evaluator_alloc_from_f_f_func(f_f_acos_func, parg1);
} else if (streq(fnnm, "acosh")) { return lrec_evaluator_alloc_from_f_f_func(f_f_acosh_func, parg1);
} else if (streq(fnnm, "asin")) { return lrec_evaluator_alloc_from_f_f_func(f_f_asin_func, parg1);
Expand All @@ -1384,15 +1382,15 @@ lrec_evaluator_t* lrec_evaluator_alloc_from_unary_func_name(char* fnnm, lrec_eva
} else if (streq(fnnm, "atanh")) { return lrec_evaluator_alloc_from_f_f_func(f_f_atanh_func, parg1);
} else if (streq(fnnm, "boolean")) { return lrec_evaluator_alloc_from_x_x_func(b_x_boolean_func, parg1);
} else if (streq(fnnm, "cbrt")) { return lrec_evaluator_alloc_from_f_f_func(f_f_cbrt_func, parg1);
} else if (streq(fnnm, "ceil")) { return lrec_evaluator_alloc_from_n_n_func(n_n_ceil_func, parg1);
} else if (streq(fnnm, "ceil")) { return lrec_evaluator_alloc_from_x_n_func(n_n_ceil_func, parg1);
} else if (streq(fnnm, "cos")) { return lrec_evaluator_alloc_from_f_f_func(f_f_cos_func, parg1);
} else if (streq(fnnm, "cosh")) { return lrec_evaluator_alloc_from_f_f_func(f_f_cosh_func, parg1);
} else if (streq(fnnm, "erf")) { return lrec_evaluator_alloc_from_f_f_func(f_f_erf_func, parg1);
} else if (streq(fnnm, "erfc")) { return lrec_evaluator_alloc_from_f_f_func(f_f_erfc_func, parg1);
} else if (streq(fnnm, "exp")) { return lrec_evaluator_alloc_from_f_f_func(f_f_exp_func, parg1);
} else if (streq(fnnm, "expm1")) { return lrec_evaluator_alloc_from_f_f_func(f_f_expm1_func, parg1);
} else if (streq(fnnm, "float")) { return lrec_evaluator_alloc_from_x_x_func(f_x_float_func, parg1);
} else if (streq(fnnm, "floor")) { return lrec_evaluator_alloc_from_n_n_func(n_n_floor_func, parg1);
} else if (streq(fnnm, "floor")) { return lrec_evaluator_alloc_from_x_n_func(n_n_floor_func, parg1);
} else if (streq(fnnm, "gmt2sec")) { return lrec_evaluator_alloc_from_i_s_func(i_s_gmt2sec_func, parg1);
} else if (streq(fnnm, "hms2sec")) { return lrec_evaluator_alloc_from_f_s_func(i_s_hms2sec_func, parg1);
} else if (streq(fnnm, "hms2fsec")) { return lrec_evaluator_alloc_from_f_s_func(f_s_hms2fsec_func, parg1);
Expand All @@ -1405,13 +1403,13 @@ lrec_evaluator_t* lrec_evaluator_alloc_from_unary_func_name(char* fnnm, lrec_eva
} else if (streq(fnnm, "log1p")) { return lrec_evaluator_alloc_from_f_f_func(f_f_log1p_func, parg1);
} else if (streq(fnnm, "qnorm")) { return lrec_evaluator_alloc_from_f_f_func(f_f_qnorm_func, parg1);
} else if (streq(fnnm, "invqnorm")) { return lrec_evaluator_alloc_from_f_f_func(f_f_invqnorm_func, parg1);
} else if (streq(fnnm, "round")) { return lrec_evaluator_alloc_from_n_n_func(n_n_round_func, parg1);
} else if (streq(fnnm, "sec2gmt")) { return lrec_evaluator_alloc_from_s_f_func(s_f_sec2gmt_func, parg1);
} else if (streq(fnnm, "round")) { return lrec_evaluator_alloc_from_x_n_func(n_n_round_func, parg1);
} else if (streq(fnnm, "sec2gmt")) { return lrec_evaluator_alloc_from_x_n_func(s_n_sec2gmt_func, parg1);
} else if (streq(fnnm, "sec2hms")) { return lrec_evaluator_alloc_from_s_i_func(s_i_sec2hms_func, parg1);
} else if (streq(fnnm, "fsec2hms")) { return lrec_evaluator_alloc_from_s_f_func(s_f_fsec2hms_func, parg1);
} else if (streq(fnnm, "sec2dhms")) { return lrec_evaluator_alloc_from_s_i_func(s_i_sec2dhms_func, parg1);
} else if (streq(fnnm, "fsec2dhms")) { return lrec_evaluator_alloc_from_s_f_func(s_f_fsec2dhms_func, parg1);
} else if (streq(fnnm, "sgn")) { return lrec_evaluator_alloc_from_n_n_func(n_n_sgn_func, parg1);
} else if (streq(fnnm, "sgn")) { return lrec_evaluator_alloc_from_x_n_func(n_n_sgn_func, parg1);
} else if (streq(fnnm, "sin")) { return lrec_evaluator_alloc_from_f_f_func(f_f_sin_func, parg1);
} else if (streq(fnnm, "sinh")) { return lrec_evaluator_alloc_from_f_f_func(f_f_sinh_func, parg1);
} else if (streq(fnnm, "sqrt")) { return lrec_evaluator_alloc_from_f_f_func(f_f_sqrt_func, parg1);
Expand Down Expand Up @@ -1460,8 +1458,8 @@ lrec_evaluator_t* lrec_evaluator_alloc_from_binary_func_name(char* fnnm,
} else if (streq(fnnm, "&")) { return lrec_evaluator_alloc_from_i_ii_func(i_ii_bitwise_and_func, parg1, parg2);
} else if (streq(fnnm, "<<")) { return lrec_evaluator_alloc_from_i_ii_func(i_ii_bitwise_lsh_func, parg1, parg2);
} else if (streq(fnnm, ">>")) { return lrec_evaluator_alloc_from_i_ii_func(i_ii_bitwise_rsh_func, parg1, parg2);
} else if (streq(fnnm, "strftime")) { return lrec_evaluator_alloc_from_x_fs_func(s_fs_strftime_func, parg1, parg2);
} else if (streq(fnnm, "strptime")) { return lrec_evaluator_alloc_from_x_ss_func(f_ss_strptime_func, parg1, parg2);
} else if (streq(fnnm, "strftime")) { return lrec_evaluator_alloc_from_x_ns_func(s_ns_strftime_func, parg1, parg2);
} else if (streq(fnnm, "strptime")) { return lrec_evaluator_alloc_from_x_ss_func(i_ss_strptime_func, parg1, parg2);
} else { return NULL; }
}

Expand Down
84 changes: 48 additions & 36 deletions c/mapping/mlr_val.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
// type(s).
// ================================================================

#define RFC8601_TIME_FORMAT "%Y-%m-%dT%H:%M:%SZ"
#define ISO8601_TIME_FORMAT "%Y-%m-%dT%H:%M:%SZ"

// For some Linux distros, in spite of including time.h:
char *strptime(const char *s, const char *format, struct tm *tm);
Expand Down Expand Up @@ -453,54 +453,66 @@ mv_t s_s_toupper_func(mv_t* pval1) {
}

// ----------------------------------------------------------------
mv_t s_f_sec2gmt_func(mv_t* pval1) {
ERROR_OUT(*pval1);
mt_get_float_nullable(pval1);
NULL_OUT(*pval1);
if (pval1->type != MT_FLOAT)
return MV_ERROR;
time_t clock = (time_t) pval1->u.fltv;
#define NZBUFLEN 63

// Precondition: psec is either int or float.
static mv_t time_string_from_seconds(mv_t* psec, char* format) {
time_t clock = 0;
if (psec->type == MT_FLOAT) {
clock = (time_t) psec->u.fltv;
} else {
clock = (time_t) psec->u.intv;
}

struct tm tm;
struct tm *ptm = gmtime_r(&clock, &tm);
// xxx use retval which is size_t
// xxx error-check all of this ...
char* string = mlr_malloc_or_die(32);
// xxx make mlrutil func
(void)strftime(string, 32, RFC8601_TIME_FORMAT, ptm);
if (ptm == NULL) {
fprintf(stderr, "%s: internal coding error detected in file %s at line %d.\n",
MLR_GLOBALS.argv0, __FILE__, __LINE__);
exit(1);
}
char* string = mlr_malloc_or_die(NZBUFLEN + 1);
int written_length = strftime(string, NZBUFLEN, format, ptm);
if (written_length > NZBUFLEN || written_length == 0) {
fprintf(stderr, "%s: internal coding error detected in file %s at line %d.\n",
MLR_GLOBALS.argv0, __FILE__, __LINE__);
exit(1);
}

mv_t rv = {.type = MT_STRING, .u.strv = string};
return rv;
return (mv_t) {.type = MT_STRING, .u.strv = string};
}

mv_t i_s_gmt2sec_func(mv_t* pval1) {
struct tm tm;
if (*pval1->u.strv == '\0') {
mv_t s_n_sec2gmt_func(mv_t* pval1) {
return time_string_from_seconds(pval1, ISO8601_TIME_FORMAT);
}

mv_t s_ns_strftime_func(mv_t* pval1, mv_t* pval2) {
return time_string_from_seconds(pval1, pval2->u.strv);
}

// ----------------------------------------------------------------
static mv_t seconds_from_time_string(char* time, char* format) {
if (*time == '\0') {
return MV_NULL;
} else {
strptime(pval1->u.strv, RFC8601_TIME_FORMAT, &tm);
struct tm tm;
char* retval = strptime(time, format, &tm);
if (retval == NULL) {
fprintf(stderr, "%s: internal coding error detected in file %s at line %d.\n",
MLR_GLOBALS.argv0, __FILE__, __LINE__);
exit(1);
}
time_t t = mlr_timegm(&tm);

mv_t rv = {.type = MT_INT, .u.intv = (long long)t};
return rv;
return (mv_t) {.type = MT_INT, .u.intv = (long long)t};
}
}

mv_t s_fs_strftime_func(mv_t* pval1, mv_t* pval2) {
time_t clock = (time_t) pval1->u.fltv;
struct tm tm;
struct tm *ptm = gmtime_r(&clock, &tm);
char* string = mlr_malloc_or_die(32);
(void)strftime(string, 31, pval2->u.strv, ptm);

return (mv_t) {.type = MT_STRING, .u.strv = string}; // xxx stub
mv_t i_s_gmt2sec_func(mv_t* pval1) {
return seconds_from_time_string(pval1->u.strv, ISO8601_TIME_FORMAT);
}
mv_t f_ss_strptime_func(mv_t* pval1, mv_t* pval2) {
struct tm tm;
strptime(pval1->u.strv, pval2->u.strv, &tm);
time_t t = mlr_timegm(&tm);
long long seconds = (long long) t;

return (mv_t) {.type = MT_INT, .u.intv = seconds}; // xxx stub
mv_t i_ss_strptime_func(mv_t* pval1, mv_t* pval2) {
return seconds_from_time_string(pval1->u.strv, pval2->u.strv);
}

// ----------------------------------------------------------------
Expand Down
7 changes: 3 additions & 4 deletions c/mapping/mlr_val.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,10 @@ mv_t gsub_no_precomp_func(mv_t* pval1, mv_t* pval2, mv_t* pval3);
mv_t gsub_precomp_func(mv_t* pval1, regex_t* pregex, string_builder_t* psb, mv_t* pval3);

// ----------------------------------------------------------------
mv_t s_f_sec2gmt_func(mv_t* pval1);
mv_t s_n_sec2gmt_func(mv_t* pval1);
mv_t i_s_gmt2sec_func(mv_t* pval1);
mv_t s_ns_strftime_func(mv_t* pval1, mv_t* pval2);
mv_t i_ss_strptime_func(mv_t* pval1, mv_t* pval2);

mv_t s_i_sec2hms_func(mv_t* pval1);
mv_t s_f_fsec2hms_func(mv_t* pval1);
Expand All @@ -239,9 +241,6 @@ mv_t f_s_hms2fsec_func(mv_t* pval1);
mv_t i_s_dhms2sec_func(mv_t* pval1);
mv_t f_s_dhms2fsec_func(mv_t* pval1);

mv_t s_fs_strftime_func(mv_t* pval1, mv_t* pval2);
mv_t f_ss_strptime_func(mv_t* pval1, mv_t* pval2);

mv_t i_s_strlen_func(mv_t* pval1);

// ----------------------------------------------------------------
Expand Down
3 changes: 2 additions & 1 deletion c/todo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ TOP OF LIST
! try to get a grip on jb issues
o mlr -f into manpage? line-wraps ...
o mv_t int/float accumulator logic for stats1 sum, step rsum, ... ? & note these in the dox.
o expose str{p,f}time: more error-checking; more UT cases
o mlr --regex-help and/or new section @ mld ref:
- /.../, "...", "..."i,
- "\(..\)" vs. "(..)"
Expand All @@ -36,6 +35,8 @@ TOP OF LIST
o dsls bake deps
o elaborate in put/filter -s/-f help: this means '$z=int($x)+int($y)' ...

* lrec_eval nullable etc. cleanup

* packaging:
- brew version bump?!?

Expand Down
4 changes: 2 additions & 2 deletions doc/mlr.1.premade
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
.\" Title: mlr
.\" Author: [see the "AUTHOR" section]
.\" Generator: ./mkman.rb
.\" Date: 2015-11-17
.\" Date: 2015-11-18
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "MILLER" "1" "2015-11-17" "\ \&" "\ \&"
.TH "MILLER" "1" "2015-11-18" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Portability definitions
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down

0 comments on commit f4de252

Please sign in to comment.