TPCCLIB
Loading...
Searching...
No Matches
tpccsv.h File Reference

Header file for library libtpccsv. More...

#include "tpcclibConfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "tpcextensions.h"

Go to the source code of this file.

Data Structures

struct  CSV_item
struct  CSV

Functions

void csvInit (CSV *csv)
void csvFree (CSV *csv)
int csvAllocate (CSV *csv, int nr)
int csvDuplicate (CSV *csv1, CSV *csv2)
 Make a duplicate of CSV structure.
int csvPutString (CSV *csv, const char *s, int newline)
int csvPutDouble (CSV *csv, double v, int newline, int tointl)
int csvPutInt (CSV *csv, int v, int newline)
int csvRowLength (CSV *csv, int row)
int csvSetDimensions (CSV *csv)
int csvIsRegular (CSV *csv)
int csvTrimRight (CSV *csv)
char * csvCell (CSV *csv, int row, int col)
int csvCellReplace (CSV *csv, int row, int col, const char *s)
int csvRemoveItem (CSV *csv, int i)
int csvRemoveEmptyRows (CSV *csv)
int csvRemoveComments (CSV *csv)
int csvReorg (CSV *d, TPCSTATUS *status)
int csvTranspose (CSV *d)
int csvList (CSV *csv, FILE *fp)
int csvWrite (CSV *csv, int regular, FILE *fp, TPCSTATUS *status)
int csvRead (CSV *csv, FILE *fp, TPCSTATUS *status)
int csvPutLine (CSV *csv, const char *line, TPCSTATUS *status)
int csvPutLineWithSpaces (CSV *csv, const char *line, TPCSTATUS *status)
int csvCleanSpaces (CSV *csv)
int csvFindField (CSV *csv, const char *s, int start_index)
int csvSearchField (CSV *csv, const char *s, int start_index)

Detailed Description

Header file for library libtpccsv.

CSV and TSV data processing and file i/o

Author
Vesa Oikonen

Definition in file tpccsv.h.

Function Documentation

◆ csvAllocate()

int csvAllocate ( CSV * csv,
int nr )

Allocate memory for list of field items for CSV data.

Any previous content is preserved.

Precondition
Before first use initialize the CSV struct with csvInit().
Returns
enum tpcerror (TPCERROR_OK when successful).
Author
Vesa Oikonen
See also
csvInit, csvFree, csvDuplicate, csvSetDimensions, csvList
Parameters
csvPointer to CSV.
nrNr of field items to add to the list.

Definition at line 58 of file csv.c.

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}
int col
Definition tpccsv.h:28
int row
Definition tpccsv.h:26
char * content
Definition tpccsv.h:30
CSV_item * c
Definition tpccsv.h:38
int nr
Definition tpccsv.h:42
int _item_nr
Definition tpccsv.h:40
@ TPCERROR_FAIL
General error.
@ TPCERROR_OUT_OF_MEMORY
Cannot allocate memory.
@ TPCERROR_OK
No error.

Referenced by csvDuplicate(), csvPutString(), parWriteCSV(), and tacWriteCSV().

◆ csvCell()

char * csvCell ( CSV * csv,
int row,
int col )

Get the CVS field contents in specified row and column.

Returns
Returns pointer to the content string, or NULL if not found.
Author
Vesa Oikonen
See also
csvRead, csvSearchField, csvFindField, csvCellReplace, csvSetDimensions
Parameters
csvPointer to CSV.
rowCSV row index.
colCSV column index.

Definition at line 358 of file csv.c.

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}

Referenced by csvDuplicate(), csvRemoveEmptyRows(), csvWrite(), parReadFIT(), parReadRES(), tacRead(), tacReadCarimasTxt(), tacReadInveonCSV(), tacReadMat(), tacReadQView(), tacReadSIF(), and tacReadSimple().

◆ csvCellReplace()

int csvCellReplace ( CSV * csv,
int row,
int col,
const char * s )

Replace the value of CVS field.

Returns
tpcerror (TPCERROR_OK when successful).
Author
Vesa Oikonen
See also
csvRead, csvSearchField, csvCell, csvRemoveItem, csvTranspose
Parameters
csvPointer to CSV.
rowCSV row index.
colCSV column index.
sField string to add; can be empty ("" or NULL).

