Easy-to-use CSV parsing library for C language.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

629 lines
15 KiB

#include "easycsv_p.h"
#include "easycsv_error.h"
/*** Constructors ***/
easycsv*
easycsv_init(const char *fp,
EASYCSV_MODE mode)
{
easycsv *csv = NULL;
int csv_exist = -1;
csv = malloc(sizeof(easycsv));
if (csv == NULL) {
easycsv_error(EASYCSV_MEMALLOC, NULL);
return NULL;
}
memset(csv, 0, sizeof(easycsv));
csv->mode = mode;
csv->file = NULL;
csv->temp = NULL;
strcpy(csv->fp, fp);
csv->rows = 0;
csv->cols = 0;
csv_exist = !access(csv->fp, F_OK);
/* Open file according to mode */
switch (csv->mode) {
case EASYCSV_R:
if (csv_exist) {
csv->file = fopen(csv->fp, "r");
}
else {
easycsv_error(EASYCSV_EMPTYCSV, NULL);
easycsv_free(csv);
return NULL;
}
break;
case EASYCSV_W:
if (csv_exist) {
csv->file = fopen(csv->fp, "r+");
}
else {
csv->file = fopen(csv->fp, "w");
}
break;
default:
easycsv_error(EASYCSV_UNKNOWNIOMODE, NULL);
easycsv_free(csv);
return NULL;
}
if (csv->file == NULL) {
easycsv_error(EASYCSV_OPENFAIL, NULL);
easycsv_free(csv);
return NULL;
}
/* Calculate rows and cols if file exists */
if (csv_exist) {
csv->rows = easycsv_rows(csv);
csv->cols = easycsv_columns(csv);
}
if (mode == EASYCSV_W) {
csv->temp = tmpfile();
if (csv->temp == NULL) {
easycsv_error(EASYCSV_OPENFAIL, NULL);
easycsv_free(csv);
return NULL;
}
}
return csv;
}
void
easycsv_free(easycsv *csv)
{
if (csv != NULL) {
if (csv->file != NULL) fclose(csv->file);
if (csv->temp != NULL) fclose(csv->temp);
free(csv);
}
}
/*** Acces, find ***/
int
easycsv_find_value(const easycsv* csv,
const char* value,
unsigned int* col,
unsigned int* row)
{
char *str;
const unsigned int cols = easycsv_print_columns(csv);
const unsigned int rows = easycsv_print_rows(csv);
for (unsigned int row_l = 1; row_l <= rows; row_l++) {
for (unsigned int col_l = 1; col_l <= cols; col_l++) {
str = easycsv_read_value(csv, col_l, row_l);
if (strcmp(str, value) == 0) {
*col = col_l;
*row = row_l;
free(str);
return 0;
}
free(str);
}
}
easycsv_error(EASYCSV_FINDVALUEFAIL, value);
return -1;
}
int
easycsv_find_num_value(const easycsv* csv,
const char* value)
{
char *str;
int num = 0;
const unsigned int cols = easycsv_print_columns(csv);
const unsigned int rows = easycsv_print_rows(csv);
for (unsigned int row_l = 1; row_l <= rows; row_l++) {
for (unsigned int col_l = 1; col_l < cols; col_l++) {
str = easycsv_read_value(csv, col_l, row_l);
if (strcmp(str, value) == 0) {
num++;
}
free(str);
}
}
return num;
}
/*** Acces, read ***/
char*
easycsv_read_value(const easycsv *csv,
unsigned int col,
unsigned int row)
{
char str_row[BUFSIZ];
size_t st;
char *pch, *val;
if (row == 0) {
easycsv_error(EASYCSV_ZEROROW, NULL);
return NULL;
}
if (row > easycsv_print_rows(csv)) {
easycsv_error(EASYCSV_ROWNOTEXIST, NULL);
return NULL;
}
if (col == 0) {
easycsv_error(EASYCSV_ZEROCOL, NULL);
return NULL;
}
if (col > easycsv_print_columns(csv)) {
easycsv_error(EASYCSV_COLNOTEXIST, NULL);
return NULL;
}
/* Set file pointer to start */
easycsv_rewind(csv);
for (unsigned int i = 1; i < row; i++) {
fscanf(csv->file, "%*[^\n]\n", NULL);
}
fscanf(csv->file, "%s\n", str_row);
/* Get first occurance of comma in str, the first value is ommited but not the comma */
pch = str_row;
/* Repeat until desired col is found */
for (unsigned int i = 1; i < col; i++) {
pch = strpbrk(pch + 1, ",");
}
val = malloc(BUFSIZ);
if (pch == NULL) {
st = 0;
}
else {
/* Get span from start of string to first occurence of comma */
if (col > 1) pch++;
st = strcspn(pch, ",");
// If 0, no string exists!
if (st > 0) {
strncpy(val, pch, st + 1);
}
}
val[st] = '\0';
return val;
}
/* char* */
/* easycsv_readcolumnvalue(const easycsv *csv, */
/* const char *col, */
/* const unsigned int row) */
/* { */
/* /\* ARGS CHECK *\/ */
/* if (_easycsv_checkcsvandstring_one(csv->csv, col) < 0) */
/* return NULL; */
/* if (row > csv->csv->rows) { */
/* _easycsv_printerror(csv->csv, EASYCSV_OVERMAXROW); */
/* return NULL; */
/* } */
/* /\* END ARGS CHECK *\/ */
/* int i = _easycsv_getcolumn(csv->csv, col); */
/* if (i < 1) { */
/* _easycsv_printerror(csv->csv, EASYCSV_COLNUMFAIL); */
/* return NULL; */
/* } */
/* return easycsv_readvalue(csv, i, row); */
/* } */
/*** Acces, print ***/
int
easycsv_print_rows(const easycsv *csv)
{
if (csv != NULL) {
return csv->rows;
}
else {
return -1;
}
}
int
easycsv_print_columns(const easycsv *csv)
{
if (csv != NULL) {
return csv->cols;
}
else {
return -1;
}
}
/*** Modifications, sort ***/
/*** Modifications, insert ***/
/* int */
/* easycsv_insertvalue(easycsv *csv, */
/* const char *val, */
/* const unsigned int col, */
/* const unsigned int row) */
/* { */
/* return easycsv_insertvaluemode(csv, val, col, row, EASYCSV_REPLACE); */
/* } */
/* int */
/* easycsv_insertvaluemode(easycsv *csv, */
/* const char *val, */
/* const unsigned int col, */
/* const unsigned int row, */
/* const EASYCSV_VALMODE valmode) */
/* { */
/* /\* ARGS CHECK *\/ */
/* if (_easycsv_checkcsvandstring_one(csv->csv, val) < 0) */
/* return -1; */
/* if (col == 0) { */
/* _easycsv_printerror(csv->csv, EASYCSV_ZEROCOL); */
/* return -1; */
/* } */
/* if (row == 0) { */
/* _easycsv_printerror(csv->csv, EASYCSV_ZEROROW); */
/* return -1; */
/* } */
/* /\* END ARGS CHECK *\/ */
/* /\* row extends max *\/ */
/* if (row > csv->csv->rows) { */
/* } */
/* char *rowstr = _easycsv_getrow(csv->csv, row); */
/* if (rowstr == NULL) */
/* return -1; */
/* size_t rowstrst = strlen(rowstr); */
/* size_t st = 0; */
/* size_t commas = 0; */
/* char *pch = NULL; */
/* char *newstr = NULL; */
/* /\* column is within limit *\/ */
/* if (col <= csv->csv->cols) { */
/* /\* Set pch to start of value in rowstr *\/ */
/* pch = _easycsv_setcharptovalue(csv->csv, rowstr, col); */
/* if (pch == NULL) */
/* return -1; */
/* /\* Calculate size of existing value *\/ */
/* st = strcspn(pch, ","); */
/* newstr = malloc(rowstrst - st + strlen(val) + 1); */
/* /\* Copy char to newstr before value (pch) *\/ */
/* strncpy(newstr, rowstr, pch - rowstr); */
/* /\* Insert value *\/ */
/* if (st != 0) { /\* Occupied cell *\/ */
/* switch (valmode) { */
/* case EASYCSV_CONCAT: { */
/* strncat(newstr, pch, st); */
/* strcat(newstr, val); */
/* break; */
/* } */
/* case EASYCSV_RCONCAT: { */
/* strcat(newstr, val); */
/* strncat(newstr, pch, st); */
/* break; */
/* } */
/* case EASYCSV_REPLACE: */
/* default: { */
/* strcat(newstr, val); */
/* break; */
/* } */
/* } */
/* } */
/* else { /\* Empty cell *\/ */
/* strcat(newstr, val); */
/* } */
/* /\* Set pch to after value *\/ */
/* pch = strchr(rowstr, ','); */
/* /\* Calculate length of rest of string *\/ */
/* st = strlen(pch); */
/* /\* Concentate rest of string including NULL char *\/ */
/* strcat(newstr, pch); */
/* } */
/* else { */
/* commas = col - csv->csv->cols; */
/* csv->csv->cols = col; */
/* newstr = malloc(rowstrst + commas + strlen(val) + 1); */
/* strncpy(newstr, rowstr, rowstrst); */
/* for (size_t i = 0; i < commas; i++) */
/* strncat(newstr, ",", 1); */
/* strcat(newstr, val); // append \0 */
/* } */
/* /\* UPDATE CSV *\/ */
/* char *str = NULL; */
/* /\* Row within limits *\/ */
/* if (row <= csv->csv->rows) { */
/* /\* Copy rows before newstr in csv to temp *\/ */
/* for (unsigned int i = 1; i < row; i++) { */
/* str = _easycsv_getrow(csv->csv, i); */
/* if (col > csv->csv->cols) { */
/* str = realloc(str, strlen(str) + commas + 1); */
/* for (size_t j = 0; j < commas; j++) { */
/* strncat(str, ",", 1); */
/* } */
/* } */
/* fputs(str, csv->csv->temp); */
/* free(str); */
/* } */
/* /\* Print newstr into temp *\/ */
/* fputs(newstr, csv->csv->temp); */
/* /\* Copy the rest of rows *\/ */
/* for (unsigned int i = row + 1; i <= csv->csv->rows; i++) { */
/* str = _easycsv_getrow(csv, i); */
/* if (col > csv->csv->cols) { */
/* str = realloc(str, strlen(str) + commas + 1); */
/* for (size_t j = 0; j < commas; j++) { */
/* strncat(str, ",", 1); */
/* } */
/* } */
/* fputs(str, csv->csv->temp); */
/* free(str); */
/* } */
/* } */
/* else { /\* Row exceeds limit *\/ */
/* /\* Copy entire file *\/ */
/* char buf[BUFSIZ]; */
/* size_t size; */
/* while (size = fread(buf, 1, BUFSIZ, csv->csv->file)) { */
/* fwrite(buf, 1, size, csv->csv->temp); */
/* } */
/* /\* Print out commas on rows before newstr *\/ */
/* for (size_t i = csv->csv->rows; i < row; i++) { */
/* for (size_t j = 0; j < csv->csv->cols; j++) */
/* fputc(',', csv->csv->temp); */
/* fputc('\n', csv->csv->temp); */
/* } */
/* fputs(newstr, csv->csv->temp); */
/* } */
/* /\* Update csv *\/ */
/* if (_easycsv_update(csv->csv) < 0) */
/* return -1; */
/* /\* END UPDATE CSV *\/ */
/* free(rowstr); // including pch */
/* free(newstr); */
/* return 0; */
/* } */
/* int */
/* easycsv_insertcolumnvalue(easycsv *csv, */
/* const char *col, */
/* const unsigned int row, */
/* const char *val) */
/* { */
/* return easycsv_insertcolumnvaluemode(csv, col, row, val, EASYCSV_REPLACE); */
/* } */
/* int */
/* easycsv_insertcolumnvaluemode(easycsv *csv, */
/* const char *col, */
/* const unsigned int row, */
/* const char *val, */
/* const EASYCSV_VALMODE valmode) */
/* { */
/* /\* ARGS CHECK *\/ */
/* if (_easycsv_checkcsvandstring_two(csv->csv, col, val) < 0) */
/* return -1; */
/* if (row == 0) { */
/* _easycsv_printerror(csv->csv, EASYCSV_ZEROROW); */
/* return -1; */
/* } */
/* /\* END ARGS CHECK *\/ */
/* int colnum = _easycsv_getcolumn(csv->csv, col); */
/* if (colnum < 0) { */
/* _easycsv_printerror(csv->csv, EASYCSV_COLNUMFAIL); */
/* return -1; */
/* } */
/* return easycsv_insertvaluemode(csv, val, colnum, row, valmode); */
/* } */
/*** Modifications, push ***/
/* int */
/* easycsv_pushcolumn(easycsv *csv, */
/* const char *col) */
/* { */
/* /\* ARGS CHECK *\/ */
/* if (_easycsv_checkcsvandstring_one(csv->csv, col) < 0) */
/* return -1; */
/* /\* END ARGS CHECK *\/ */
/* if (csv->mode == EASYCSV_R) { */
/* _easycsv_printerror(csv->csv, EASYCSV_UNWRITABLE); */
/* return -1; */
/* } */
/* if ((csv->mode == EASYCSV_W) && (access(csv->csv->fp, F_OK) < 0)) { */
/* /\* If the file doesn't exist, just put the col */
/* in the file *\/ */
/* if (fputs(col, csv->csv->file) < 0) { */
/* _easycsv_printerror(csv->csv, EASYCSV_PUSHCOLFAIL); */
/* return -1; */
/* } */
/* return 0; */
/* } */
/* /\* Grab first row *\/ */
/* char *str = _easycsv_getrow(csv->csv, 1); */
/* char *pch = NULL; */
/* size_t i; */
/* /\* Find empty column in first row *\/ */
/* for (i = 1; i < csv->csv->cols; i++) { */
/* if (strcspn(pch, ",") == 0) */
/* break; */
/* pch = strchr(str, ','); */
/* pch++; */
/* } */
/* /\* No empty columns in first row *\/ */
/* if (i == csv->csv->cols) */
/* i++; */
/* return easycsv_insertvalue(csv, col, i, 1); */
/* /\*size_t ststr = strlen(str); */
/* size_t stcol = strlen(col); */
/* realloc(str, ststr + stcol + 2); // 1 for null and 1 for comma */
/* strncat(str + ststr, ",", 1); */
/* strncat(str + ststr + 1, col, stcol); */
/* // Put str in temp file */
/* if (fputs(str, csv->csv->temp) < 0) { */
/* _easycsv_printerror(csv->csv, EASYCSV_PUSHCOLFAIL); */
/* return -1; */
/* } */
/* free(str); */
/* // Copy every row following the first into temp */
/* for (int i = 2; i <= csv->csv->rows; i++) { */
/* char *row = _easycsv_getrow(csv, i); */
/* fputs(row, csv->csv->temp); */
/* free(row); */
/* }*\/ */
/* } */
/* int */
/* easycsv_pushcolumnvalue(easycsv *csv, */
/* const char *col, */
/* const char *val) */
/* { */
/* /\* ARGS CHECK *\/ */
/* if (_easycsv_checkcsvandstring_two(csv->csv, col, val) < 0) */
/* return -1; */
/* /\* ARGS CHECK *\/ */
/* int colnum = _easycsv_getcolumn(csv->csv, col); */
/* if (colnum < 0) { */
/* _easycsv_printerror(csv->csv, EASYCSV_COLNUMFAIL); */
/* return -1; */
/* } */
/* /\* Find a free cell under col within csv->csv->cols limits, */
/* if there is none, generate a new row *\/ */
/* unsigned int row; */
/* EASYCSV_ERRORMSG temp_error = csv->csv->error; */
/* csv->csv->error = EASYCSV_ERROROFF; */
/* for (row = 2; row <= csv->csv->cols; row++) */
/* if (easycsv_readvalue(csv, colnum, row) != NULL) */
/* break; */
/* csv->csv->error = temp_error; */
/* /\* All rows are filled, generate new row *\/ */
/* if (row > csv->csv->cols) */
/* csv->csv->rows++; */
/* /\* ROW WILL NOT BE GENERATED \\ row < csv->csv->rows *\/ */
/* return easycsv_insertvalue(csv, val, colnum, row); */
/* } */
/*** Modifications, delete ***/
/* int */
/* easycsv_deletevalue(easycsv *csv, */
/* const unsigned int col, */
/* const unsigned int row) */
/* { */
/* return easycsv_insertvalue(csv, "", col, row); */
/* } */
/* int */
/* easycsv_deletecolumnint(easycsv *csv, */
/* const unsigned int col) */
/* { */
/* /\* ARGS CHECK *\/ */
/* if (csv == NULL) { */
/* _easycsv_printerror(csv->csv, EASYCSV_NULLCSV); */
/* return -1; */
/* } */
/* if (col == 0) { */
/* _easycsv_printerror(csv->csv, EASYCSV_ZEROCOL); */
/* return -1; */
/* } */
/* if (col > csv->csv->cols) { */
/* _easycsv_printerror(csv->csv, EASYCSV_OVERMAXCOL); */
/* return -1; */
/* } */
/* /\* END ARGS CHECK *\/ */
/* for (unsigned int i = 1; i <= csv->csv->cols; i++) { */
/* if (easycsv_readvalue(csv, col, i) == NULL) */
/* break; */
/* if (easycsv_deletevalue(csv, col, i) < 0) */
/* return -1; */
/* } */
/* return 0; */
/* } */
/* int */
/* easycsv_deletecolumnstr(easycsv *csv, */
/* const char *col) */
/* { */
/* /\* ARGS CHECK *\/ */
/* if (_easycsv_checkcsvandstring_one(csv->csv, col) < 0) */
/* return -1; */
/* /\* END ARGS CHECK *\/ */
/* int colnum = _easycsv_getcolumn(csv->csv, col); */
/* if (colnum < 0) */
/* return -1; */
/* return easycsv_deletecolumnint(csv, colnum); */
/* } */
/* int */
/* easycsV_deleterowint(easycsv *csv, */
/* const unsigned int row) */
/* { */
/* return 0; */
/* } */