#include "_easycsv.h" #include "../include/easycsv.h" // typedef struct _easycsv _easycsv; // _easycsv* _easycsv_priv_init(const char *fp, const EASYCSV_MODE mode, const EASYCSV_ERRORMSG error); /* CONSTRUCTORS AND DESTRUCTORS */ /* (Constructor) Initialise easycsv */ easycsv* easycsv_init(const char *fp, const EASYCSV_MODE mode) { return easycsv_init_errormsg(fp, mode, EASYCSV_ERRORSTDERR); } /* (Constructor) Initialise easycsv with error message option */ easycsv* easycsv_init_errormsg(const char *fp, const EASYCSV_MODE mode, const EASYCSV_ERRORMSG error) { #ifdef EASYCSV_DEBUG csv->start = clock(); #endif easycsv *csv = malloc(sizeof(easycsv)); csv->mode = mode; csv->_priv = _easycsv_priv_init(fp, mode, error); if (csv->_priv == NULL) { easycsv_free(csv); return NULL; } return csv; } /* (Destructor) Free easycsv memory */ void easycsv_free(easycsv *csv) { /* ARGS CHECK */ if (csv == NULL) return; /* END ARGS CHECK */ _easycsv_priv_free(csv->_priv); free(csv); } /* GENERIC ALGORITHMS */ /* READ VALUE */ char* easycsv_readvalue(const easycsv *csv, const unsigned int col, const unsigned int row) { /* ARGS CHECK */ if (row == 0) { _easycsv_printerror(csv->_priv, EASYCSV_ZEROROW); _easycsv_printerror(csv->_priv, EASYCSV_READVALUEFAIL); return NULL; } if (col == 0) { _easycsv_printerror(csv->_priv, EASYCSV_ZEROCOL); _easycsv_printerror(csv->_priv, EASYCSV_READVALUEFAIL); return NULL; } /* END ARGS CHECK */ char *str = _easycsv_getrow(csv->_priv, row); if (str == NULL) { _easycsv_printerror(csv->_priv, EASYCSV_ROWNOTEXIST); _easycsv_printerror(csv->_priv, EASYCSV_READVALUEFAIL); return NULL; } char *val = _easycsv_getvalueinrow(csv->_priv, str, col); if (val == NULL) { _easycsv_printerror(csv->_priv, EASYCSV_READVALUEFAIL); return NULL; } return val; } char* easycsv_readcolumnvalue(const easycsv *csv, const char *col, const unsigned int row) { /* ARGS CHECK */ if (_easycsv_checkcsvandstring_one(csv->_priv, col) < 0) return NULL; if (row > csv->_priv->rows) { _easycsv_printerror(csv->_priv, EASYCSV_OVERMAXROW); return NULL; } /* END ARGS CHECK */ int i = _easycsv_getcolumn(csv->_priv, col); if (i < 1) { _easycsv_printerror(csv->_priv, EASYCSV_COLNUMFAIL); return NULL; } return easycsv_readvalue(csv, i, row); } int easycsv_printrows(const easycsv *csv) { return csv->_priv->rows; } int easycsv_printcolumns(const easycsv *csv) { return csv->_priv->cols; } /* INSERT VALUE -- AT SPECIFIC ROW AND COLUMN */ 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->_priv, val) < 0) return -1; if (col == 0) { _easycsv_printerror(csv->_priv, EASYCSV_ZEROCOL); return -1; } if (row == 0) { _easycsv_printerror(csv->_priv, EASYCSV_ZEROROW); return -1; } /* END ARGS CHECK */ /* row extends max */ if (row > csv->_priv->rows) { } char *rowstr = _easycsv_getrow(csv->_priv, 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->_priv->cols) { /* Set pch to start of value in rowstr */ pch = _easycsv_setcharptovalue(csv->_priv, 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->_priv->cols; csv->_priv->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->_priv->rows) { /* Copy rows before newstr in csv to temp */ for (unsigned int i = 1; i < row; i++) { str = _easycsv_getrow(csv->_priv, i); if (col > csv->_priv->cols) { str = realloc(str, strlen(str) + commas + 1); for (size_t j = 0; j < commas; j++) { strncat(str, ",", 1); } } fputs(str, csv->_priv->temp); free(str); } /* Print newstr into temp */ fputs(newstr, csv->_priv->temp); /* Copy the rest of rows */ for (unsigned int i = row + 1; i <= csv->_priv->rows; i++) { str = _easycsv_getrow(csv, i); if (col > csv->_priv->cols) { str = realloc(str, strlen(str) + commas + 1); for (size_t j = 0; j < commas; j++) { strncat(str, ",", 1); } } fputs(str, csv->_priv->temp); free(str); } } else { /* Row exceeds limit */ /* Copy entire file */ char buf[BUFSIZ]; size_t size; while (size = fread(buf, 1, BUFSIZ, csv->_priv->file)) { fwrite(buf, 1, size, csv->_priv->temp); } /* Print out commas on rows before newstr */ for (size_t i = csv->_priv->rows; i < row; i++) { for (size_t j = 0; j < csv->_priv->cols; j++) fputc(',', csv->_priv->temp); fputc('\n', csv->_priv->temp); } fputs(newstr, csv->_priv->temp); } /* Update csv */ if (_easycsv_update(csv->_priv) < 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->_priv, col, val) < 0) return -1; if (row == 0) { _easycsv_printerror(csv->_priv, EASYCSV_ZEROROW); return -1; } /* END ARGS CHECK */ int colnum = _easycsv_getcolumn(csv->_priv, col); if (colnum < 0) { _easycsv_printerror(csv->_priv, EASYCSV_COLNUMFAIL); return -1; } return easycsv_insertvaluemode(csv, val, colnum, row, valmode); } /* PUSH VALUE */ int easycsv_pushcolumn(easycsv *csv, const char *col) { /* ARGS CHECK */ if (_easycsv_checkcsvandstring_one(csv->_priv, col) < 0) return -1; /* END ARGS CHECK */ if (csv->mode == EASYCSV_R) { _easycsv_printerror(csv->_priv, EASYCSV_UNWRITABLE); return -1; } if ((csv->mode == EASYCSV_W) && (access(csv->_priv->fp, F_OK) < 0)) { /* If the file doesn't exist, just put the col in the file */ if (fputs(col, csv->_priv->file) < 0) { _easycsv_printerror(csv->_priv, EASYCSV_PUSHCOLFAIL); return -1; } return 0; } /* Grab first row */ char *str = _easycsv_getrow(csv->_priv, 1); char *pch = NULL; size_t i; /* Find empty column in first row */ for (i = 1; i < csv->_priv->cols; i++) { if (strcspn(pch, ",") == 0) break; pch = strchr(str, ','); pch++; } /* No empty columns in first row */ if (i == csv->_priv->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->_priv->temp) < 0) { _easycsv_printerror(csv->_priv, EASYCSV_PUSHCOLFAIL); return -1; } free(str); // Copy every row following the first into temp for (int i = 2; i <= csv->_priv->rows; i++) { char *row = _easycsv_getrow(csv, i); fputs(row, csv->_priv->temp); free(row); }*/ } int easycsv_pushcolumnvalue(easycsv *csv, const char *col, const char *val) { /* ARGS CHECK */ if (_easycsv_checkcsvandstring_two(csv->_priv, col, val) < 0) return -1; /* ARGS CHECK */ int colnum = _easycsv_getcolumn(csv->_priv, col); if (colnum < 0) { _easycsv_printerror(csv->_priv, EASYCSV_COLNUMFAIL); return -1; } /* Find a free cell under col within csv->_priv->cols limits, if there is none, generate a new row */ unsigned int row; EASYCSV_ERRORMSG temp_error = csv->_priv->error; csv->_priv->error = EASYCSV_ERROROFF; for (row = 2; row <= csv->_priv->cols; row++) if (easycsv_readvalue(csv, colnum, row) != NULL) break; csv->_priv->error = temp_error; /* All rows are filled, generate new row */ if (row > csv->_priv->cols) csv->_priv->rows++; /* ROW WILL NOT BE GENERATED \\ row < csv->_priv->rows */ return easycsv_insertvalue(csv, val, colnum, row); } /* DELETE VALUES */ 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->_priv, EASYCSV_NULLCSV); return -1; } if (col == 0) { _easycsv_printerror(csv->_priv, EASYCSV_ZEROCOL); return -1; } if (col > csv->_priv->cols) { _easycsv_printerror(csv->_priv, EASYCSV_OVERMAXCOL); return -1; } /* END ARGS CHECK */ for (unsigned int i = 1; i <= csv->_priv->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->_priv, col) < 0) return -1; /* END ARGS CHECK */ int colnum = _easycsv_getcolumn(csv->_priv, col); if (colnum < 0) return -1; return easycsv_deletecolumnint(csv, colnum); } int easycsV_deleterowint(easycsv *csv, const unsigned int row) { return 0; }