Definition at line 380 of file csv.c.

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}
char * strdup(const char *s)
Definition stringext.c:185
@ TPCERROR_MISSING_DATA
File contains missing values.

◆ csvCleanSpaces()

int csvCleanSpaces ( CSV * csv)

Removes any initial and trailing space characters from CSV. Space characters in the middle of the string are not removed.

Returns
tpcerror (TPCERROR_OK when successful).
Author
Vesa Oikonen
See also
csvRemoveEmptyLines, csvRead, strCleanSpaces
Parameters
csvPointer to CSV, the content of which is to be cleaned.

Definition at line 422 of file csvio.c.

425 {
426 if(csv==NULL) return TPCERROR_FAIL;
427 for(int i=0; i<csv->nr; i++) strCleanSpaces(csv->c[i].content);
428 return(TPCERROR_OK);
429}
int strCleanSpaces(char *s)
Definition stringext.c:300

Referenced by parReadCSV().

◆ csvDuplicate()

int csvDuplicate ( CSV * csv1,
CSV * csv2 )

Make a duplicate of CSV structure.

Previous contents are copied. In the duplicate the space is allocated for row_nr times col_nr cells.

See also
csvInit, csvAllocate, csvFree
Returns
Returns TPCERROR status (0 when successful).
Parameters
csv1Pointer to the source CSV.
csv2Pointer to the target CSV; must be initiated; any old contents are deleted.

Definition at line 102 of file csv.c.

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}
char * csvCell(CSV *csv, int row, int col)
Definition csv.c:358
int csvAllocate(CSV *csv, int nr)
Definition csv.c:58
void csvFree(CSV *csv)
Definition csv.c:38
int row_nr
Definition tpccsv.h:44
int col_nr
Definition tpccsv.h:46
char separator
Definition tpccsv.h:49
@ TPCERROR_NO_DATA
File contains no data.

◆ csvFindField()

int csvFindField ( CSV * csv,
const char * s,
int start_index )

Find the CSV field with specified content. Search is case-insensitive, but otherwise match must be exact.

See also
csvSearchField, csvCell, csvRead, csvRemoveItem
Returns
field index, or <0 if not found.
Author
Vesa Oikonen
Parameters
csvPointer to CSV.
sField value to be searched for.
start_indexCSV item index [0..nr-1] from which search is started.

Definition at line 27 of file csvfind.c.

34 {
35 if(csv==NULL || s==NULL) return -2;
36 if(start_index<0 || start_index>=csv->nr) return -2;
37 for(int i=start_index; i<csv->nr; i++) if(csv->c[i].content!=NULL)
38 if(strcasecmp(csv->c[i].content, s)==0) return i;
39 return -1;
40}

Referenced by parReadRES(), and tacRead4DM().

◆ csvFree()

void csvFree ( CSV * csv)

Free memory allocated for CSV data. All contents are destroyed.

Precondition
Before first use initialize the CSV struct with csvInit().
Author
Vesa Oikonen
See also
csvInit, csvAllocate, csvWrite
Parameters
csvPointer to CSV.

Definition at line 38 of file csv.c.

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}
void csvInit(CSV *csv)
Definition csv.c:22

Referenced by csvDuplicate(), parRead(), parWriteCSV(), tacRead(), and tacWriteCSV().

◆ csvInit()

void csvInit ( CSV * csv)

Initiate the CSV struct before any use.

Author
Vesa Oikonen
See also
csvFree, csvAllocate, csvRead
Parameters
csvPointer to CSV.

Definition at line 22 of file csv.c.

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}

Referenced by csvFree(), parRead(), parWriteCSV(), tacFormatDetermine(), tacRead(), and tacWriteCSV().

◆ csvIsRegular()

int csvIsRegular ( CSV * csv)

Check whether CSV is regular, that is, each row contain the same number of columns.

Author
Vesa Oikonen
See also
csvTranspose, csvTrimRight, csvSetDimensions, csvRowLength, csvRead, csvDuplicate
Returns
Returns 1 if CSV is regular, 0 if not.
Parameters
csvPointer to CSV

Definition at line 292 of file csv.c.

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}

Referenced by tacRead(), tacReadMat(), and tacReadSimple().

