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