// ---------------------------------------------------------------- static void mapper_step_free(void* pvstate) { mapper_step_state_t* pstate = pvstate; slls_free(pstate->pstepper_names); slls_free(pstate->pvalue_field_names); slls_free(pstate->pgroup_by_field_names); // xxx free the level-2's 1st lhmslv_free(pstate->groups); }
static lrec_t* lrec_reader_csvex_process(void* pvhandle, void* pvstate, context_t* pctx) { lrec_reader_csvex_state_t* pstate = pvstate; // xxx byte-reader open ... // if (pstate->pfr == NULL) { // pstate->pfr = pfr_alloc((FILE*)pvhandle, pstate->peek_buf_len); // } if (pstate->expect_header_line_next) { slls_t* pheader_fields = lrec_reader_csvex_get_fields(pstate); if (pheader_fields == NULL) return NULL; pstate->ilno++; pstate->expect_header_line_next = FALSE; pstate->pheader_keeper = lhmslv_get(pstate->pheader_keepers, pheader_fields); if (pstate->pheader_keeper == NULL) { pstate->pheader_keeper = header_keeper_alloc(NULL, pheader_fields); lhmslv_put(pstate->pheader_keepers, pheader_fields, pstate->pheader_keeper); } else { // Re-use the header-keeper in the header cache slls_free(pheader_fields); } } pstate->ilno++; slls_t* pdata_fields = lrec_reader_csvex_get_fields(pstate); return paste_header_and_data(pstate, pdata_fields); }
static lrec_t* lrec_reader_mmap_csvlite_process_multi_seps(void* pvstate, void* pvhandle, context_t* pctx) { file_reader_mmap_state_t* phandle = pvhandle; lrec_reader_mmap_csvlite_state_t* pstate = pvstate; while (TRUE) { if (pstate->expect_header_line_next) { slls_t* pheader_fields = lrec_reader_mmap_csvlite_get_header_multi_seps(phandle, pstate); if (pheader_fields == NULL) // EOF return NULL; pstate->expect_header_line_next = FALSE; pstate->pheader_keeper = lhmslv_get(pstate->pheader_keepers, pheader_fields); if (pstate->pheader_keeper == NULL) { pstate->pheader_keeper = header_keeper_alloc(NULL, pheader_fields); lhmslv_put(pstate->pheader_keepers, pheader_fields, pstate->pheader_keeper); } else { // Re-use the header-keeper in the header cache slls_free(pheader_fields); } } int end_of_stanza = FALSE; lrec_t* prec = lrec_reader_mmap_csvlite_get_record_multi_seps(phandle, pstate, pstate->pheader_keeper, &end_of_stanza); if (end_of_stanza) { pstate->expect_header_line_next = TRUE; } else if (prec == NULL) { // EOF return NULL; } else { return prec; } } }
// ---------------------------------------------------------------- static void lrec_writer_pprint_process(FILE* output_stream, lrec_t* prec, void* pvstate) { lrec_writer_pprint_state_t* pstate = pvstate; int drain = FALSE; if (prec == NULL) { drain = TRUE; } else { if (pstate->pprev_keys != NULL && !lrec_keys_equal_list(prec, pstate->pprev_keys)) { drain = TRUE; } } if (drain) { if (pstate->num_blocks_written > 0LL) // separate blocks with empty line fputs(pstate->ors, output_stream); print_and_free_record_list(pstate->precords, output_stream, pstate->ors, pstate->ofs, pstate->left_align); if (pstate->pprev_keys != NULL) { slls_free(pstate->pprev_keys); pstate->pprev_keys = NULL; } pstate->precords = sllv_alloc(); pstate->num_blocks_written++; } if (prec != NULL) { sllv_append(pstate->precords, prec); if (pstate->pprev_keys == NULL) pstate->pprev_keys = mlr_copy_keys_from_record(prec); } }
static void lrec_writer_csv_free(void* pvstate) { lrec_writer_csv_state_t* pstate = pvstate; if (pstate->plast_header_output != NULL) { slls_free(pstate->plast_header_output); pstate->plast_header_output = NULL; } }
// ---------------------------------------------------------------- static void mapper_tail_free(void* pvstate) { mapper_tail_state_t* pstate = pvstate; if (pstate->pgroup_by_field_names != NULL) slls_free(pstate->pgroup_by_field_names); if (pstate->precord_lists_by_group != NULL) // xxx free the void-star payloads 1st lhmslv_free(pstate->precord_lists_by_group); }
// ---------------------------------------------------------------- static void mapper_head_free(void* pvstate) { mapper_head_state_t* pstate = (mapper_head_state_t*)pvstate; if (pstate->pgroup_by_field_names != NULL) slls_free(pstate->pgroup_by_field_names); // xxx recursively free void-stars ... here & elsewhere. lhmslv_free(pstate->precord_lists_by_group); }
static lrec_t* lrec_reader_stdio_csv_process(void* pvhandle, void* pvstate, context_t* pctx) { FILE* input_stream = pvhandle; lrec_reader_stdio_csv_state_t* pstate = pvstate; while (TRUE) { if (pstate->expect_header_line_next) { // xxx cmt while (TRUE) { char* hline = mlr_get_line(input_stream, pstate->irs); if (hline == NULL) // EOF return NULL; pstate->ilno++; slls_t* pheader_fields = split_csv_header_line(hline, pstate->ifs, pstate->allow_repeat_ifs); if (pheader_fields->length == 0) { pstate->expect_header_line_next = TRUE; if (pstate->pheader_keeper != NULL) { pstate->pheader_keeper = NULL; } } else { pstate->expect_header_line_next = FALSE; pstate->pheader_keeper = lhmslv_get(pstate->pheader_keepers, pheader_fields); if (pstate->pheader_keeper == NULL) { pstate->pheader_keeper = header_keeper_alloc(hline, pheader_fields); lhmslv_put(pstate->pheader_keepers, pheader_fields, pstate->pheader_keeper); } else { // Re-use the header-keeper in the header cache slls_free(pheader_fields); free(hline); } break; } } } char* line = mlr_get_line(input_stream, pstate->irs); if (line == NULL) // EOF return NULL; // xxx empty-line check ... make a lib func is_empty_modulo_whitespace(). if (!*line) { if (pstate->pheader_keeper != NULL) { pstate->pheader_keeper = NULL; pstate->expect_header_line_next = TRUE; free(line); continue; } } else { pstate->ifnr++; return lrec_parse_stdio_csv_data_line(pstate->pheader_keeper, line, pstate->ifs, pstate->allow_repeat_ifs); } } }
static void lrec_writer_pprint_free(lrec_writer_t* pwriter) { lrec_writer_pprint_state_t* pstate = pwriter->pvstate; if (pstate->precords != NULL) { sllv_free(pstate->precords); pstate->precords = NULL; } if (pstate->pprev_keys != NULL) { slls_free(pstate->pprev_keys); pstate->pprev_keys = NULL; } free(pstate); free(pwriter); }
// ---------------------------------------------------------------- static lrec_t* lrec_reader_mmap_csv_process(void* pvstate, void* pvhandle, context_t* pctx) { lrec_reader_mmap_csv_state_t* pstate = pvstate; file_reader_mmap_state_t* phandle = pvhandle; if (pstate->expect_header_line_next) { if (!lrec_reader_mmap_csv_get_fields(pstate, pstate->pfields, phandle)) return NULL; pstate->ilno++; slls_t* pheader_fields = slls_alloc(); int i = 0; for (rsllse_t* pe = pstate->pfields->phead; i < pstate->pfields->length && pe != NULL; pe = pe->pnext, i++) { if (*pe->value == 0) { fprintf(stderr, "%s: unacceptable empty CSV key at file \"%s\" line %lld.\n", MLR_GLOBALS.argv0, pctx->filename, pstate->ilno); exit(1); } // Transfer pointer-free responsibility from the rslls to the // header fields in the header keeper slls_append(pheader_fields, pe->value, pe->free_flag); pe->free_flag = 0; } rslls_reset(pstate->pfields); pstate->pheader_keeper = lhmslv_get(pstate->pheader_keepers, pheader_fields); if (pstate->pheader_keeper == NULL) { pstate->pheader_keeper = header_keeper_alloc(NULL, pheader_fields); lhmslv_put(pstate->pheader_keepers, pheader_fields, pstate->pheader_keeper, NO_FREE); // freed by header-keeper } else { // Re-use the header-keeper in the header cache slls_free(pheader_fields); } pstate->expect_header_line_next = FALSE; } int rc = lrec_reader_mmap_csv_get_fields(pstate, pstate->pfields, phandle); pstate->ilno++; if (rc == FALSE) // EOF return NULL; else { lrec_t* prec = pstate->use_implicit_header ? paste_indices_and_data(pstate, pstate->pfields, pctx) : paste_header_and_data(pstate, pstate->pfields, pctx); rslls_reset(pstate->pfields); return prec; } }
// ---------------------------------------------------------------- static void lrec_writer_csv_process(FILE* output_stream, lrec_t* prec, void* pvstate) { if (prec == NULL) return; lrec_writer_csv_state_t* pstate = pvstate; char *ors = pstate->ors; char *ofs = pstate->ofs; if (pstate->plast_header_output != NULL) { if (!lrec_keys_equal_list(prec, pstate->plast_header_output)) { slls_free(pstate->plast_header_output); pstate->plast_header_output = NULL; if (pstate->num_header_lines_output > 0LL) fputs(ors, output_stream); } } if (pstate->plast_header_output == NULL) { int nf = 0; if (!pstate->headerless_csv_output) { for (lrece_t* pe = prec->phead; pe != NULL; pe = pe->pnext) { if (nf > 0) fputs(ofs, output_stream); pstate->pquoted_output_func(output_stream, pe->key, pstate->ors, pstate->ofs, pstate->orslen, pstate->ofslen); nf++; } fputs(ors, output_stream); } pstate->plast_header_output = mlr_copy_keys_from_record(prec); pstate->num_header_lines_output++; } int nf = 0; for (lrece_t* pe = prec->phead; pe != NULL; pe = pe->pnext) { if (nf > 0) fputs(ofs, output_stream); pstate->pquoted_output_func(output_stream, pe->value, pstate->ors, pstate->ofs, pstate->orslen, pstate->ofslen); nf++; } fputs(ors, output_stream); pstate->onr++; // See ../README.md for memory-management conventions lrec_free(prec); }
void ap_free(ap_state_t* pstate) { if (pstate == NULL) return; for (sllve_t* pe = pstate->pflag_defs->phead; pe != NULL; pe = pe->pnext) { ap_flag_def_t* pdef = pe->pvdata; if (pdef->type == AP_STRING_LIST_FLAG && pdef->pval != NULL) { slls_t** pplist = pdef->pval; if (*pplist != NULL) slls_free(*pplist); } free(pdef); } sllv_free(pstate->pflag_defs); free(pstate); }
static void lrec_writer_csv_process(FILE* output_stream, lrec_t* prec, void* pvstate) { if (prec == NULL) return; lrec_writer_csv_state_t* pstate = pvstate; char ors = pstate->ors; char ofs = pstate->ofs; if (pstate->plast_header_output != NULL) { // xxx make a fcn to compare these w/o copy: put it in mixutil. if (!lrec_keys_equal_list(prec, pstate->plast_header_output)) { slls_free(pstate->plast_header_output); pstate->plast_header_output = NULL; if (pstate->num_header_lines_output > 0LL) fputc(ors, output_stream); } } if (pstate->plast_header_output == NULL) { int nf = 0; for (lrece_t* pe = prec->phead; pe != NULL; pe = pe->pnext) { if (nf > 0) fputc(ofs, output_stream); fputs(pe->key, output_stream); nf++; } fputc(ors, output_stream); pstate->plast_header_output = mlr_copy_keys_from_record(prec); pstate->num_header_lines_output++; } int nf = 0; for (lrece_t* pe = prec->phead; pe != NULL; pe = pe->pnext) { if (nf > 0) fputc(ofs, output_stream); fputs(pe->value, output_stream); nf++; } fputc(ors, output_stream); pstate->onr++; lrec_free(prec); // xxx cmt mem-mgmt }
// ---------------------------------------------------------------- static lrec_t* lrec_reader_stdio_xtab_process(void* pvstate, void* pvhandle, context_t* pctx) { FILE* input_stream = pvhandle; lrec_reader_stdio_xtab_state_t* pstate = pvstate; if (pstate->at_eof) return NULL; slls_t* pxtab_lines = slls_alloc(); while (TRUE) { char* line = (pstate->ifslen == 1) ? mlr_get_cline(input_stream, pstate->ifs[0]) : mlr_get_sline(input_stream, pstate->ifs, pstate->ifslen); if (line == NULL) { // EOF // EOF or blank line terminates the stanza. pstate->at_eof = TRUE; if (pxtab_lines->length == 0) { slls_free(pxtab_lines); return NULL; } else { return (pstate->ipslen == 1) ? lrec_parse_stdio_xtab_single_ips(pxtab_lines, pstate->ips[0], pstate->allow_repeat_ips) : lrec_parse_stdio_xtab_multi_ips(pxtab_lines, pstate->ips, pstate->ipslen, pstate->allow_repeat_ips); } } else if (*line == '\0') { free(line); if (pxtab_lines->length > 0) { return (pstate->ipslen == 1) ? lrec_parse_stdio_xtab_single_ips(pxtab_lines, pstate->ips[0], pstate->allow_repeat_ips) : lrec_parse_stdio_xtab_multi_ips(pxtab_lines, pstate->ips, pstate->ipslen, pstate->allow_repeat_ips); } } else { slls_add_with_free(pxtab_lines, line); } } }
static void lrec_free_multiline_backing(lrec_t* prec) { slls_free(prec->pxtab_lines); }
static void lrec_writer_csv_free(lrec_writer_t* pwriter) { lrec_writer_csv_state_t* pstate = pwriter->pvstate; slls_free(pstate->plast_header_output); free(pstate); free(pwriter); }
// ---------------------------------------------------------------- static lrec_t* lrec_reader_stdio_csvlite_process(void* pvstate, void* pvhandle, context_t* pctx) { FILE* input_stream = pvhandle; lrec_reader_stdio_csvlite_state_t* pstate = pvstate; while (TRUE) { if (pstate->expect_header_line_next) { while (TRUE) { char* hline = (pstate->irslen == 1) ? mlr_get_cline(input_stream, pstate->irs[0]) : mlr_get_sline(input_stream, pstate->irs, pstate->irslen); if (hline == NULL) // EOF return NULL; pstate->ilno++; slls_t* pheader_fields = (pstate->ifslen == 1) ? split_csvlite_header_line_single_ifs(hline, pstate->ifs[0], pstate->allow_repeat_ifs) : split_csvlite_header_line_multi_ifs(hline, pstate->ifs, pstate->ifslen, pstate->allow_repeat_ifs); if (pheader_fields->length == 0) { pstate->expect_header_line_next = TRUE; if (pstate->pheader_keeper != NULL) { pstate->pheader_keeper = NULL; } } else { for (sllse_t* pe = pheader_fields->phead; pe != NULL; pe = pe->pnext) { if (*pe->value == 0) { fprintf(stderr, "%s: unacceptable empty CSV key at file \"%s\" line %lld.\n", MLR_GLOBALS.argv0, pctx->filename, pstate->ilno); exit(1); } } pstate->expect_header_line_next = FALSE; pstate->pheader_keeper = lhmslv_get(pstate->pheader_keepers, pheader_fields); if (pstate->pheader_keeper == NULL) { pstate->pheader_keeper = header_keeper_alloc(hline, pheader_fields); lhmslv_put(pstate->pheader_keepers, pheader_fields, pstate->pheader_keeper, NO_FREE); // freed by header-keeper } else { // Re-use the header-keeper in the header cache slls_free(pheader_fields); free(hline); } break; } } } char* line = (pstate->irslen == 1) ? mlr_get_cline(input_stream, pstate->irs[0]) : mlr_get_sline(input_stream, pstate->irs, pstate->irslen); if (line == NULL) // EOF return NULL; pstate->ilno++; if (!*line) { if (pstate->pheader_keeper != NULL) { pstate->pheader_keeper = NULL; pstate->expect_header_line_next = TRUE; free(line); continue; } } else { pstate->ifnr++; if (pstate->ifslen == 1) { return pstate->use_implicit_header ? lrec_parse_stdio_csvlite_data_line_single_ifs_implicit_header( pstate->pheader_keeper, pctx->filename, pstate->ilno, line, pstate->ifs[0], pstate->allow_repeat_ifs) : lrec_parse_stdio_csvlite_data_line_single_ifs(pstate->pheader_keeper, pctx->filename, pstate->ilno, line, pstate->ifs[0], pstate->allow_repeat_ifs); } else { return pstate->use_implicit_header ? lrec_parse_stdio_csvlite_data_line_multi_ifs_implicit_header( pstate->pheader_keeper, pctx->filename, pstate->ilno, line, pstate->ifs, pstate->ifslen, pstate->allow_repeat_ifs) : lrec_parse_stdio_csvlite_data_line_multi_ifs(pstate->pheader_keeper, pctx->filename, pstate->ilno, line, pstate->ifs, pstate->ifslen, pstate->allow_repeat_ifs); } } } }
// ---------------------------------------------------------------- static lrec_t* lrec_reader_stdio_csv_process(void* pvstate, void* pvhandle, context_t* pctx) { lrec_reader_stdio_csv_state_t* pstate = pvstate; // Ingest the next header line, if expected if (pstate->expect_header_line_next) { while (TRUE) { if (!lrec_reader_stdio_csv_get_fields(pstate, pstate->pfields, pctx, TRUE)) return NULL; pstate->ilno++; // We check for comments here rather than within the parser since it's important // for users to be able to comment out lines containing double-quoted newlines. if (pstate->comment_string != NULL && pstate->pfields->phead != NULL) { if (streqn(pstate->pfields->phead->value, pstate->comment_string, pstate->comment_string_length)) { if (pstate->comment_handling == PASS_COMMENTS) { int i = 0; for ( rsllse_t* pe = pstate->pfields->phead; i < pstate->pfields->length && pe != NULL; pe = pe->pnext, i++) { if (i > 0) fputs(pstate->ifs, stdout); fputs(pe->value, stdout); } if (pstate->do_auto_line_term) { fputs(pctx->auto_line_term, stdout); } else { fputs(pstate->irs, stdout); } } rslls_reset(pstate->pfields); continue; } } slls_t* pheader_fields = slls_alloc(); int i = 0; for (rsllse_t* pe = pstate->pfields->phead; i < pstate->pfields->length && pe != NULL; pe = pe->pnext) { if (*pe->value == 0) { fprintf(stderr, "%s: unacceptable empty CSV key at file \"%s\" line %lld.\n", MLR_GLOBALS.bargv0, pctx->filename, pstate->ilno); exit(1); } // Transfer pointer-free responsibility from the rslls to the // header fields in the header keeper slls_append(pheader_fields, pe->value, pe->free_flag); pe->free_flag = 0; } rslls_reset(pstate->pfields); pstate->pheader_keeper = lhmslv_get(pstate->pheader_keepers, pheader_fields); if (pstate->pheader_keeper == NULL) { pstate->pheader_keeper = header_keeper_alloc(NULL, pheader_fields); lhmslv_put(pstate->pheader_keepers, pheader_fields, pstate->pheader_keeper, NO_FREE); // freed by header-keeper } else { // Re-use the header-keeper in the header cache slls_free(pheader_fields); } pstate->expect_header_line_next = FALSE; break; } } // Ingest the next data line, if expected while (TRUE) { int rc = lrec_reader_stdio_csv_get_fields(pstate, pstate->pfields, pctx, FALSE); pstate->ilno++; if (rc == FALSE) // EOF return NULL; // We check for comments here rather than within the parser since it's important // for users to be able to comment out lines containing double-quoted newlines. if (pstate->comment_string != NULL && pstate->pfields->phead != NULL) { if (streqn(pstate->pfields->phead->value, pstate->comment_string, pstate->comment_string_length)) { if (pstate->comment_handling == PASS_COMMENTS) { int i = 0; for ( rsllse_t* pe = pstate->pfields->phead; i < pstate->pfields->length && pe != NULL; pe = pe->pnext, i++) { if (i > 0) fputs(pstate->ifs, stdout); fputs(pe->value, stdout); } if (pstate->do_auto_line_term) { fputs(pctx->auto_line_term, stdout); } else { fputs(pstate->irs, stdout); } } rslls_reset(pstate->pfields); continue; } } lrec_t* prec = pstate->use_implicit_header ? paste_indices_and_data(pstate, pstate->pfields, pctx) : paste_header_and_data(pstate, pstate->pfields, pctx); rslls_reset(pstate->pfields); return prec; } }
// ---------------------------------------------------------------- static void mapper_reorder_free(void* pvstate) { mapper_reorder_state_t* pstate = (mapper_reorder_state_t*)pvstate; if (pstate->pfield_name_list != NULL) slls_free(pstate->pfield_name_list); }
// ---------------------------------------------------------------- int ap_parse(ap_state_t* pstate, char* verb, int* pargi, int argc, char** argv) { int argi = *pargi; int ok = TRUE; while (argi < argc) { if (argv[argi][0] != '-') { break; } if (streq(argv[argi], "-h") || streq(argv[argi], "--help")) { ok = FALSE; break; } ap_flag_def_t* pdef = ap_find(pstate, argv[argi]); if (pdef == NULL) { ok = FALSE; break; } if ((argc-argi) < pdef->count) { fprintf(stderr, "%s %s: option %s requires an argument.\n", argv[0], verb, argv[argi]); fprintf(stderr, "\n"); ok = FALSE; break; } if (pdef->type == AP_INT_VALUE_FLAG) { *(int *)pdef->pval = pdef->intval; } else if (pdef->type == AP_CHAR_FLAG) { if (!try_sep_from_arg(argv[argi+1], (char *)pdef->pval)) { fprintf(stderr, "%s %s: couldn't parse \"%s\" after \"%s\" as character.\n", argv[0], verb, argv[argi+1], argv[argi]); fprintf(stderr, "\n"); } } else if (pdef->type == AP_INT_FLAG) { if (sscanf(argv[argi+1], "%d", (int *)pdef->pval) != 1) { fprintf(stderr, "%s %s: couldn't parse \"%s\" after \"%s\" as integer.\n", argv[0], verb, argv[argi+1], argv[argi]); fprintf(stderr, "\n"); } } else if (pdef->type == AP_DOUBLE_FLAG) { if (!mlr_try_double_from_string(argv[argi+1], (double *)pdef->pval)) { fprintf(stderr, "%s %s: couldn't parse \"%s\" after \"%s\" as double.\n", argv[0], verb, argv[argi+1], argv[argi]); fprintf(stderr, "\n"); } } else if (pdef->type == AP_STRING_FLAG) { char** pstring = pdef->pval; *pstring = argv[argi+1]; pdef->pval = pstring; } else if (pdef->type == AP_STRING_LIST_FLAG) { slls_t** pplist = pdef->pval; if (*pplist != NULL) slls_free(*pplist); *pplist = slls_from_line(argv[argi+1], ',', FALSE); pdef->pval = pplist; } else { ok = FALSE; fprintf(stderr, "argparse.c: coding error: flag-def type %x not recognized.\n", pdef->type); fprintf(stderr, "\n"); break; } argi += pdef->count; } *pargi = argi; return ok; }