◆ csvList()

int csvList ( CSV * csv,
FILE * fp )

Write CSV data as a tab separated list into file opened for writing. List contains the cell rows, columns, and values.

Data is not sorted, and cell contents are written as they are, that is, no conversions for decimal separator is done here.

Returns
enum tpcerror (TPCERROR_OK when successful).
Author
Vesa Oikonen
See also
csvWrite, csvSetDimensions, csvTrimRight
Parameters
csvPointer to CSV structure, contents of which are to be written.
fpOutput file pointer; usually stdout.

Definition at line 27 of file csvio.c.

32 {
33 if(fp==NULL) return TPCERROR_CANNOT_WRITE;
34 if(csv==NULL || csv->nr<1) return TPCERROR_NO_DATA;
35
36 for(int i=0; i<csv->nr; i++)
37 if(fprintf(fp, "%d\t%d\t%s\n", 1+csv->c[i].row, 1+csv->c[i].col, csv->c[i].content)<5)
39
40 return(TPCERROR_OK);
41}
@ TPCERROR_CANNOT_WRITE
Cannot write file.

Referenced by tacReadSIF().

◆ csvPutDouble()

int csvPutDouble ( CSV * csv,
double v,
int newline,
int tointl )

Add specified double value as string into CSV.

Returns
tpcerror (TPCERROR_OK when successful).
Precondition
Before first use initialize the CSV struct with csvInit().
Author
Vesa Oikonen
See also
csvInit, csvPutString, csvPutInt, csvPutLine
Parameters
csvPointer to initiated CSV; previous contents are not changed.
vDouble value to add; NaN is added as an empty field.
newlineNew line (1) or same line (0).
tointlConvert (1) or do not convert (0) commas to semicolons and dots to commas.

Definition at line 193 of file csv.c.

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}
int csvPutString(CSV *csv, const char *s, int newline)
Definition csv.c:144
void strReplaceChar(char *s, char c1, char c2)
Definition stringext.c:134

Referenced by parWriteCSV(), and tacWriteCSV().

◆ csvPutInt()

int csvPutInt ( CSV * csv,
int v,
int newline )

Add specified integer value as string into CSV.

Returns
tpcerror (TPCERROR_OK when successful).
Precondition
Before first use initialize the CSV struct with csvInit().
Author
Vesa Oikonen
See also
csvInit, csvPutDouble, csvPutString, csvPutLine
Parameters
csvPointer to initiated CSV; previous contents are not changed
vInteger value to add; use csvPutString() to add an empty field
newlineNew line (1) or same line (0)

Definition at line 222 of file csv.c.

229 {
230 int ret;
231 char s[128];
232 sprintf(s, "%d", v);
233 ret=csvPutString(csv, s, newline);
234 return ret;
235}

Referenced by parWriteCSV().

◆ csvPutLine()

int csvPutLine ( CSV * csv,
const char * line,
TPCSTATUS * status )

Process a given text line (string) to add a new row of fields to CSV, using as field delimiter the character specified in CSV structure.

Returns
tpcerror (TPCERROR_OK when successful).
Precondition
Before first use initialize the CSV structure with csvInit().
Postcondition
Remember to free the memory in CSV after last use with csvFree().
Author
Vesa Oikonen
See also
csvInit, csvFree, csvWrite, csvPutString, csvPutInt, csvPutLineWithSpaces
Parameters
csvPointer to initiated CSV; previous contents are not changed.
linePointer to the CSV file line to be processed.
statusPointer to status data; enter NULL if not needed.

Definition at line 251 of file csvio.c.

