1 #include <stdlib.h>
2 #include "containers/mixutil.h"
3 #include "lib/mlrutil.h"
4 #include "output/lrec_writers.h"
5
6 typedef struct _lrec_writer_csvlite_state_t {
7 int onr;
8 char* ors;
9 char* ofs;
10 long long num_header_lines_output;
11 slls_t* plast_header_output;
12 int headerless_csv_output;
13 } lrec_writer_csvlite_state_t;
14
15 static void lrec_writer_csvlite_free(lrec_writer_t* pwriter, context_t* pctx);
16 static void lrec_writer_csvlite_process(void* pvstate, FILE* output_stream, lrec_t* prec, char* ors);
17 static void lrec_writer_csvlite_process_auto_ors(void* pvstate, FILE* output_stream, lrec_t* prec, context_t* pctx);
18 static void lrec_writer_csvlite_process_nonauto_ors(void* pvstate, FILE* output_stream, lrec_t* prec, context_t* pctx);
19
20 // ----------------------------------------------------------------
lrec_writer_csvlite_alloc(char * ors,char * ofs,int headerless_csv_output)21 lrec_writer_t* lrec_writer_csvlite_alloc(char* ors, char* ofs, int headerless_csv_output) {
22 lrec_writer_t* plrec_writer = mlr_malloc_or_die(sizeof(lrec_writer_t));
23
24 lrec_writer_csvlite_state_t* pstate = mlr_malloc_or_die(sizeof(lrec_writer_csvlite_state_t));
25 pstate->onr = 0;
26 pstate->ors = ors;
27 pstate->ofs = ofs;
28 pstate->num_header_lines_output = 0LL;
29 pstate->plast_header_output = NULL;
30 pstate->headerless_csv_output = headerless_csv_output;
31
32 plrec_writer->pvstate = (void*)pstate;
33 plrec_writer->pprocess_func = streq(ors, "auto")
34 ? lrec_writer_csvlite_process_auto_ors
35 : lrec_writer_csvlite_process_nonauto_ors;
36 plrec_writer->pfree_func = lrec_writer_csvlite_free;
37
38 return plrec_writer;
39 }
40
lrec_writer_csvlite_free(lrec_writer_t * pwriter,context_t * pctx)41 static void lrec_writer_csvlite_free(lrec_writer_t* pwriter, context_t* pctx) {
42 lrec_writer_csvlite_state_t* pstate = pwriter->pvstate;
43 slls_free(pstate->plast_header_output);
44 free(pstate);
45 free(pwriter);
46 }
47
48 // ----------------------------------------------------------------
lrec_writer_csvlite_process_auto_ors(void * pvstate,FILE * output_stream,lrec_t * prec,context_t * pctx)49 static void lrec_writer_csvlite_process_auto_ors(void* pvstate, FILE* output_stream, lrec_t* prec, context_t* pctx) {
50 lrec_writer_csvlite_process(pvstate, output_stream, prec, pctx->auto_line_term);
51 }
52
lrec_writer_csvlite_process_nonauto_ors(void * pvstate,FILE * output_stream,lrec_t * prec,context_t * pctx)53 static void lrec_writer_csvlite_process_nonauto_ors(void* pvstate, FILE* output_stream, lrec_t* prec, context_t* pctx) {
54 lrec_writer_csvlite_state_t* pstate = pvstate;
55 lrec_writer_csvlite_process(pvstate, output_stream, prec, pstate->ors);
56 }
57
58
lrec_writer_csvlite_process(void * pvstate,FILE * output_stream,lrec_t * prec,char * ors)59 static void lrec_writer_csvlite_process(void* pvstate, FILE* output_stream, lrec_t* prec, char* ors) {
60 if (prec == NULL)
61 return;
62 lrec_writer_csvlite_state_t* pstate = pvstate;
63 char* ofs = pstate->ofs;
64
65 if (pstate->plast_header_output != NULL) {
66 if (!lrec_keys_equal_list(prec, pstate->plast_header_output)) {
67 slls_free(pstate->plast_header_output);
68 pstate->plast_header_output = NULL;
69 if (pstate->num_header_lines_output > 0LL)
70 fputs(ors, output_stream);
71 }
72 }
73
74 if (pstate->plast_header_output == NULL) {
75 if (!pstate->headerless_csv_output) {
76 int nf = 0;
77 for (lrece_t* pe = prec->phead; pe != NULL; pe = pe->pnext) {
78 if (nf > 0)
79 fputs(ofs, output_stream);
80 fputs(pe->key, output_stream);
81 nf++;
82 }
83 fputs(ors, output_stream);
84 }
85 pstate->plast_header_output = mlr_copy_keys_from_record(prec);
86 pstate->num_header_lines_output++;
87 }
88
89 int nf = 0;
90 for (lrece_t* pe = prec->phead; pe != NULL; pe = pe->pnext) {
91 if (nf > 0)
92 fputs(ofs, output_stream);
93 fputs(pe->value, output_stream);
94 nf++;
95 }
96 fputs(ors, output_stream);
97 pstate->onr++;
98
99 lrec_free(prec); // end of baton-pass
100 }
101