lrec_t* lrec_literal_3(char* k1, char* v1, char* k2, char* v2, char* k3, char* v3) { lrec_t* prec = lrec_unbacked_alloc(); lrec_put(prec, k1, v1, NO_FREE); lrec_put(prec, k2, v2, NO_FREE); lrec_put(prec, k3, v3, NO_FREE); return prec; }
// ---------------------------------------------------------------- lrec_t* lrec_parse_stdio_nidx(char* line, char ifs, int allow_repeat_ifs) { lrec_t* prec = lrec_nidx_alloc(line); int idx = 0; char* key = NULL; char* value = line; char free_flags = 0; for (char* p = line; *p; ) { if (*p == ifs) { *p = 0; idx++; key = make_nidx_key(idx, &free_flags); lrec_put(prec, key, value, free_flags); p++; if (allow_repeat_ifs) { while (*p == ifs) p++; } value = p; } else { p++; } } idx++; key = make_nidx_key(idx, &free_flags); lrec_put(prec, key, value, free_flags); return prec; }
static void stats1_count_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) { stats1_count_state_t* pstate = pvstate; if (copy_data) lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), mv_alloc_format_val(&pstate->counter), FREE_ENTRY_KEY|FREE_ENTRY_VALUE); else lrec_put(poutrec, pstate->output_field_name, mv_alloc_format_val(&pstate->counter), FREE_ENTRY_VALUE); }
static void acc_max_emit(void* pvstate, char* value_field_name, char* acc_name, lrec_t* poutrec) { acc_max_state_t* pstate = pvstate; char* key = mlr_paste_3_strings(value_field_name, "_", acc_name); if (pstate->have_max) { char* val = mlr_alloc_string_from_double(pstate->max, MLR_GLOBALS.ofmt); lrec_put(poutrec, key, val, LREC_FREE_ENTRY_KEY|LREC_FREE_ENTRY_VALUE); } else { lrec_put(poutrec, key, "", LREC_FREE_ENTRY_KEY); } }
lrec_t* lrec_parse_stdio_csvlite_data_line_multi_ifs(header_keeper_t* pheader_keeper, char* filename, long long ilno, char* data_line, char* ifs, int ifslen, int allow_repeat_ifs) { lrec_t* prec = lrec_csvlite_alloc(data_line); char* p = data_line; if (allow_repeat_ifs) { while (streqn(p, ifs, ifslen)) p += ifslen; } char* key = NULL; char* value = p; sllse_t* pe = pheader_keeper->pkeys->phead; for ( ; *p; ) { if (streqn(p, ifs, ifslen)) { *p = 0; if (pe == NULL) { fprintf(stderr, "%s: Header-data length mismatch in file %s at line %lld.\n", MLR_GLOBALS.argv0, filename, ilno); exit(1); } key = pe->value; pe = pe->pnext; lrec_put(prec, key, value, NO_FREE); p += ifslen; if (allow_repeat_ifs) { while (streqn(p, ifs, ifslen)) p += ifslen; } value = p; } else { p++; } } if (allow_repeat_ifs && *value == 0) { ; // OK } else if (pe == NULL) { fprintf(stderr, "%s: Header-data length mismatch in file %s at line %lld.\n", MLR_GLOBALS.argv0, filename, ilno); exit(1); } else { key = pe->value; lrec_put(prec, key, value, NO_FREE); if (pe->pnext != NULL) { fprintf(stderr, "%s: Header-data length mismatch in file %s at line %lld.\n", MLR_GLOBALS.argv0, filename, ilno); exit(1); } } return prec; }
lrec_t* lrec_parse_mmap_nidx(file_reader_mmap_state_t *phandle, char irs, char ifs, int allow_repeat_ifs) { lrec_t* prec = lrec_unbacked_alloc(); char* line = phandle->sol; int idx = 0; char free_flags = 0; char* p = line; if (allow_repeat_ifs) { while (*p == ifs) p++; } char* key = NULL; char* value = p; for ( ; p < phandle->eof && *p; ) { if (*p == irs) { *p = 0; phandle->sol = p+1; break; } else if (*p == ifs) { *p = 0; idx++; key = make_nidx_key(idx, &free_flags); lrec_put(prec, key, value, free_flags); p++; if (allow_repeat_ifs) { while (*p == ifs) p++; } value = p; } else { p++; } } if (p >= phandle->eof) phandle->sol = p+1; idx++; if (allow_repeat_ifs && *value == 0) { ; // OK } else { key = make_nidx_key(idx, &free_flags); lrec_put(prec, key, value, free_flags); } return prec; }
// xxx recast all of these in terms of providable outputs static void acc_stddev_var_meaneb_emit(void* pvstate, char* value_field_name, char* acc_name, lrec_t* poutrec) { acc_stddev_var_meaneb_state_t* pstate = pvstate; char* key = mlr_paste_3_strings(value_field_name, "_", acc_name); if (pstate->count < 2LL) { lrec_put(poutrec, key, "", LREC_FREE_ENTRY_KEY); } else { double output = mlr_get_var(pstate->count, pstate->sumx, pstate->sumx2); if (pstate->do_which == DO_STDDEV) output = sqrt(output); else if (pstate->do_which == DO_MEANEB) output = sqrt(output / pstate->count); char* val = mlr_alloc_string_from_double(output, MLR_GLOBALS.ofmt); lrec_put(poutrec, key, val, LREC_FREE_ENTRY_KEY|LREC_FREE_ENTRY_VALUE); } }
static void stats1_mean_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) { stats1_mean_state_t* pstate = pvstate; if (pstate->count == 0LL) { if (copy_data) lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), "", FREE_ENTRY_KEY); else lrec_put(poutrec, pstate->output_field_name, "", NO_FREE); } else { double quot = pstate->sum / pstate->count; char* val = mlr_alloc_string_from_double(quot, MLR_GLOBALS.ofmt); if (copy_data) lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), val, FREE_ENTRY_KEY|FREE_ENTRY_VALUE); else lrec_put(poutrec, pstate->output_field_name, val, FREE_ENTRY_VALUE); } }
static void stats1_mode_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) { stats1_mode_state_t* pstate = pvstate; int max_count = 0; char* max_key = ""; for (lhmsie_t* pe = pstate->pcounts_for_value->phead; pe != NULL; pe = pe->pnext) { int count = pe->value; if (count > max_count) { max_key = pe->key; max_count = count; } } if (copy_data) lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), mlr_strdup_or_die(max_key), FREE_ENTRY_KEY|FREE_ENTRY_VALUE); else lrec_put(poutrec, pstate->output_field_name, max_key, NO_FREE); }
static void stats1_max_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) { stats1_max_state_t* pstate = pvstate; if (mv_is_null(&pstate->max)) { if (copy_data) lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), "", FREE_ENTRY_KEY); else lrec_put(poutrec, pstate->output_field_name, "", NO_FREE); } else { if (copy_data) lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), mv_alloc_format_val(&pstate->max), FREE_ENTRY_KEY|FREE_ENTRY_VALUE); else lrec_put(poutrec, pstate->output_field_name, mv_alloc_format_val(&pstate->max), FREE_ENTRY_VALUE); } }
static void stats1_kurtosis_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) { stats1_kurtosis_state_t* pstate = pvstate; if (pstate->count < 2LL) { if (copy_data) lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), "", FREE_ENTRY_KEY); else lrec_put(poutrec, pstate->output_field_name, "", NO_FREE); } else { double output = mlr_get_kurtosis(pstate->count, pstate->sumx, pstate->sumx2, pstate->sumx3, pstate->sumx4); char* val = mlr_alloc_string_from_double(output, MLR_GLOBALS.ofmt); if (copy_data) lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), val, FREE_ENTRY_KEY|FREE_ENTRY_VALUE); else lrec_put(poutrec, pstate->output_field_name, val, FREE_ENTRY_VALUE); } }
static void acc_mean_emit(void* pvstate, char* value_field_name, char* acc_name, lrec_t* poutrec) { acc_mean_state_t* pstate = pvstate; double quot = pstate->sum / pstate->count; char* key = mlr_paste_3_strings(value_field_name, "_", acc_name); char* val = mlr_alloc_string_from_double(quot, MLR_GLOBALS.ofmt); lrec_put(poutrec, key, val, LREC_FREE_ENTRY_KEY|LREC_FREE_ENTRY_VALUE); }
// ---------------------------------------------------------------- lrec_t* lrec_copy(lrec_t* pinrec) { lrec_t* poutrec = lrec_unbacked_alloc(); for (lrece_t* pe = pinrec->phead; pe != NULL; pe = pe->pnext) { lrec_put(poutrec, mlr_strdup_or_die(pe->key), mlr_strdup_or_die(pe->value), FREE_ENTRY_KEY|FREE_ENTRY_VALUE); } return poutrec; }
static void acc_percentile_emit(void* pvstate, char* value_field_name, char* acc_name, lrec_t* poutrec) { acc_percentile_state_t* pstate = pvstate; char* key = mlr_paste_3_strings(value_field_name, "_", acc_name); double p; (void)sscanf(acc_name, "p%lf", &p); // Assuming this was range-checked earlier on to be in [0,100]. double v = percentile_keeper_emit(pstate->ppercentile_keeper, p); char* s = mlr_alloc_string_from_double(v, MLR_GLOBALS.ofmt); lrec_put(poutrec, key, s, LREC_FREE_ENTRY_KEY|LREC_FREE_ENTRY_VALUE); }
// ---------------------------------------------------------------- lrec_t* lrec_parse_stdio_nidx_multi_sep(char* line, char* ifs, int ifslen, int allow_repeat_ifs) { lrec_t* prec = lrec_nidx_alloc(line); int idx = 0; char free_flags = 0; char* p = line; if (allow_repeat_ifs) { while (streqn(p, ifs, ifslen)) p += ifslen; } char* key = NULL; char* value = p; for ( ; *p; ) { if (streqn(p, ifs, ifslen)) { *p = 0; idx++; key = make_nidx_key(idx, &free_flags); lrec_put(prec, key, value, free_flags); p += ifslen; if (allow_repeat_ifs) { while (streqn(p, ifs, ifslen)) p += ifslen; } value = p; } else { p++; } } idx++; if (allow_repeat_ifs && *value == 0) { ; // OK } else { key = make_nidx_key(idx, &free_flags); lrec_put(prec, key, value, free_flags); } return prec; }
// ---------------------------------------------------------------- lrec_t* lrec_parse_stdio_csvlite_data_line_single_ifs_implicit_header(header_keeper_t* pheader_keeper, char* filename, long long ilno, char* data_line, char ifs, int allow_repeat_ifs) { lrec_t* prec = lrec_csvlite_alloc(data_line); char* p = data_line; if (allow_repeat_ifs) { while (*p == ifs) p++; } char* key = NULL; char free_flags; char* value = p; int idx = 0; for ( ; *p; ) { if (*p == ifs) { *p = 0; key = make_nidx_key(++idx, &free_flags); lrec_put(prec, key, value, free_flags); p++; if (allow_repeat_ifs) { while (*p == ifs) p++; } value = p; } else { p++; } } if (allow_repeat_ifs && *value == 0) { ; // OK } else { key = make_nidx_key(++idx, &free_flags); lrec_put(prec, key, value, NO_FREE); lrec_put(prec, key, value, free_flags); } return prec; }
// ---------------------------------------------------------------- static void handle_full_srec_assignment( mlr_dsl_cst_statement_t* pstatement, variables_t* pvars, cst_outputs_t* pcst_outputs) { full_srec_assignment_state_t* pstate = pstatement->pvstate; lrec_t* poutrec = lrec_unbacked_alloc(); // pinrec might be part of the RHS. lhmsmv_t* pout_typed_overlay = lhmsmv_alloc(); rxval_evaluator_t* prhs_xevaluator = pstate->prhs_xevaluator; boxed_xval_t boxed_xval = prhs_xevaluator->pprocess_func(prhs_xevaluator->pvstate, pvars); if (!boxed_xval.xval.is_terminal) { for (mlhmmv_level_entry_t* pe = boxed_xval.xval.pnext_level->phead; pe != NULL; pe = pe->pnext) { mv_t* pkey = &pe->level_key; mlhmmv_xvalue_t* pval = &pe->level_xvalue; if (pval->is_terminal) { // xxx else collapse-down using json separator? char* skey = mv_alloc_format_val(pkey); // xxx if we're going to transfer here *and* free below, this needs a nullptr poke // at the copy-from site //mv_t val = boxed_xval.is_ephemeral ? pval->terminal_mlrval : mv_copy(&pval->terminal_mlrval); mv_t val = mv_copy(&pval->terminal_mlrval); // Write typed mlrval output to the typed overlay rather than into the lrec // (which holds only string values). // // The rval_evaluator reads the overlay in preference to the lrec. E.g. if the // input had "x"=>"abc","y"=>"def" but a previous statement had set "y"=>7.4 and // "z"=>"ghi", then an expression right-hand side referring to $y would get the // floating-point value 7.4. So we don't need to lrec_put the value here, and // moreover should not for two reasons: (1) there is a performance hit of doing // throwaway number-to-string formatting -- it's better to do it once at the // end; (2) having the string values doubly owned by the typed overlay and the // lrec would result in double frees, or awkward bookkeeping. However, the NR // variable evaluator reads prec->field_count, so we need to put something here. // And putting something statically allocated minimizes copying/freeing. lhmsmv_put(pout_typed_overlay, mlr_strdup_or_die(skey), &val, FREE_ENTRY_KEY | FREE_ENTRY_VALUE); lrec_put(poutrec, skey, "bug", FREE_ENTRY_KEY); } } if (boxed_xval.is_ephemeral) { mlhmmv_xvalue_free(&boxed_xval.xval); } } else { mlhmmv_xvalue_free(&boxed_xval.xval); } lrec_free(pvars->pinrec); lhmsmv_free(pvars->ptyped_overlay); pvars->pinrec = poutrec; pvars->ptyped_overlay = pout_typed_overlay; }
static void stats1_stddev_var_meaneb_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) { stats1_stddev_var_meaneb_state_t* pstate = pvstate; if (pstate->count < 2LL) { if (copy_data) lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), "", FREE_ENTRY_KEY); else lrec_put(poutrec, pstate->output_field_name, "", NO_FREE); } else { double output = mlr_get_var(pstate->count, pstate->sumx, pstate->sumx2); if (pstate->do_which == DO_STDDEV) output = sqrt(output); else if (pstate->do_which == DO_MEANEB) output = sqrt(output / pstate->count); char* val = mlr_alloc_string_from_double(output, MLR_GLOBALS.ofmt); if (copy_data) lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), val, FREE_ENTRY_KEY|FREE_ENTRY_VALUE); else lrec_put(poutrec, pstate->output_field_name, val, FREE_ENTRY_VALUE); } }
static void step_delta_dprocess(void* pvstate, double dblv, lrec_t* prec) { step_delta_state_t* pstate = pvstate; double delta = dblv; if (pstate->have_prev) { delta = dblv - pstate->prev; } else { pstate->have_prev = TRUE; } lrec_put(prec, pstate->output_field_name, mlr_alloc_string_from_double(delta, MLR_GLOBALS.ofmt), LREC_FREE_ENTRY_VALUE); pstate->prev = dblv; }
// ---------------------------------------------------------------- static lrec_t* paste_indices_and_data(lrec_reader_mmap_csv_state_t* pstate, rslls_t* pdata_fields, context_t* pctx) { int idx = 0; lrec_t* prec = lrec_unbacked_alloc(); for (rsllse_t* pd = pdata_fields->phead; idx < pdata_fields->length && pd != NULL; pd = pd->pnext) { idx++; char free_flags = pd->free_flag; char* key = make_nidx_key(idx, &free_flags); // Transfer pointer-free responsibility from the rslls to the lrec object lrec_put(prec, key, pd->value, free_flags); pd->free_flag = 0; } return prec; }
lrec_t* lrec_parse_stdio_xtab_multi_ips(slls_t* pxtab_lines, char* ips, int ipslen, int allow_repeat_ips) { lrec_t* prec = lrec_xtab_alloc(pxtab_lines); for (sllse_t* pe = pxtab_lines->phead; pe != NULL; pe = pe->pnext) { char* line = pe->value; char* p = line; char* key = p; while (*p != 0 && !streqn(p, ips, ipslen)) p++; // Advance by only 1 in case of subsequent match if (*p == 0) { lrec_put(prec, key, "", NO_FREE); } else { while (*p != 0 && !streqn(p, ips, ipslen)) { *p = 0; p += ipslen; } lrec_put(prec, key, p, NO_FREE); } } return prec; }
// ---------------------------------------------------------------- lrec_t* lrec_parse_stdio_xtab_single_ips(slls_t* pxtab_lines, char ips, int allow_repeat_ips) { lrec_t* prec = lrec_xtab_alloc(pxtab_lines); for (sllse_t* pe = pxtab_lines->phead; pe != NULL; pe = pe->pnext) { char* line = pe->value; char* p = line; char* key = p; while (*p != 0 && *p != ips) p++; if (*p == 0) { lrec_put(prec, key, "", NO_FREE); } else { while (*p != 0 && *p == ips) { *p = 0; p++; } lrec_put(prec, key, p, NO_FREE); } } return prec; }
static void acc_mode_emit(void* pvstate, char* value_field_name, char* acc_name, lrec_t* poutrec) { acc_mode_state_t* pstate = pvstate; int max_count = 0; char* max_key = ""; for (lhmsie_t* pe = pstate->pcounts_for_value->phead; pe != NULL; pe = pe->pnext) { int count = pe->value; if (count > max_count) { max_key = pe->key; max_count = count; } } char* key = mlr_paste_3_strings(value_field_name, "_", acc_name); lrec_put(poutrec, key, max_key, LREC_FREE_ENTRY_KEY); }
static void stats1_percentile_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) { stats1_percentile_state_t* pstate = pvstate; double p; (void)sscanf(stats1_acc_name, "p%lf", &p); // Assuming this was range-checked earlier on to be in [0,100]. mv_t v = percentile_keeper_emit(pstate->ppercentile_keeper, p); char* s = mv_alloc_format_val(&v); // For this type, one accumulator tracks many stats1_names, but a single value_field_name. char* output_field_name = lhmss_get(pstate->poutput_field_names, stats1_acc_name); if (output_field_name == NULL) { output_field_name = mlr_paste_3_strings(value_field_name, "_", stats1_acc_name); lhmss_put(pstate->poutput_field_names, mlr_strdup_or_die(stats1_acc_name), output_field_name, FREE_ENTRY_KEY|FREE_ENTRY_VALUE); } lrec_put(poutrec, mlr_strdup_or_die(output_field_name), s, FREE_ENTRY_KEY|FREE_ENTRY_VALUE); }
// ---------------------------------------------------------------- static sllv_t* mapper_put_process(lrec_t* pinrec, context_t* pctx, void* pvstate) { if (pinrec != NULL) { mapper_put_state_t* pstate = (mapper_put_state_t*)pvstate; for (int i = 0; i < pstate->num_evaluators; i++) { // xxx decide ownership location for type conversions ... mv_t val = pstate->pevaluators[i]->pevaluator_func(pinrec, pctx, pstate->pevaluators[i]->pvstate); char* string = mt_format_val(&val); lrec_put(pinrec, pstate->output_field_names[i], string, LREC_FREE_ENTRY_VALUE); free(string); } return sllv_single(pinrec); } else { return sllv_single(NULL); } }
// ---------------------------------------------------------------- static lrec_t* paste_header_and_data(lrec_reader_mmap_csv_state_t* pstate, rslls_t* pdata_fields, context_t* pctx) { if (pstate->pheader_keeper->pkeys->length != pdata_fields->length) { fprintf(stderr, "%s: Header/data length mismatch (%d != %d) at file \"%s\" line %lld.\n", MLR_GLOBALS.argv0, pstate->pheader_keeper->pkeys->length, pdata_fields->length, pctx->filename, pstate->ilno); exit(1); } lrec_t* prec = lrec_unbacked_alloc(); sllse_t* ph = pstate->pheader_keeper->pkeys->phead; rsllse_t* pd = pdata_fields->phead; for ( ; ph != NULL && pd != NULL; ph = ph->pnext, pd = pd->pnext) { // Transfer pointer-free responsibility from the rslls to the lrec object lrec_put(prec, ph->value, pd->value, pd->free_flag); pd->free_flag = 0; } return prec; }
// ---------------------------------------------------------------- static sllv_t* mapper_stats1_emit(mapper_stats1_state_t* pstate) { sllv_t* poutrecs = sllv_alloc(); for (lhmslve_t* pa = pstate->groups->phead; pa != NULL; pa = pa->pnext) { slls_t* pgroup_by_field_values = pa->key; lrec_t* poutrec = lrec_unbacked_alloc(); // Add in a=s,b=t fields: sllse_t* pb = pstate->pgroup_by_field_names->phead; sllse_t* pc = pgroup_by_field_values->phead; for ( ; pb != NULL && pc != NULL; pb = pb->pnext, pc = pc->pnext) { lrec_put(poutrec, pb->value, pc->value, 0); } // Add in fields such as x_sum=#, y_count=#, etc.: lhmsv_t* group_to_acc_field = pa->pvvalue; // for "x", "y" for (lhmsve_t* pd = group_to_acc_field->phead; pd != NULL; pd = pd->pnext) { char* value_field_name = pd->key; lhmsv_t* acc_field_to_acc_state = pd->pvvalue; for (sllse_t* pe = pstate->paccumulator_names->phead; pe != NULL; pe = pe->pnext) { char* acc_name = pe->value; if (streq(acc_name, fake_acc_name_for_setups)) continue; acc_t* pacc = lhmsv_get(acc_field_to_acc_state, acc_name); if (pacc == NULL) { fprintf(stderr, "%s stats1: internal coding error: acc_name \"%s\" has gone missing.\n", MLR_GLOBALS.argv0, acc_name); exit(1); } pacc->pemit_func(pacc->pvstate, value_field_name, acc_name, poutrec); } } sllv_add(poutrecs, poutrec); } sllv_add(poutrecs, NULL); return poutrecs; }
// ---------------------------------------------------------------- static sllv_t* mapper_regularize_process(lrec_t* pinrec, context_t* pctx, void* pvstate) { if (pinrec != NULL) { mapper_regularize_state_t* pstate = (mapper_regularize_state_t*)pvstate; slls_t* current_sorted_field_names = mlr_reference_keys_from_record(pinrec); slls_sort(current_sorted_field_names); slls_t* previous_sorted_field_names = lhmslv_get(pstate->psorted_to_original, current_sorted_field_names); if (previous_sorted_field_names == NULL) { previous_sorted_field_names = slls_copy(current_sorted_field_names); lhmslv_put(pstate->psorted_to_original, previous_sorted_field_names, mlr_copy_keys_from_record(pinrec)); return sllv_single(pinrec); } else { lrec_t* poutrec = lrec_unbacked_alloc(); for (sllse_t* pe = previous_sorted_field_names->phead; pe != NULL; pe = pe->pnext) { lrec_put(poutrec, pe->value, strdup(lrec_get(pinrec, pe->value)), LREC_FREE_ENTRY_VALUE); } lrec_free(pinrec); return sllv_single(poutrec); } } else { return sllv_single(NULL); } }
static void step_counter_sprocess(void* pvstate, char* strv, lrec_t* prec) { step_counter_state_t* pstate = pvstate; pstate->counter++; lrec_put(prec, pstate->output_field_name, mlr_alloc_string_from_ull(pstate->counter), LREC_FREE_ENTRY_VALUE); }
static void step_rsum_dprocess(void* pvstate, double dblv, lrec_t* prec) { step_rsum_state_t* pstate = pvstate; pstate->rsum += dblv; lrec_put(prec, pstate->output_field_name, mlr_alloc_string_from_double(pstate->rsum, MLR_GLOBALS.ofmt), LREC_FREE_ENTRY_VALUE); }