258 {
259 if(csv==NULL) return TPCERROR_FAIL;
260 if(line==NULL || strlen(line)<1) {
261 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
262 return TPCERROR_NO_DATA;
263 }
264 int verbose=0; if(status!=NULL) verbose=status->verbose;
265 if(verbose>10) printf("%s():\n", __func__);
266 if(verbose>12) printf("'%s'\n", line);
267
268 //size_t len=strlen(line);
269 char delimiter=csv->separator;
270
271 /* Space is not supported here */
272 if(delimiter==' ') {
273 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_SEPARATOR);
275 }
276
277 int ret, i, last_was_delim=0;
278 int field_nr=0;
279 char *cptr=(char*)line, *lptr, *s;
280 /* If the first character is delimiter, we have had an empty field */
281 if(*cptr==delimiter) {
282 if(verbose>20) printf("first char is delimiter.\n");
283 ret=csvPutString(csv, "", !field_nr); if(ret!=TPCERROR_OK) {
284 statusSet(status, __func__, __FILE__, __LINE__, ret);
285 return ret;
286 }
287 last_was_delim=1; cptr++; field_nr++;
288 }
289 /* Read all fields */
290 int single_quotation=0;
291 int double_quotation=0;
292 lptr=cptr;
293 while(*cptr && *lptr) {
294 if(verbose>20) printf("cptr='%s'\n", cptr);
295 /* Read next field */
296 lptr=cptr; i=0;
297 while(*lptr) {
298 // jump over quoted sequences
299 if(*lptr=='\'') {
300 if(single_quotation==0 && strchr(lptr+1, '\'')!=NULL) single_quotation=1;
301 else single_quotation=0;
302 lptr++; i++; continue;
303 }
304 if(*lptr=='\"') {
305 if(double_quotation==0 && strchr(lptr+1, '\"')!=NULL) double_quotation=1;
306 else double_quotation=0;
307 lptr++; i++; continue;
308 }
309 if(single_quotation==1 || double_quotation==1) {lptr++; i++; continue;}
310 // if this character is the delimiter, then stop
311 if(*lptr==delimiter) break;
312 // otherwise continue search
313 lptr++; i++;
314 }
315 s=strndup(cptr, i);
316 if(verbose>20) printf(" s='%s'\n", s);
317 ret=csvPutString(csv, s, !field_nr); if(ret!=TPCERROR_OK) {
318 statusSet(status, __func__, __FILE__, __LINE__, ret);
319 free(s); return ret;
320 }
321 free(s); field_nr++;
322 if(*lptr==delimiter) {
323 last_was_delim=1; cptr+=(i+1);
324 } else {last_was_delim=0; cptr+=(i+1);}
325 }
326 if(verbose>20) printf("line finished.\n");
327 /* If the last character is delimiter, we have an empty field in the end */
328 if(last_was_delim) {
329 if(verbose>20) printf("last char is delimiter.\n");
330 ret=csvPutString(csv, "", !field_nr); if(ret!=TPCERROR_OK) {
331 statusSet(status, __func__, __FILE__, __LINE__, ret);
332 return ret;
333 }
334 field_nr++;
335 }
336 if(verbose>20) printf("ending %s()\n", __func__);
337 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
338 return(TPCERROR_OK);
339}
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
char * strndup(const char *s, size_t n)
Definition stringext.c:205
int verbose
Verbose level, used by statusPrint() etc.
@ TPCERROR_INVALID_SEPARATOR
Invalid field delimiter.

Referenced by csvRead().

◆ csvPutLineWithSpaces()

int csvPutLineWithSpaces ( CSV * csv,
const char * line,
TPCSTATUS * status )

Process a given text line (string) to add a new row of fields to CSV, using spaces as field delimiters, independent on what is told in CSV struct.

Returns
tpcerror (TPCERROR_OK when successful).
Precondition
Before first use initialize the CSV struct with csvInit().
Postcondition
Remember to free the memory in CSV after last use with csvFree().
Author
Vesa Oikonen
See also
csvPutLine, csvRemoveEmptyLines, csvRead
Parameters
csvPointer to initiated CSV; previous contents are not changed.
linePointer to the CSV file line to be processed.
statusPointer to status data; enter NULL if not needed.

Definition at line 351 of file csvio.c.

