TPCCLIB
Loading...
Searching...
No Matches
csv.c
Go to the documentation of this file.
1
5/*****************************************************************************/
6#include "tpcclibConfig.h"
7/*****************************************************************************/
8#include <stdio.h>
9#include <stdlib.h>
10#include <math.h>
11#include <time.h>
12#include <string.h>
13/*****************************************************************************/
14#include "tpccsv.h"
15/*****************************************************************************/
16
17/*****************************************************************************/
24 CSV *csv
25) {
26 if(csv==NULL) return;
27 csv->c=NULL; csv->_item_nr=csv->nr=csv->row_nr=csv->col_nr=0;
28 csv->separator='\t'; //(char)0;
29}
30/*****************************************************************************/
31
32/*****************************************************************************/
40 CSV *csv
41) {
42 if(csv==NULL) return;
43 for(int i=0; i<csv->_item_nr; i++) free(csv->c[i].content);
44 free(csv->c);
45 csvInit(csv);
46}
47/*****************************************************************************/
48
49/*****************************************************************************/
60 CSV *csv,
62 int nr
63) {
64 if(csv==NULL) return TPCERROR_FAIL;
65 if(nr<1) return TPCERROR_OK;
66
67 /* If not allocated previously, then just allocate and thats it */
68 if(csv->_item_nr==0) {
69 csv->c=(CSV_item*)calloc(nr, sizeof(CSV_item));
70 if(csv->c==NULL) return TPCERROR_OUT_OF_MEMORY;
71 csv->_item_nr=nr;
72 return TPCERROR_OK;
73 }
74
75 /* How many unused places there are already? */
76 int unused=csv->_item_nr-csv->nr;
77 /* Check if enough memory is already allocated */
78 if(unused>=nr) return TPCERROR_OK;
79
80 /* Ok, we have to reallocate more memory for the list */
81 nr+=csv->nr;
82 CSV_item *new_list;
83 new_list=(CSV_item*)realloc(csv->c, nr*sizeof(CSV_item));
84 if(new_list==NULL) return TPCERROR_OUT_OF_MEMORY;
85 else csv->c=new_list;
86 /* Initiate the list */
87 for(int i=csv->_item_nr; i<nr; i++) {
88 csv->c[i].row=0; csv->c[i].col=0; csv->c[i].content=NULL;
89 }
90 csv->_item_nr=nr;
91 return TPCERROR_OK;
92}
93/*****************************************************************************/
94
95/*****************************************************************************/
104 CSV *csv1,
106 CSV *csv2
107) {
108 if(csv1==NULL || csv2==NULL) return TPCERROR_FAIL;
109 if(csv1->nr<1 || csv1->_item_nr<csv1->nr || csv1->row_nr<1 || csv1->col_nr<1) return TPCERROR_NO_DATA;
110
111 /* Empty the duplicate */
112 csvFree(csv2);
113
114 /* Allocate memory for csv2 */
115 int ret=csvAllocate(csv2, csv1->row_nr*csv1->col_nr);
116 if(ret!=TPCERROR_OK) return(ret);
117 csv2->col_nr=csv1->col_nr;
118 csv2->row_nr=csv1->row_nr;
119 csv2->nr=csv2->col_nr*csv2->row_nr;
120
121 /* Copy the contents */
122 csv2->separator=csv1->separator;
123 int ni=0, fulln=0;
124 for(int ri=0; ri<csv2->row_nr; ri++)
125 for(int ci=0; ci<csv2->col_nr; ci++) {
126 csv2->c[ni].row=ri;
127 csv2->c[ni].col=ci;
128 char *cp=csvCell(csv1, ri, ci);
129 if(cp==NULL) csv2->c[ni].content=NULL; else {csv2->c[ni].content=strdup(cp); fulln++;}
130 ni++;
131 }
132 if(fulln<1) return TPCERROR_NO_DATA;
133 return TPCERROR_OK;
134}
135/*****************************************************************************/
136
137/*****************************************************************************/
146 CSV *csv,
148 const char *s,
150 int newline
151) {
152 if(csv==NULL) return TPCERROR_FAIL;
153 /* Allocate memory, if needed, and if needed, then a bigger chunk */
154 int avail=csv->_item_nr-csv->nr;
155 if(avail<1) {
156 int ret=csvAllocate(csv, 10);
157 if(ret!=TPCERROR_OK) return ret;
158 }
159 /* Write the item */
160 if(s==NULL || *s=='\0') csv->c[csv->nr].content=strdup("");
161 else csv->c[csv->nr].content=strdup(s);
162 if(csv->c[csv->nr].content==NULL) return TPCERROR_OUT_OF_MEMORY;
163 /* Set the row and column number */
164 int r, c;
165 if(csv->nr==0) {r=c=0;}
166 else {
167 if(newline!=0) {
168 c=0;
169 r=csv->c[csv->nr-1].row+1;
170 } else {
171 c=csv->c[csv->nr-1].col+1;
172 r=csv->c[csv->nr-1].row;
173 }
174 }
175 csv->c[csv->nr].col=c; csv->c[csv->nr].row=r;
176 /* Update row_nr and max col nr, if necessary */
177 c++; r++;
178 if(c>csv->col_nr) csv->col_nr=c;
179 if(r>csv->row_nr) csv->row_nr=r;
180
181 csv->nr++;
182 return TPCERROR_OK;
183}
184/*****************************************************************************/
185
186/*****************************************************************************/
195 CSV *csv,
197 double v,
199 int newline,
201 int tointl
202) {
203 int ret;
204 if(isnan(v)) {
205 ret=csvPutString(csv, "", newline);
206 } else {
207 char s[128];
208 sprintf(s, "%g", v); if(tointl) strReplaceChar(s, '.', ',');
209 ret=csvPutString(csv, s, newline);
210 }
211 return ret;
212}
213/*****************************************************************************/
214
215/*****************************************************************************/
224 CSV *csv,
226 int v,
228 int newline
229) {
230 int ret;
231 char s[128];
232 sprintf(s, "%d", v);
233 ret=csvPutString(csv, s, newline);
234 return ret;
235}
236/*****************************************************************************/
237
238/*****************************************************************************/
246 CSV *csv,
248 int row
249) {
250 if(csv==NULL) return(0);
251// int i, n=0;
252// for(i=0; i<csv->nr; i++) if(csv->c[i].row==row) n++;
253// return(n);
254 int n=-1;
255 for(int i=0; i<csv->nr; i++) if(csv->c[i].row==row && csv->c[i].col>n) n=csv->c[i].col;
256 return(1+n);
257}
258/*****************************************************************************/
259
260/*****************************************************************************/
271 CSV *csv
272) {
273 if(csv==NULL) return TPCERROR_FAIL;
274 if(csv->nr<1) {csv->col_nr=0; csv->row_nr=0; return(TPCERROR_OK);}
275
276 int maxri=0, maxci=0;
277 for(int i=0; i<csv->nr; i++) {
278 if(csv->c[i].row>maxri) maxri=csv->c[i].row;
279 if(csv->c[i].col>maxci) maxci=csv->c[i].col;
280 }
281 csv->col_nr=1+maxci; csv->row_nr=1+maxri;
282 return(TPCERROR_OK);
283}
284/*****************************************************************************/
285
286/*****************************************************************************/
294 CSV *csv
295) {
296 if(csv==NULL) return(0);
297 if(csv->nr<2) return(1);
298 int i, r, n=0, m=0;
299 i=0; r=csv->c[i].row; m++;
300 for(i=1; i<csv->nr; i++) {
301 if(r==csv->c[i].row) {
302 m++;
303 continue;}
304 if(n>0 && m!=n) return(0);
305 r=csv->c[i].row; n=m; m=1;
306 }
307 if(n>0 && m!=n) return(0);
308 return(1);
309}
310/*****************************************************************************/
311
312/*****************************************************************************/
323 CSV *csv
324) {
325 if(csv==NULL) return TPCERROR_FAIL;
326 if(csv->nr<1 || csv->col_nr<2 || csv->row_nr<2) return TPCERROR_NO_DATA;
327
328 int ci=csv->col_nr-1;
329 while(ci>0) {
330 /* Does this column contain any data? */
331 int n=0;
332 for(int i=0; i<csv->nr; i++) if(csv->c[i].col==ci) {
333 if(csv->c[i].content!=NULL && csv->c[i].content[0]!='\0' && csv->c[i].content[0]!='#') n++;
334 }
335 if(n>0) break; // yes
336 /* No, so let's delete the last column */
337 int i=csv->nr-1;
338 while(i>=0) {
339 if(csv->c[i].col==ci) {
340 if(csvRemoveItem(csv, i)!=TPCERROR_OK) return TPCERROR_FAIL;
341 }
342 i--;
343 }
344 csv->col_nr--;
345 /* Try the previous column */
346 ci--;
347 }
348 return(TPCERROR_OK);
349}
350/*****************************************************************************/
351
352/*****************************************************************************/
360 CSV *csv,
362 int row,
364 int col
365) {
366 if(csv==NULL) return((char*)NULL);
367 for(int i=0; i<csv->nr; i++)
368 if(csv->c[i].row==row && csv->c[i].col==col)
369 return(csv->c[i].content);
370 return((char*)NULL);
371}
372/*****************************************************************************/
373
374/*****************************************************************************/
382 CSV *csv,
384 int row,
386 int col,
388 const char *s
389) {
390 if(csv==NULL) return(TPCERROR_FAIL);
391 int ci=-1;
392 for(int i=0; i<csv->nr; i++) if(csv->c[i].row==row && csv->c[i].col==col) {ci=i; break;}
393 if(ci<0) return(TPCERROR_MISSING_DATA);
394 /* Delete the previous value */
395 free(csv->c[ci].content);
396 /* Save the new item */
397 if(s==NULL || *s=='\0') csv->c[ci].content=strdup("");
398 else csv->c[ci].content=strdup(s);
399 if(csv->c[ci].content==NULL) return(TPCERROR_OUT_OF_MEMORY);
400 return(TPCERROR_OK);
401}
402/*****************************************************************************/
403
404/*****************************************************************************/
411 CSV *csv,
413 int i
414) {
415 if(csv==NULL || i<0) return TPCERROR_FAIL;
416 if(csv->nr<1 || i>=csv->nr) return TPCERROR_NO_DATA;
417 free(csv->c[i].content); csv->c[i].content=NULL;
418 for(int j=i+1; j<csv->nr; j++) {
419 csv->c[j-1].row=csv->c[j].row;
420 csv->c[j-1].col=csv->c[j].col;
421 csv->c[j-1].content=csv->c[j].content;
422 }
423 csv->nr--; csv->c[csv->nr].content=NULL;
424 return(TPCERROR_OK);
425}
426/*****************************************************************************/
427
428/*****************************************************************************/
436 CSV *csv
437) {
438 if(csv==NULL) return TPCERROR_FAIL;
439 if(csv->nr<1 || csv->row_nr<1 || csv->col_nr<1) return TPCERROR_NO_DATA;
440
441 /* Check the rows */
442 int ri=csv->row_nr-1;
443 while(ri>=0) {
444 int n=0;
445 for(int ci=0; ci<csv->col_nr; ci++) {
446 char *cp=csvCell(csv, ri, ci); if(cp==NULL) continue;
447 if(*cp=='\0' || *cp=='#') continue;
448 n++;
449 }
450 if(n==0) { // this line is empty
451 int i=csv->nr-1;
452 while(i>=0) {
453 if(csv->c[i].row==ri) csvRemoveItem(csv, i);
454 i--;
455 }
456 for(i=0; i<csv->nr; i++) if(csv->c[i].row>ri) csv->c[i].row--;
457 csv->row_nr--;
458 }
459 ri--;
460 }
461 return(TPCERROR_OK);
462}
463/*****************************************************************************/
464
465/*****************************************************************************/
472 CSV *csv
473) {
474 if(csv==NULL) return(TPCERROR_FAIL);
475 if(csv->nr<1) return(TPCERROR_NO_DATA);
476
477 int i=csv->nr-1;
478 while(i>=0) {
479 if(csv->c[i].content!=NULL && csv->c[i].content[0]=='#') csvRemoveItem(csv, i);
480 i--;
481 }
482 return(TPCERROR_OK);
483// return(csvRemoveEmptyRows(csv));
484}
485/*****************************************************************************/
486
487/*****************************************************************************/
489
490static int csvReorgQSort(const void *c1, const void *c2)
491{
492 if(((CSV_item*)c2)->row > ((CSV_item*)c1)->row) return(-1);
493 if(((CSV_item*)c2)->row < ((CSV_item*)c1)->row) return(+1);
494 if(((CSV_item*)c2)->col > ((CSV_item*)c1)->col) return(-1);
495 if(((CSV_item*)c2)->col < ((CSV_item*)c1)->col) return(+1);
496 return(0);
497}
499
505 CSV *d,
507 TPCSTATUS *status
508) {
509 int verbose=0; if(status!=NULL) verbose=status->verbose;
510 if(verbose>0) printf("%s()\n", __func__);
511 /* Check that required data exists */
512 if(d==NULL || d->nr<1) {
513 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
514 return TPCERROR_NO_DATA;
515 }
516 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
517 if(d->nr<2) return TPCERROR_OK;
518 qsort(d->c, d->nr, sizeof(CSV_item), csvReorgQSort);
519 return TPCERROR_OK;
520}
521/*****************************************************************************/
522
523/*****************************************************************************/
532 CSV *csv
533) {
534 if(csv==NULL) return(TPCERROR_FAIL);
535 if(csv->nr<1) return(TPCERROR_NO_DATA);
536
537 /* Get dimensions */
538 {
539 int ret=csvSetDimensions(csv);
540 if(ret!=TPCERROR_OK) return(ret);
541 }
542 if(csv->row_nr<1 || csv->col_nr<1) return(TPCERROR_NO_DATA);
543
544 /* If only one row and column, then nothing to do */
545 if(csv->row_nr==1 && csv->col_nr==1) return(TPCERROR_OK);
546
547 /* Switch column and row numbers */
548 for(int i=0; i<csv->nr; i++) {
549 int cr=csv->c[i].col;
550 csv->c[i].col=csv->c[i].row;
551 csv->c[i].row=cr;
552 }
553 {
554 int cn=csv->col_nr;
555 csv->col_nr=csv->row_nr;
556 csv->row_nr=cn;
557 }
558
559 /* Sort CSV data by rows and columns */
560 {
561 int ret=csvReorg(csv, NULL);
562 if(ret!=TPCERROR_OK) return(ret);
563 }
564
565 return(TPCERROR_OK);
566}
567/*****************************************************************************/
568
569/*****************************************************************************/
void csvInit(CSV *csv)
Definition csv.c:22
int csvIsRegular(CSV *csv)
Definition csv.c:292
int csvPutInt(CSV *csv, int v, int newline)
Definition csv.c:222
int csvRemoveComments(CSV *csv)
Definition csv.c:470
char * csvCell(CSV *csv, int row, int col)
Definition csv.c:358
int csvAllocate(CSV *csv, int nr)
Definition csv.c:58
int csvCellReplace(CSV *csv, int row, int col, const char *s)
Definition csv.c:380
int csvRemoveItem(CSV *csv, int i)
Definition csv.c:409
int csvSetDimensions(CSV *csv)
Definition csv.c:269
int csvTrimRight(CSV *csv)
Definition csv.c:321
int csvDuplicate(CSV *csv1, CSV *csv2)
Make a duplicate of CSV structure.
Definition csv.c:102
int csvTranspose(CSV *csv)
Definition csv.c:530
int csvPutString(CSV *csv, const char *s, int newline)
Definition csv.c:144
int csvReorg(CSV *d, TPCSTATUS *status)
Definition csv.c:503
int csvRowLength(CSV *csv, int row)
Definition csv.c:244
int csvRemoveEmptyRows(CSV *csv)
Definition csv.c:434
int csvPutDouble(CSV *csv, double v, int newline, int tointl)
Definition csv.c:193
void csvFree(CSV *csv)
Definition csv.c:38
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
void strReplaceChar(char *s, char c1, char c2)
Definition stringext.c:134
char * strdup(const char *s)
Definition stringext.c:185
int col
Definition tpccsv.h:28
int row
Definition tpccsv.h:26
char * content
Definition tpccsv.h:30
Definition tpccsv.h:36
int row_nr
Definition tpccsv.h:44
int col_nr
Definition tpccsv.h:46
char separator
Definition tpccsv.h:49
CSV_item * c
Definition tpccsv.h:38
int nr
Definition tpccsv.h:42
int _item_nr
Definition tpccsv.h:40
int verbose
Verbose level, used by statusPrint() etc.
Header file for library libtpccsv.
@ TPCERROR_FAIL
General error.
@ TPCERROR_OUT_OF_MEMORY
Cannot allocate memory.
@ TPCERROR_OK
No error.
@ TPCERROR_NO_DATA
File contains no data.
@ TPCERROR_MISSING_DATA
File contains missing values.