358 {
359 if(csv==NULL) return TPCERROR_FAIL;
360 if(line==NULL || strlen(line)<1) {
361 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
362 return TPCERROR_NO_DATA;
363 }
364 int verbose=0; if(status!=NULL) verbose=status->verbose;
365 if(verbose>10) printf("%s():\n", __func__);
366 if(verbose>12) printf("'%s'\n", line);
367
368 char *cptr=(char*)line;
369 char *lptr=cptr, *s;
370 int single_quotation=0;
371 int double_quotation=0;
372 int ret;
373 size_t j;
374 int field_nr=0;
375 while(*cptr && *lptr) {
376 if(verbose>20) printf("cptr='%s'\n", cptr);
377 // Pass the spaces
378 j=strspn(cptr, " \t\n\r"); cptr+=j; if(!cptr) break;
379 // Find the end of token
380 lptr=cptr; j=0;
381 while(*lptr) {
382 // jump over quoted sequences */
383 if(*lptr=='\'') {
384 if(single_quotation==0 && strchr(lptr+1, '\'')!=NULL) single_quotation=1;
385 else single_quotation=0;
386 lptr++; j++; continue;
387 }
388 if(*lptr=='\"') {
389 if(double_quotation==0 && strchr(lptr+1, '\"')!=NULL) double_quotation=1;
390 else double_quotation=0;
391 lptr++; j++; continue;
392 }
393 if(single_quotation==1 || double_quotation==1) {lptr++; j++; continue;}
394 // if this character is the delimiter, then stop
395 if(*lptr==' ') break;
396 // otherwise continue search
397 lptr++; j++;
398 }
399 if(j==0) break;
400 s=strndup(cptr, j);
401 if(verbose>20) printf(" s='%s'\n", s);
402 ret=csvPutString(csv, s, !field_nr); if(ret!=TPCERROR_OK) {
403 statusSet(status, __func__, __FILE__, __LINE__, ret);
404 free(s); return ret;
405 }
406 free(s); cptr+=j; field_nr++;
407 if(verbose>20) printf(" csv.nr=%d\n", csv->nr);
408 }
409
410 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
411 return(TPCERROR_OK);
412}

Referenced by csvRead().

◆ csvPutString()

int csvPutString ( CSV * csv,
const char * s,
int newline )

Add specified string to CSV.

Returns
tpcerror (TPCERROR_OK when successful).
Precondition
Before first use initialize the CSV struct with csvInit().
Author
Vesa Oikonen
See also
csvInit, csvPutDouble, csvPutInt, csvPutLine
Parameters
csvPointer to initiated CSV; previous contents are not changed.
sField string to add; can be empty ("" or NULL).
newlineNew line (1) or same line (0).

Definition at line 144 of file csv.c.

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}

Referenced by csvPutDouble(), csvPutInt(), csvPutLine(), csvPutLineWithSpaces(), parWriteCSV(), tacReadSIF(), and tacWriteCSV().

◆ csvRead()

int csvRead ( CSV * csv,
FILE * fp,
TPCSTATUS * status )

Read CSV file contents into CSV structure, allocating memory as needed.

Lines consisting only of space characters, including tabs, are not read. Partial support for spaces as delimiters.

Returns
enum tpcerror (TPCERROR_OK when successful).
Precondition
Before first use initialize the CSV structure with csvInit().
Postcondition
After last use free memory in the CSV structure with csvFree().
Bug
File is assumed to be relatively well-formatted. Specifically, both tabs and spaces must not be used as field delimiters inside one file.
Author
Vesa Oikonen
See also
csvInit, csvFree, csvWrite, csvSearchField, csvCell, csvCellReplace, csvIsRegular
Parameters
csvPointer to CSV to read into; any previous contents of CSV are preserved.
fpInput file pointer.
statusPointer to status data; enter NULL if not needed.

Definition at line 124 of file csvio.c.

131 {
132 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
133 if(csv==NULL || fp==NULL) return TPCERROR_FAIL;
134 int verbose=0; if(status!=NULL) verbose=status->verbose;
135 if(verbose>10) printf("%s()\n", __func__);
136
137 /* Get the size of the ASCII part of the file */
138 size_t fsize=asciiFileSize(fp, NULL);
139 if(verbose>11) printf(" ASCII size := %d\n", (int)fsize);
140 /* If ASCII part is too small, then lets consider that an error */
141 if(fsize<1) {
142 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
143 return TPCERROR_NO_DATA;
144 }
145 /* If ASCII part is too large, then lets consider that an error */
146 if(fsize>50000000) {
147 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_TOO_BIG);
148 return TPCERROR_TOO_BIG;
149 }
150 /* Read that to a string */
151 rewind(fp);
152 char *data;
153 data=asciiFileRead(fp, NULL, fsize+1); rewind(fp);
154 if(data==NULL) {
155 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
156 return TPCERROR_NO_DATA;
157 }
158 if(verbose>20) printf(" ASCII file read\n");
159
160 /* Read one line at a time from the string and determine the field and decimal separators */
161 int i=0, j;
162 int tab_nr=0, sem_nr=0, com_nr=0, dot_nr=0, spa_nr=0;
163 char *cptr, *line, *lptr;
164 cptr=data;
165 while((line=strTokenDup(cptr, "\n\r", &j))!=NULL) {
166 if(verbose>80) printf("line='%s'\n", line);
167 /* If line starts with '#' then jump over it */
168 if(line[0]=='#') {free(line); cptr+=j; continue;}
169 /* If line contains only space characters then jump over it */
170 if(strIsSpaceOnly(line)) {free(line); cptr+=j; continue;}
171 /* Compute the nr of dots, commas etc outside quotes */
172 lptr=line; while((lptr=strstrNoQuotation(lptr, "\t"))!=NULL) {tab_nr++;lptr++;}
173 lptr=line; while((lptr=strstrNoQuotation(lptr, ";"))!=NULL) {sem_nr++; lptr++;}
174 lptr=line; while((lptr=strstrNoQuotation(lptr, ","))!=NULL) {com_nr++; lptr++;}
175 lptr=line; while((lptr=strstrNoQuotation(lptr, "."))!=NULL) {dot_nr++; lptr++;}
176 lptr=line; while((lptr=strstrNoQuotation(lptr, " "))!=NULL) {spa_nr++; lptr++;}
177 free(line); cptr+=j; i++;
178 }
179 if(verbose>10) {
180 printf("dataline_nr := %d\n", i);
181 printf("semicolon_nr := %d\n", sem_nr);
182 printf("tabulator_nr := %d\n", tab_nr);
183 printf("dot_nr := %d\n", dot_nr);
184 printf("comma_nr := %d\n", com_nr);
185 printf("space_nr := %d\n", spa_nr);
186 }
187 if(sem_nr==0 && tab_nr==0 && dot_nr==0 && com_nr==0 && spa_nr==0) {
188 csv->separator='\t'; // the default
189 } else if(sem_nr>0) {
190 // If at least one semi-colon, then assume that it is the field separator
191 csv->separator=';';
192 } else if(tab_nr>0) {
193 // If at least one tab, then assume that it is the field separator
194 csv->separator='\t';
195 } else if(spa_nr==0) {
196 // If no spaces, then comma must be the field separator
197 csv->separator=',';
198 } else {
199 // Spaces exist, so is space or comma the field separator ?
200 if(com_nr==0) {
201 // No commas, thus space is probably field separator
202 csv->separator=' ';
203 } else if(dot_nr>0) {
204 // Dots and commas exist, probably decimal point, and comma as field separator
205 csv->separator=',';
206 } else {
207 // No dots, but commas and spaces; lets assume that the more frequent one is the field separator
208 if(com_nr>spa_nr) csv->separator=','; else csv->separator=' ';
209 }
210 }
211 if(verbose>10) {
212 if(csv->separator=='\t') printf("field_separator := tab\n");
213 else if(csv->separator==' ') printf("field_separator := space\n");
214 else printf("field_separator := %c\n", csv->separator);
215 }
216
217 /* Copy field values into CSV */
218 cptr=data; i=0; int ret;
219 while((line=strTokenDup(cptr, "\n\r", &j))!=NULL) {
220 /* If line starts with '#' then jump over it */
221 if(line[0]=='#') {free(line); cptr+=j; continue;}
222 /* If line contains only space characters then jump over it */
223 if(strIsSpaceOnly(line)) {free(line); cptr+=j; continue;}
224 /* Write contents into CSV as a new data row */
225 if(csv->separator!=' ') ret=csvPutLine(csv, line, status);
226 else ret=csvPutLineWithSpaces(csv, line, status);
227 if(verbose>1 && ret!=0) fprintf(stderr, "Warning: cannot read line %d: '%s'.\n", i, line);
228 /* Prepare for the next line */
229 free(line); cptr+=j; i++;
230 }
231 if(i==0) {
232 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
233 return TPCERROR_NO_DATA;
234 }
235
236 free(data);
237 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
238 return(TPCERROR_OK);
239}
int csvPutLineWithSpaces(CSV *csv, const char *line, TPCSTATUS *status)
Definition csvio.c:351
int csvPutLine(CSV *csv, const char *line, TPCSTATUS *status)
Definition csvio.c:251
char * asciiFileRead(FILE *fp, char *data, size_t maxlen)
size_t asciiFileSize(FILE *fp, int *nonprintable)
char * strstrNoQuotation(const char *haystack, const char *needle)
Definition stringext.c:225
int strIsSpaceOnly(char *s)
Definition stringext.c:671
char * strTokenDup(const char *s1, const char *s2, int *next)
Definition stringext.c:413
@ TPCERROR_TOO_BIG
File is too big.

Referenced by parRead(), tacFormatDetermine(), and tacRead().

◆ csvRemoveComments()

int csvRemoveComments ( CSV * csv)

Remove those cells from CSV structure whose contents start with '#'.

Returns
enum tpcerror (TPCERROR_OK when successful).
See also
csvIsRegular, csvRemoveEmptyRows
Parameters
csvPointer to CSV.

Definition at line 470 of file csv.c.

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}
int csvRemoveItem(CSV *csv, int i)
Definition csv.c:409

◆ csvRemoveEmptyRows()

int csvRemoveEmptyRows ( CSV * csv)

Remove empty rows from CSV. Rows that contain only empty cells or cells that start with '#' are considered empty.

Returns
enum tpcerror (TPCERROR_OK when successful).
See also
csvRemoveComments, csvIsRegular, csvDuplicate, csvCellReplace
Parameters
csvPointer to CSV.

Definition at line 434 of file csv.c.

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}

◆ csvRemoveItem()

int csvRemoveItem ( CSV * csv,
int i )

Remove item from CSV data structure.

Returns
enum tpcerror (TPCERROR_OK when successful).
See also
csvCellReplace, csvFree, csvDuplicate, csvRemoveEmptyRows
Parameters
csvPointer to CSV.
iIndex of item to delete.

Definition at line 409 of file csv.c.

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}

Referenced by csvRemoveComments(), csvRemoveEmptyRows(), and csvTrimRight().

◆ csvReorg()

int csvReorg ( CSV * d,
TPCSTATUS * status )

Sort CSV data array by increasing row and column numbers.

Returns
enum tpcerror (TPCERROR_OK when successful).
See also
csvTranspose, csvList, csvAllocate, csvWrite
Parameters
dPointer to CSV structure.
statusPointer to status data; enter NULL if not needed.

Definition at line 503 of file csv.c.

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}

Referenced by csvTranspose(), and tacReadSIF().

◆ csvRowLength()

int csvRowLength ( CSV * csv,
int row )

Count the nr of columns on specified CSV row.

Author
Vesa Oikonen
See also
csvCell, csvRead, csvIsRegular, csvSetDimensions
Returns
The number of columns.
Parameters
csvPointer to CSV
rowCSV row index

Definition at line 244 of file csv.c.

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}

Referenced by csvWrite(), parReadFIT(), parReadRES(), tacReadDFT(), tacReadSIF(), and tacReadSimple().

◆ csvSearchField()

int csvSearchField ( CSV * csv,
const char * s,
int start_index )

Find the CSV field which contains the given search string. Search is case-insensitive.

See also
csvFindField, csvCell, csvRead, csvRemoveItem
Returns
field index, or <0 if not found.
Author
Vesa Oikonen
Parameters
csvPointer to CSV.
sString to be searched for inside field values.
start_indexCSV field index [0..nr-1] from which search is started.

Definition at line 50 of file csvfind.c.

57 {
58 if(csv==NULL || s==NULL) return -2;
59 if(start_index<0 || start_index>=csv->nr) return -2;
60 for(int i=start_index; i<csv->nr; i++) {
61 if(csv->c[i].content==NULL || csv->c[i].content[0]=='\0') {
62 if(*s=='\0') return i; else continue;
63 }
64 if(*s=='\0') continue;
65 if(strcasestr(csv->c[i].content, s)!=NULL) return i;
66 }
67 return -1;
68}
char * strcasestr(const char *haystack, const char *needle)
Definition stringext.c:155

Referenced by parReadFIT(), and tacRead4DM().

◆ csvSetDimensions()

int csvSetDimensions ( CSV * csv)

Set the number of rows and columns in CSV table, based on the row and column stored with each cell. CSV may not be regular, thus maximum row and column numbers are used.

Author
Vesa Oikonen
See also
csvIsRegular, csvRowLength, csvRead, csvRemoveComments
Returns
enum tpcerror (TPCERROR_OK when successful).
Parameters
csvPointer to CSV structure.

Definition at line 269 of file csv.c.

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}

Referenced by csvTranspose().

◆ csvTranspose()

int csvTranspose ( CSV * csv)

Transpose data in CSV structure.

To work properly, CSV should not contain comment cells/lines.

Returns
enum tpcerror (TPCERROR_OK when successful).
See also
csvIsRegular, csvDuplicate, csvCellReplace, csvReorg, csvRmComments
Parameters
csvPointer to CSV.

Definition at line 530 of file csv.c.

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}
int csvSetDimensions(CSV *csv)
Definition csv.c:269
int csvReorg(CSV *d, TPCSTATUS *status)
Definition csv.c:503

◆ csvTrimRight()

int csvTrimRight ( CSV * csv)

Remove empty cells from the right side of CVS table until a non-empty column is reached.

Resulting CSV may still not be regular.

Author
Vesa Oikonen
See also
csvIsRegular, csvRowLength, csvRead, csvTranspose
Returns
enum tpcerror (TPCERROR_OK when successful).
Parameters
csvPointer to CSV

Definition at line 321 of file csv.c.

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}

Referenced by tacReadSimple().

◆ csvWrite()

int csvWrite ( CSV * csv,
int regular,
FILE * fp,
TPCSTATUS * status )

Write CSV data into file opened for writing, using the column separator specified inside CSV structure.

Field contents are written as they are, that is, no conversions for decimal separator is done here.

Returns
enum tpcerror (TPCERROR_OK when successful).
Author
Vesa Oikonen
See also
csvRead, csvList, csvSetDimensions, csvTrimRight
Parameters
csvPointer to CSV structure, contents of which are to be written.
regularForced regularization (1), or not (0); if regularized, then row_nr rows are written, each with col_nr columns; otherwise, empty rows are not written, and missing cells are not written to the end of rows.
fpOutput file pointer.
statusPointer to status data; enter NULL if not needed.

Definition at line 52 of file csvio.c.

63 {
64 int verbose=0; if(status!=NULL) verbose=status->verbose;
65 if(fp==NULL) {
66 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
68 }
69 if(csv==NULL || csv->nr<1) {
70 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
71 return TPCERROR_NO_DATA;
72 }
73 if(csv->separator!=',' && csv->separator!=';' && csv->separator!='\t' && csv->separator!=' ') {
74 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_SEPARATOR);
76 }
77 if(verbose>10) {
78 printf("%s():\n", __func__);
79 printf("regular := %d\n", regular);
80 printf("csv_nr := %d\n", csv->nr);
81 printf("csv_row_nr := %d\n", csv->row_nr);
82 printf("csv_col_nr := %d\n", csv->col_nr);
83 if(csv->separator=='\t') printf("csv_separator := tab\n");
84 else if(csv->separator==' ') printf("csv_separator := space\n");
85 else printf("csv_separator := '%c'\n", csv->separator);
86 }
87
88 /* Write in file */
89 int wn=0;
90 for(int ri=0; ri<csv->row_nr; ri++) {
91 int n=csv->col_nr;
92 if(regular==0) {n=csvRowLength(csv, ri); if(n==0) continue;}
93 for(int ci=0; ci<n; ci++) {
94 if(ci>0) wn+=fprintf(fp, "%c", csv->separator);
95 char *cptr=csvCell(csv, ri, ci);
96 if(cptr!=NULL) wn+=fprintf(fp, "%s", cptr);
97 }
98 wn+=fprintf(fp, "\n");
99 }
100 if(wn<1) {
101 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
103 }
104
105 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
106 return(TPCERROR_OK);
107}
int csvRowLength(CSV *csv, int row)
Definition csv.c:244

Referenced by parRead(), parReadFIT(), parReadRES(), parWriteCSV(), tacRead(), tacReadSimple(), and tacWriteCSV().