diff --git a/include/easycsv.h b/include/easycsv.h index f5d4d2c..fc32a0a 100644 --- a/include/easycsv.h +++ b/include/easycsv.h @@ -1,132 +1,145 @@ #ifndef EASYCSV_H #define EASYCSV_H -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Flags for error messages */ -typedef enum { - EASYCSV_ERRORSTDERR = 0, // default - EASYCSV_ERROROFF, - EASYCSV_ERRORSTDOUT -} EASYCSV_ERRORMSG; - -/* Flags to facilitate changing modes during file copying phases */ -typedef enum { - EASYCSV_UNKNOWNMODE = 0, - EASYCSV_R, - EASYCSV_W -} EASYCSV_MODE; - -/* Flags to parameterise the easycsv_insertvalue */ -typedef enum { - EASYCSV_REPLACE, /* (Default) Replaces word */ - EASYCSV_CONCAT, /* Concantates word at the end */ - EASYCSV_RCONCAT, /* Concantates word from the start */ -} EASYCSV_VALMODE; - -typedef enum { - EASYCSV_ALPHA, /* sort alphabetically */ - EASYCSV_RALPHA, /* sort reverse alphabetically */ - EASYCSV_NUMER, /* sort numerically, from lowest value to highest */ - EASYCSV_RNUMER /* sort from highest value to lowest */ -} EASYCSV_SORT; +#include "../src/_easycsv.h" typedef struct _easycsv _easycsv; -/* Public easycsv members */ +/** Public easycsv members */ typedef struct easycsv { - EASYCSV_MODE mode; // end users able to easily modify mode to their needs - _easycsv *_priv; // private members + EASYCSV_MODE mode; + _easycsv *_priv; } easycsv; -/* - * ============================ - * FUNCTION PROTOTYPES - PUBLIC - * ============================ +/*** Constructors ***/ + +/** + * Initialise easycsv + * @param[in] relative path to CSV file + * @param[in] easycsv mode + * @return pointer to easycsv structure */ - -/* CONSTRUCTORS AND DESTRUCTORS */ - -/* (Constructor) Initialise easycsv */ easycsv* easycsv_init(const char*, const EASYCSV_MODE); -/* (Constructor) Initialise easycsv with error message option */ +/** + * Initialise easycsv structure with a given error message mode + * @param[in] relative path to CSV file + * @param[in] easycsv mode + * @param[in] easycsv error message mode + * @return pointer to easycsv structure + */ easycsv* easycsv_init_errormsg(const char*, const EASYCSV_MODE, const EASYCSV_ERRORMSG); -/* (Destructor) Free easycsv memory */ +/** + * Destroy easycsv structure + * @param[in] Pointer to easycsv stucture + */ void easycsv_free(easycsv*); -/* GENERIC ALGORITHMS */ +/*** Access ***/ -/* Find value and returns row and column in unsigned int pointers */ +/** + * Find value and returns row and column + * @param[in] constant pointer to easycsv structure + * @param[in] value to find + * @param[out] row number + * @param[out] column number + * @return easycsv error code + */ int easycsv_findvalue(const easycsv*, const char*, unsigned int*, unsigned int*); -/* Find number of instances of value */ +/** + * Find number of instances of value + * @param[in] constant pointer to easycsv structure + * @param[in] value to find + * @return number of instances + */ int easycsv_findnumvalue(const easycsv*, const char*); +/** + * Read string in a specific cell + * @param[in] constant pointer to easycsv structure + * @param[in] row number + * @param[in] column number + * @return string value of cell, NULL if empty cell + */ +char* +easycsv_readvalue(const easycsv*, + unsigned int, + unsigned int); + +/** + * Read string in a specific cell with named column in row 1 + * @param[in] constant pointer to easycsv structure + * @param[in] row value + * @param[in] column number + * @return string value of cell, NULL if empty cell + */ +char* +easycsv_readcolumnvalue(const easycsv*, + const char*, + unsigned int); + +/** + * Return number of rows + * @param[in] constant pointer to easycsv structure + * @return number of rows + */ +int +easycsv_printrows(const easycsv*); + +/** + * Return number of columns + * @param[in] constant pointer to easycsv structure + * @return number of columns + */ +int +easycsv_printcolumns(const easycsv*); + +/*** Modifications, sort ***/ + +/** + * Sort row + * @param[in] pointer to easycsv structure + * @param[in] row value + * @param[in] easycsv sort mode + * @return easycsv error code + */ int easycsv_sortrow(easycsv*, const char*, const EASYCSV_SORT); +/** + * Sort column + * @param[in] pointer to easycsv structure + * @param[in] column value + * @param[in] easycsv sort mode + * @return easycsv error code + */ int easycsv_sortcolumn(easycsv*, const char*, const EASYCSV_SORT); -/* Append to CSV files */ -int -easycsv_appendcsv(easycsv*, - easycsv*); +/*** Modifications, insert ***/ int -easycsv_compress(easycsv*); - -/* READ VALUE */ - -/* Read string in a specific cell */ -char* -easycsv_readvalue(const easycsv*, - const unsigned int, - const unsigned int); - -/* Read string in a specific cell with named column in row 1 */ -char* -easycsv_readcolumnvalue(const easycsv*, - const char*, - const unsigned int); - -/* Number of rows in entire CSV file */ -int -easycsv_printrows(const easycsv*); - -/* Number of columns in entire CSV file */ -int -easycsv_printcolumns(const easycsv*); - -/* INSERT VALUE -- AT SPECIFIC ROW AND COLUMN */ - -// int easycsv_insertrow(struct easycsv*, const char*, const int); +easycsv_insertrow(easycsv*, + const char*, + const int); /* Insert string in a specific cell */ int @@ -158,7 +171,7 @@ easycsv_insertcolumnvaluemode(easycsv*, const char*, const EASYCSV_VALMODE); -/* PUSH VALUE */ +/* Modifications, push */ /* Create new column on the RHS of an existing one */ int @@ -171,7 +184,7 @@ easycsv_pushcolumnvalue(easycsv*, const char*, const char*); -/* DELETE VALUES -- use INSERT VALUE with empty string*/ +/* Modifications, delete */ /* Delete CSV value */ int @@ -193,4 +206,16 @@ easycsv_deletecolumnstr(easycsv*, /* Delete named row */ + + +/* Modifications, append */ +int +easycsv_appendcsv(easycsv*, + easycsv*); + +/*** Modifications, miscellenaeous ***/ + +int +easycsv_compress(easycsv*); + #endif /* EASYCSV_H */ diff --git a/src/Makefile.am b/src/Makefile.am index 25b3649..e7a2f0d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,6 @@ lib_LTLIBRARIES = libeasycsv.la -libeasycsv_la_SOURCES = easycsv.c +libeasycsv_la_SOURCES = \ + _easycsv.c \ + _easycsv.h \ + easycsv.c include_HEADERS = ../include/easycsv.h diff --git a/src/_easycsv.c b/src/_easycsv.c new file mode 100644 index 0000000..454a17e --- /dev/null +++ b/src/_easycsv.c @@ -0,0 +1,506 @@ +#include "_easycsv.h" + +/* (Constructor) Initialise _easycsv */ +_easycsv* +_easycsv_priv_init(const char *fp, + const EASYCSV_MODE mode, + const EASYCSV_ERRORMSG error) +{ + _easycsv *_priv = malloc(sizeof(_easycsv)); + + _priv->file = NULL; + _priv->temp = NULL; + _priv->fp = NULL; + _priv->tmpfp = NULL; + _priv->rows = 0; + _priv->cols = 0; +#ifdef EASYCSV_DEBUG + _priv->start = 0; +#endif + + _priv->error = error; + + /* Open file according to mode */ + switch (mode) { + case EASYCSV_R: { + _priv->file = fopen(fp, "r"); + break; + } + case EASYCSV_W: { + _priv->file = fopen(fp, "w"); + break; + } + default: { + _easycsv_printerror(_priv, EASYCSV_UNKNOWNIOMODE); + _easycsv_priv_free(_priv); + return NULL; + } + } + + if (_priv->file == NULL) + { + _easycsv_printerror(_priv, EASYCSV_OPENFAIL); + _easycsv_priv_free(_priv); + return NULL; + } + + size_t stfp = strlen(fp); + + /* Allocate memory for char* */ + _priv->fp = malloc(stfp + 1); // + 1 for null + + strcpy(_priv->fp, fp); + + /* Calculate rows and cols if file exists */ + if (access(_priv->fp, F_OK) == 0) { + _priv->rows = _easycsv_rows(_priv, mode); + _priv->cols = _easycsv_columns(_priv, mode); + } + + if (mode == EASYCSV_W) { + + /* csv->tmpfp = malloc(16 + stfp + 1); */ + /* strncpy(csv->tmpfp, prefix, 16); */ + + /* strncat(csv->tmpfp, fp, stfp); */ + + do { + /* Write to temporary file */ + unsigned int i = 1; + char buffer[21] = "/tmp/easycsv-"; // 13 char, 3 for digits, 4 for .csv, 1 for NULL + + if (i < 100) + strncat(buffer, "0", 1); + + if (i < 10) + strncat(buffer, "0", 1); + + sprintf(buffer + strlen(buffer), "%i", i); + strcat(buffer, ".csv"); + + if (access(buffer, F_OK) < 0) { + i++; + } + else { + _priv->tmpfp = malloc(21); + strncpy(_priv->tmpfp, buffer, 21); + break; + } + + } while (1); + + _priv->temp = fopen(_priv->tmpfp, "w"); + if (_priv->temp == NULL) { + _easycsv_printerror(_priv, EASYCSV_OPENFAIL); + _easycsv_priv_free(_priv); + return NULL; + } + /* +#ifdef EASYCSV_DEBUG + printf("[%i] easycsv_debug: temp file %s opened\n", clock() - csv->start, csv->tmpfp); + #endif*/ + /* + + if (freopen(csv->fp, csv->mode, csv->file) == NULL) { + fprintf(stderr, "easycsv: failed to set temporary file %s to %s mode\n", csv->tmpfp, csv->mode); + return NULL; + } + + if (freopen(csv->tmpfp, csv->mode, csv->temp) == NULL) { + fprintf(stderr, "easycsv: failed to set temporary file %s to %s mode\n", csv->tmpfp, csv->mode); + return NULL; + } + */ + + } + + return _priv; +} + +/* (Destructor) Free _easycsv memory */ +void +_easycsv_priv_free(_easycsv *_priv) +{ + /* ARGS CHECK */ + if (_priv == NULL) + return; + /* ARGS CHECK */ + if (_priv->file != NULL) + fclose(_priv->file); + if (_priv->temp != NULL) + fclose(_priv->temp); + if (_priv->fp != NULL) + free(_priv->fp); + if (_priv->tmpfp != NULL) + free(_priv->tmpfp); + free(_priv); +} + +int +_easycsv_update(_easycsv *csv) +{ + /* ARGS CHECK */ + if (csv == NULL) { + _easycsv_printerror(csv, EASYCSV_NULLCSV); + return -1; + } + /* ARGS CHECK */ + + /* Set temp file to read binary */ + if (freopen(csv->tmpfp, "rb", csv->temp) == NULL) { + _easycsv_printerror(csv, EASYCSV_REOPENFAIL); + easycsv_free(csv); + return -1; + } + + /* Set file to write binary */ + if (freopen(csv->fp, "wb", csv->file) == NULL) { + _easycsv_printerror(csv, EASYCSV_REOPENFAIL); + easycsv_free(csv); + return -1; + } + + /* Copy entire file */ + char buf[BUFSIZ]; + size_t size; + while (size = fread(buf, 1, BUFSIZ, csv->temp)) { + fwrite(buf, 1, size, csv->file); + } + + /* Set temp file back to write */ + if (freopen(csv->tmpfp, "w", csv->temp) == NULL) { + _easycsv_printerror(csv, EASYCSV_REOPENFAIL); + easycsv_free(csv); + return -1; + } + + /* Set file back to read */ + if (freopen(csv->fp, "r", csv->file) == NULL) { + _easycsv_printerror(csv, EASYCSV_REOPENFAIL); + easycsv_free(csv); + return -1; + } + + return 0; +} + +int +_easycsv_rows(_easycsv *_priv, + const EASYCSV_MODE mode) +{ + // no need to check _priv for NULL + + if (_easycsv_rewind(_priv, mode) < 0) + return -1; + + int rows = 1; + char c; + + /* Go through each character in the file and count the number of \n + in it */ + while ((c = fgetc(_priv->file)) != EOF) { + if (c == '\n') rows++; + } + + return rows; +} + +int +_easycsv_columns(_easycsv *_priv, + const EASYCSV_MODE mode) +{ + // no need to check _priv for NULL + + /* Prepare it for reading */ + if (_easycsv_rewind(_priv, mode) < 0) return -1; + + /* + 1. check if empty file + 2. check if only one column -> 0 commas + 3. if >1 column, n commas = n+1 columns + */ + + int col = 1; + char c; + + while ((c = fgetc(_priv->file)) != '\n') { + if (c == ',') col++; + } + + return col; +} + +char* +_easycsv_getrow(const _easycsv *csv, + const unsigned int row) +{ + /* ARGS CHECK */ + if (csv == NULL) { + _easycsv_printerror(csv, EASYCSV_NULLCSV); + return NULL; + } + + if (row > csv->rows) { + _easycsv_printerror(csv, EASYCSV_OVERMAXROW); + return NULL; + } + + if (row == 0) { + _easycsv_printerror(csv, EASYCSV_ZEROROW); + return NULL; + } + /* END ARGS CHECK */ + + /* Allocate memory */ + char *str = malloc(BUFSIZ); + + /* Set file pointer to start */ + rewind(csv->file); + + for (int i = 1; i < row; i++) + { + /* skip until row is reached */ + fscanf(csv->file, "%*[^\n]\n", NULL); + } + + /* Grab the row and store it in str */ + fscanf(csv->file, "%s\n", str); + + // printf("row: %s\n", str); + + return str; +} + +int +_easycsv_rewind(_easycsv *_priv, + const EASYCSV_MODE mode) +{ + /* Check if empty file */ + if (fscanf(_priv->file, "\n") == EOF) { + _easycsv_printerror(_priv, EASYCSV_EMPTYCSV); + return -1; + } + + /* Check if file is readable */ + if (mode != EASYCSV_R) { + _easycsv_printerror(_priv, EASYCSV_UNREADABLE); + return -1; + } + + /* Set file pointer to the start */ + rewind(_priv->file); + + return 0; +} + +int +_easycsv_getcolumn(const _easycsv *csv, + const char *col) +{ + /* ARGS CHECK */ + if (_easycsv_checkcsvandstring_one(csv, col) < 0) + return -1; + /* ARGS CHECK */ + + /* Grab str of row 1 */ + char *firstrow = _easycsv_getrow(csv, 1); + + if (firstrow == NULL) { + _easycsv_printerror(csv, EASYCSV_ROWNOTEXIST); + return -1; + } + + unsigned int commas = 0; + + // printf("FIRST COLUMN: %s\n", firstrow); + + /* Find first occurance of col in firstrow */ + char *str = strstr(firstrow, col); + + if (str == NULL) { + _easycsv_printerror(csv, EASYCSV_COLNOTEXIST); + return -1; + } + + /* Count numbers of commas following str */ + char *c = strpbrk(str, ","); + while (c != NULL) { + commas++; + c = strpbrk(c + 1, ","); + } + + /* no need to free c as it is already NULL at this point */ + // free((char*) str); apparently invalid pointer + + // printf("ROW: %i\nCOL: %i\n", row, csv->cols - commas); + /* +#ifdef EASYCSV_DEBUG + printf("[%i] rcv_commas: %i\n", clock() - csv->start, commas); +#endif + */ + free(firstrow); + + return csv->cols - commas; +} + +/* +int _easycsv_checkifvalue(struct easycsv *csv, const int col, const int row) +{ + const char *rowstr = _easycsv_getrow(csv, row); + + return 0; +} +*/ + +char* +_easycsv_getvalueinrow(const _easycsv *_priv, + const char *row, + const unsigned int col) +{ + size_t st; + char *pch = NULL; + + /* If not first column */ + if (col != 1) { + + /* Get first occurance of comma in str, + the first value is ommited but not the comma */ + char *pch = strpbrk(row, ","); + + /* Repeat until desired col is found */ + for (int i = 2; i < col; i++) { + pch = strpbrk(pch + 1, ","); + } + } + + /* Get span from start of string to first occurence + of comma */ + st = strcspn(pch + 1, ","); + + /* If 0, no string exists! */ + if (st == 0) { + _easycsv_printerror(_priv, EASYCSV_EMPTYVALUE); + return NULL; + } + + char *val = malloc(st + 1); + strncpy(val, pch + 1, st); + strncat(val, "\0", 1); + + return val; +} + +char* +_easycsv_setcharptovalue(const _easycsv *_priv, + const char *rowstr, + const unsigned int col) +{ + char *pch = rowstr; + + for (unsigned int i = 1; i < col; i++) { + pch = strchr(rowstr, ','); + if (pch == NULL) { + _easycsv_printerror(_priv, EASYCSV_NULLPTR); + return NULL; + } + pch++; + } + + return pch; +} + +void +_easycsv_printerror(const _easycsv *_priv, + const EASYCSV_ERROR error) +{ + switch (_priv->error) { + case EASYCSV_ERROROFF: return; + case EASYCSV_ERRORSTDOUT: _easycsv_geterror(_priv, error, stdout); break; + case EASYCSV_ERRORSTDERR: + default: _easycsv_geterror(_priv, error, stderr); return; + } +} + +void +_easycsv_geterror(const _easycsv *_priv, + const EASYCSV_ERROR error, + FILE *fs) +{ +#ifdef EASYCSV_DEBUG + fprintf(stderr, "[%i] ", clock() - _priv->start); +#endif + + fputs("easycsv: ", fs); + + switch (error) { + + /* Generic errors */ + case EASYCSV_NOERROR: fputs("no error", fs); break; + case EASYCSV_NULLCSV: fputs("easycsv pointer is NULL", fs); break; + case EASYCSV_NULLPTR: fputs("pointer is NULL", fs); break; + case EASYCSV_EMPTYSTRING: fputs("string is empty", fs); break; + case EASYCSV_EMPTYVALUE: fputs("value in CSV file is empty", fs); break; + case EASYCSV_OVERMAXROW: fprintf(fs, "int exceeds row limit %i", _priv->rows); break; + case EASYCSV_OVERMAXCOL: fprintf(fs, "int exceeds column limit %i", _priv->cols); break; + case EASYCSV_ZEROROW: fputs("parameterised row number is zero", fs); break; + case EASYCSV_ZEROCOL: fputs("parameterised column number is zero", fs); break; + + /* File input/output errors */ + case EASYCSV_UNKNOWNIOMODE: fputs("unknown file IO mode", fs); break; + case EASYCSV_OPENFAIL: fputs("failed to open file", fs); break; + case EASYCSV_REOPENFAIL: fputs("failed to reopen file", fs); break; + case EASYCSV_EMPTYCSV: fputs("CSV file is empty", fs); break; + case EASYCSV_UNWRITABLE: fputs("CSV file is not in a writable mode", fs); break; + case EASYCSV_UNREADABLE: fputs("CSV file is not in a readable mode", fs); break; + case EASYCSV_UPDATEFAIL: fputs("CSV file has failed to update", fs); break; + case EASYCSV_UPDATETEMPFAIL: fputs("failed to update temp CSV file", fs); break; + case EASYCSV_FILEPTRFAIL: fputs("failed to move FILE pointer", fs); break; + + /* Non-existant elements */ + case EASYCSV_ROWNOTEXIST: fputs("given row does not exist", fs); break; + case EASYCSV_COLNOTEXIST: fputs("given column does not exist", fs); break; + + /* User-facing failure */ + case EASYCSV_PUSHCOLFAIL: fputs("failed to push value under column", fs); break; + case EASYCSV_COLNUMFAIL: fputs("failed to determine the column number of a value in the first row", fs); break; + default: fputs("unknown error, easycsv* is possibly NULL", fs); break; + } + + if (_priv->fp != NULL) + fprintf(fs, " in %s", _priv->fp); + + fputc('\n', fs); +} + +int +_easycsv_checkcsvandstring_one(const _easycsv *csv, + const char *one) +{ + if (csv == NULL) { + _easycsv_printerror(csv, EASYCSV_NULLCSV); + return -1; + } + + if (one == NULL) { + _easycsv_printerror(csv, EASYCSV_EMPTYSTRING); + return -1; + } + + return 0; +} + +int +_easycsv_checkcsvandstring_two(const _easycsv *csv, + const char *one, + const char *two) +{ + if (_easycsv_checkcsvandstring_one(csv, one) < 0) + return -1; + + if (two == NULL) { + _easycsv_printerror(csv, EASYCSV_EMPTYSTRING); + return -1; + } + + return 0; +} diff --git a/src/_easycsv.h b/src/_easycsv.h new file mode 100644 index 0000000..f42895e --- /dev/null +++ b/src/_easycsv.h @@ -0,0 +1,178 @@ +#ifndef _EASYCSV +#define _EASYCSV + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "easycsv_error.h" + +/* Generic type definitions for internal use */ + +typedef uint32_t row_t; // max length of 2^32 - 1 +typedef uint32_t column_t; +typedef char* rowstr; // non-const, to free it after usage + +/** Flags for error messages */ +typedef enum { + EASYCSV_ERRORSTDERR = 0, + EASYCSV_ERROROFF, + EASYCSV_ERRORSTDOUT +} EASYCSV_ERRORMSG; + +/** Flags to facilitate changing modes during file copying phases */ +typedef enum { + EASYCSV_UNKNOWNMODE = 0, + EASYCSV_R, + EASYCSV_W +} EASYCSV_MODE; + +/** Flags to parameterise the easycsv_insertvalue */ +typedef enum { + EASYCSV_REPLACE, ///< (default) replaces word + EASYCSV_CONCAT, ///< concantates word at the end + EASYCSV_RCONCAT, ///< concantates word from the start +} EASYCSV_VALMODE; + +/** Flags to parameterise sorting */ +typedef enum { + EASYCSV_ALPHA, ///< sort alphabetically + EASYCSV_RALPHA, ///< sort reverse alphabetically + EASYCSV_NUMER, ///< sort numerically, from lowest value to highest + EASYCSV_RNUMER ///< sort from highest value to lowest +} EASYCSV_SORT; + +/* Flags denoting cell type */ +typedef enum { + EASYCSV_NONE, + EASYCSV_STRING, + EASYCSV_INT, + EASYCSV_FLOAT, + EASYCSV_UNKNOWNTYPE +} _EASYCSV_TYPE; + +/* Private easycsv members */ +typedef struct _easycsv { + FILE *file; // original CSV file + FILE *temp; // temporary CSV file for writing + char *fp; + char *tmpfp; + unsigned int rows; + unsigned int cols; + EASYCSV_ERRORMSG error; +#ifdef EASYCSV_DEBUG + clock_t start; +#endif +} _easycsv; + +/* (Constructor) Initialise _easycsv */ +_easycsv* +_easycsv_priv_init(const char*, + const EASYCSV_MODE, + const EASYCSV_ERRORMSG); + +/* (Destructor) Free _easycsv memory */ +void +_easycsv_priv_free(_easycsv*); + +/* Verifies mode of file */ +// int _easycsv_checkmode(struct easycsv*, const char); + +/* Copies data from temp FILE to file FILE */ +int +_easycsv_update(_easycsv*); + +/* Rewind easycsv, checks for readability */ +int +_easycsv_rewind(_easycsv*, + const EASYCSV_MODE); + +/* Returns string of a specific row, + includes the '\n' character as well! */ +char* +_easycsv_getrow(const _easycsv*, + const unsigned int); + +/* Return column number of a named column */ +int +_easycsv_getcolumn(const _easycsv*, + const char*); + +/* Verifies the type of the value (eg: string or int) */ +_EASYCSV_TYPE +_easycsv_checktype(const _easycsv*, + const int, + const int); + +/* Verifies if there is a value or not */ +int +_easycsv_checkifvalue(const _easycsv*, + const int, + const int); + +/* Grab const char* in row */ +char* +_easycsv_getvalueinrow(const _easycsv*, + const char*, + const unsigned int); + +/* Returns char pointer to start of value in rowstr */ +char* +_easycsv_setcharptovalue(const _easycsv*, + const char*, + const unsigned int); + +/* Insert value in row in specific column */ +char* +_easycsv_insertvalueinrow(const _easycsv*, + const char*, + const char*, + const unsigned int); + +/* Calculate rows */ +int +_easycsv_rows(_easycsv*, + const EASYCSV_MODE); + +/* Calculate columns*/ +int +_easycsv_columns(_easycsv*, + const EASYCSV_MODE); + +void +_easycsv_printerror(const _easycsv*, + const EASYCSV_ERROR); + +/* Print error from _easycsv struct in stderr */ +void +_easycsv_geterror(const _easycsv*, + const EASYCSV_ERROR, + FILE*); + +/* Check if easycsv* and const char* are NULL */ +int +_easycsv_checkcsvandstring_one(const _easycsv*, + const char*); + +/* Check if easycsv* and two const char* are NULL*/ +int +_easycsv_checkcsvandstring_two(const _easycsv*, + const char*, + const char*); + +/* Verifies if the string is not NULL or empty, returns 0 on success and -1 on failure */ +// int _easycsv_checkstring(const char*); + +/* Verifies if easycsv is not NULL or unallocated */ +// int _easycsv_checkeasycsv(const struct easycsv*); + +/* Verifies if int is */ +// int _easycsv_checkunsigned(const int); + +#endif diff --git a/src/easycsv.c b/src/easycsv.c index 21d0426..e323e14 100644 --- a/src/easycsv.c +++ b/src/easycsv.c @@ -1,185 +1,8 @@ +#include "_easycsv.h" #include "../include/easycsv.h" -/* Generic type definitions for internal use */ - -typedef uint32_t row_t; // max length of 2^32 - 1 -typedef uint32_t column_t; -typedef char* rowstr; // non-const, to free it after usage - -/* I may possibly need to make types for rows, - iterators and columns */ - -/* Flags denoting cell type */ -typedef enum { - EASYCSV_NONE, - EASYCSV_STRING, - EASYCSV_INT, - EASYCSV_FLOAT, - EASYCSV_UNKNOWNTYPE -} _EASYCSV_TYPE; - -/* Error flags */ -typedef enum { - - /* Generic errors */ - EASYCSV_NOERROR, // no error - EASYCSV_NULLCSV, // easycsv* is NULL - EASYCSV_NULLPTR, // generic pointer is NULL - EASYCSV_EMPTYSTRING, // empty string - EASYCSV_EMPTYVALUE, // value is empty - EASYCSV_OVERMAXROW, // int exceeds row limit - EASYCSV_OVERMAXCOL, // int exceeds col limit - EASYCSV_ZEROROW, - EASYCSV_ZEROCOL, - - /* File input/output errors */ - EASYCSV_UNKNOWNIOMODE, // unknown file IO mode - EASYCSV_OPENFAIL, // fail to open - EASYCSV_REOPENFAIL, // fail to reopen - EASYCSV_EMPTYCSV, // csv is empty or does not exist - EASYCSV_UNWRITABLE, // csv mode not at EASYCSV_W - EASYCSV_UNREADABLE, // csv mode not at EASYCSV_R - EASYCSV_UPDATEFAIL, // update file fail = temp -> file - EASYCSV_UPDATETEMPFAIL, // update = -> temp - EASYCSV_FILEPTRFAIL, // move file pointer fail - - /* Non-existant elements */ - EASYCSV_ROWNOTEXIST, // row does not exist - EASYCSV_COLNOTEXIST, // column does not exist - - /* User-facing failure */ - EASYCSV_PUSHCOLFAIL, // push column value fail - EASYCSV_COLNUMFAIL, // column number retrieval fail - EASYCSV_READVALUEFAIL, // read value fail -} EASYCSV_ERROR; - -/* Private easycsv members */ -typedef struct _easycsv { - FILE *file; // original CSV file - FILE *temp; // temporary CSV file for writing - char *fp; - char *tmpfp; - unsigned int rows; - unsigned int cols; - EASYCSV_ERRORMSG error; -#ifdef EASYCSV_DEBUG - clock_t start; -#endif -} _easycsv; - -/* PRIVATE FUNCTIONS */ - -/* (Constructor) Initialise _easycsv */ -static _easycsv* -_easycsv_priv_init(const char*, - const EASYCSV_MODE, - const EASYCSV_ERRORMSG); - -/* (Destructor) Free _easycsv memory */ -static void -_easycsv_priv_free(_easycsv*); - -/* Verifies mode of file */ -// static int _easycsv_checkmode(struct easycsv*, const char); - -/* Copies data from temp FILE to file FILE */ -static int -_easycsv_update(easycsv*); - -/* Rewind easycsv, checks for readability */ -static int -_easycsv_rewind(_easycsv*, - const EASYCSV_MODE); - -/* Returns string of a specific row, - includes the '\n' character as well! */ -static char* -_easycsv_getrow(const easycsv*, - const unsigned int); - -/* Return column number of a named column */ -static int -_easycsv_getcolumn(const easycsv*, - const char*); - -/* Verifies the type of the value (eg: string or int) */ -static _EASYCSV_TYPE -_easycsv_checktype(const easycsv*, - const int, - const int); - -/* Verifies if there is a value or not */ -static int -_easycsv_checkifvalue(const easycsv*, - const int, - const int); - -/* Grab const char* in row */ -static char* -_easycsv_getvalueinrow(const _easycsv*, - const char*, - const unsigned int); - -/* Returns char pointer to start of value in rowstr */ -static char* -_easycsv_setcharptovalue(const _easycsv*, - const char*, - const unsigned int); - -/* Insert value in row in specific column */ -static char* -_easycsv_insertvalueinrow(const _easycsv*, - const char*, - const char*, - const unsigned int); - -/* Calculate rows */ -static int -_easycsv_rows(_easycsv*, - const EASYCSV_MODE); - -/* Calculate columns*/ -static int -_easycsv_columns(_easycsv*, - const EASYCSV_MODE); - -static void -_easycsv_printerror(const _easycsv*, - const EASYCSV_ERROR); - -/* Print error from _easycsv struct in stderr */ -static void -_easycsv_geterror(const _easycsv*, - const EASYCSV_ERROR, - FILE*); - -/* Check if easycsv* and const char* are NULL */ -static int -_easycsv_checkcsvandstring_one(const easycsv*, - const char*); - -/* Check if easycsv* and two const char* are NULL*/ -static int -_easycsv_checkcsvandstring_two(const easycsv*, - const char*, - const char*); - -/* Verifies if the string is not NULL or empty, returns 0 on success and -1 on failure */ -// static int _easycsv_checkstring(const char*); - -/* Verifies if easycsv is not NULL or unallocated */ -// static int _easycsv_checkeasycsv(const struct easycsv*); - -/* Verifies if int is */ -// static int _easycsv_checkunsigned(const int); - -/* - * ==================== - * FUNCTION DEFINITIONS - * ==================== - */ - -/* == PUBLIC FUNCTIONS == */ +// typedef struct _easycsv _easycsv; +// _easycsv* _easycsv_priv_init(const char *fp, const EASYCSV_MODE mode, const EASYCSV_ERRORMSG error); /* CONSTRUCTORS AND DESTRUCTORS */ @@ -248,7 +71,7 @@ easycsv_readvalue(const easycsv *csv, } /* END ARGS CHECK */ - char *str = _easycsv_getrow(csv, row); + char *str = _easycsv_getrow(csv->_priv, row); if (str == NULL) { _easycsv_printerror(csv->_priv, EASYCSV_ROWNOTEXIST); _easycsv_printerror(csv->_priv, EASYCSV_READVALUEFAIL); @@ -270,7 +93,7 @@ easycsv_readcolumnvalue(const easycsv *csv, const unsigned int row) { /* ARGS CHECK */ - if (_easycsv_checkcsvandstring_one(csv, col) < 0) + if (_easycsv_checkcsvandstring_one(csv->_priv, col) < 0) return NULL; if (row > csv->_priv->rows) { @@ -279,7 +102,7 @@ easycsv_readcolumnvalue(const easycsv *csv, } /* END ARGS CHECK */ - int i = _easycsv_getcolumn(csv, col); + int i = _easycsv_getcolumn(csv->_priv, col); if (i < 1) { _easycsv_printerror(csv->_priv, EASYCSV_COLNUMFAIL); return NULL; @@ -319,7 +142,7 @@ easycsv_insertvaluemode(easycsv *csv, const EASYCSV_VALMODE valmode) { /* ARGS CHECK */ - if (_easycsv_checkcsvandstring_one(csv, val) < 0) + if (_easycsv_checkcsvandstring_one(csv->_priv, val) < 0) return -1; if (col == 0) { @@ -337,7 +160,7 @@ easycsv_insertvaluemode(easycsv *csv, if (row > csv->_priv->rows) { } - char *rowstr = _easycsv_getrow(csv, row); + char *rowstr = _easycsv_getrow(csv->_priv, row); if (rowstr == NULL) return -1; @@ -415,7 +238,7 @@ easycsv_insertvaluemode(easycsv *csv, /* Copy rows before newstr in csv to temp */ for (unsigned int i = 1; i < row; i++) { - str = _easycsv_getrow(csv, 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++) { @@ -464,7 +287,7 @@ easycsv_insertvaluemode(easycsv *csv, } /* Update csv */ - if (_easycsv_update(csv) < 0) + if (_easycsv_update(csv->_priv) < 0) return -1; /* END UPDATE CSV */ @@ -492,7 +315,7 @@ easycsv_insertcolumnvaluemode(easycsv *csv, const EASYCSV_VALMODE valmode) { /* ARGS CHECK */ - if (_easycsv_checkcsvandstring_two(csv, col, val) < 0) + if (_easycsv_checkcsvandstring_two(csv->_priv, col, val) < 0) return -1; if (row == 0) { @@ -501,7 +324,7 @@ easycsv_insertcolumnvaluemode(easycsv *csv, } /* END ARGS CHECK */ - int colnum = _easycsv_getcolumn(csv, col); + int colnum = _easycsv_getcolumn(csv->_priv, col); if (colnum < 0) { _easycsv_printerror(csv->_priv, EASYCSV_COLNUMFAIL); return -1; @@ -517,7 +340,7 @@ easycsv_pushcolumn(easycsv *csv, const char *col) { /* ARGS CHECK */ - if (_easycsv_checkcsvandstring_one(csv, col) < 0) + if (_easycsv_checkcsvandstring_one(csv->_priv, col) < 0) return -1; /* END ARGS CHECK */ @@ -539,7 +362,7 @@ easycsv_pushcolumn(easycsv *csv, } /* Grab first row */ - char *str = _easycsv_getrow(csv, 1); + char *str = _easycsv_getrow(csv->_priv, 1); char *pch = NULL; size_t i; @@ -586,11 +409,11 @@ easycsv_pushcolumnvalue(easycsv *csv, const char *val) { /* ARGS CHECK */ - if (_easycsv_checkcsvandstring_two(csv, col, val) < 0) + if (_easycsv_checkcsvandstring_two(csv->_priv, col, val) < 0) return -1; /* ARGS CHECK */ - int colnum = _easycsv_getcolumn(csv, col); + int colnum = _easycsv_getcolumn(csv->_priv, col); if (colnum < 0) { _easycsv_printerror(csv->_priv, EASYCSV_COLNUMFAIL); return -1; @@ -662,11 +485,11 @@ easycsv_deletecolumnstr(easycsv *csv, const char *col) { /* ARGS CHECK */ - if (_easycsv_checkcsvandstring_one(csv, col) < 0) + if (_easycsv_checkcsvandstring_one(csv->_priv, col) < 0) return -1; /* END ARGS CHECK */ - int colnum = _easycsv_getcolumn(csv, col); + int colnum = _easycsv_getcolumn(csv->_priv, col); if (colnum < 0) return -1; @@ -679,509 +502,3 @@ easycsV_deleterowint(easycsv *csv, { return 0; } -/* PRIVATE FUNCTIONS */ - -/* (Constructor) Initialise _easycsv */ -_easycsv* -_easycsv_priv_init(const char *fp, - const EASYCSV_MODE mode, - const EASYCSV_ERRORMSG error) -{ - _easycsv *_priv = malloc(sizeof(_easycsv)); - - _priv->file = NULL; - _priv->temp = NULL; - _priv->fp = NULL; - _priv->tmpfp = NULL; - _priv->rows = 0; - _priv->cols = 0; -#ifdef EASYCSV_DEBUG - _priv->start = 0; -#endif - - _priv->error = error; - - /* Open file according to mode */ - switch (mode) { - case EASYCSV_R: { - _priv->file = fopen(fp, "r"); - break; - } - case EASYCSV_W: { - _priv->file = fopen(fp, "w"); - break; - } - default: { - _easycsv_printerror(_priv, EASYCSV_UNKNOWNIOMODE); - _easycsv_priv_free(_priv); - return NULL; - } - } - - if (_priv->file == NULL) - { - _easycsv_printerror(_priv, EASYCSV_OPENFAIL); - _easycsv_priv_free(_priv); - return NULL; - } - - size_t stfp = strlen(fp); - - /* Allocate memory for char* */ - _priv->fp = malloc(stfp + 1); // + 1 for null - - strcpy(_priv->fp, fp); - - /* Calculate rows and cols if file exists */ - if (access(_priv->fp, F_OK) == 0) { - _priv->rows = _easycsv_rows(_priv, mode); - _priv->cols = _easycsv_columns(_priv, mode); - } - - if (mode == EASYCSV_W) { - - /* csv->tmpfp = malloc(16 + stfp + 1); */ - /* strncpy(csv->tmpfp, prefix, 16); */ - - /* strncat(csv->tmpfp, fp, stfp); */ - - do { - /* Write to temporary file */ - unsigned int i = 1; - char buffer[21] = "/tmp/easycsv-"; // 13 char, 3 for digits, 4 for .csv, 1 for NULL - - if (i < 100) - strncat(buffer, "0", 1); - - if (i < 10) - strncat(buffer, "0", 1); - - sprintf(buffer + strlen(buffer), "%i", i); - strcat(buffer, ".csv"); - - if (access(buffer, F_OK) < 0) { - i++; - } - else { - _priv->tmpfp = malloc(21); - strncpy(_priv->tmpfp, buffer, 21); - break; - } - - } while (1); - - _priv->temp = fopen(_priv->tmpfp, "w"); - if (_priv->temp == NULL) { - _easycsv_printerror(_priv, EASYCSV_OPENFAIL); - _easycsv_priv_free(_priv); - return NULL; - } - /* -#ifdef EASYCSV_DEBUG - printf("[%i] easycsv_debug: temp file %s opened\n", clock() - csv->start, csv->tmpfp); - #endif*/ - /* - - if (freopen(csv->fp, csv->mode, csv->file) == NULL) { - fprintf(stderr, "easycsv: failed to set temporary file %s to %s mode\n", csv->tmpfp, csv->mode); - return NULL; - } - - if (freopen(csv->tmpfp, csv->mode, csv->temp) == NULL) { - fprintf(stderr, "easycsv: failed to set temporary file %s to %s mode\n", csv->tmpfp, csv->mode); - return NULL; - } - */ - - } - - return _priv; -} - -/* (Destructor) Free _easycsv memory */ -void -_easycsv_priv_free(_easycsv *_priv) -{ - /* ARGS CHECK */ - if (_priv == NULL) - return; - /* ARGS CHECK */ - if (_priv->file != NULL) - fclose(_priv->file); - if (_priv->temp != NULL) - fclose(_priv->temp); - if (_priv->fp != NULL) - free(_priv->fp); - if (_priv->tmpfp != NULL) - free(_priv->tmpfp); - free(_priv); -} - -int -_easycsv_update(easycsv *csv) -{ - /* ARGS CHECK */ - if (csv == NULL) { - _easycsv_printerror(csv->_priv, EASYCSV_NULLCSV); - return -1; - } - /* ARGS CHECK */ - - /* Set temp file to read binary */ - if (freopen(csv->_priv->tmpfp, "rb", csv->_priv->temp) == NULL) { - _easycsv_printerror(csv->_priv, EASYCSV_REOPENFAIL); - easycsv_free(csv); - return -1; - } - - /* Set file to write binary */ - if (freopen(csv->_priv->fp, "wb", csv->_priv->file) == NULL) { - _easycsv_printerror(csv->_priv, EASYCSV_REOPENFAIL); - easycsv_free(csv); - return -1; - } - - /* Copy entire file */ - char buf[BUFSIZ]; - size_t size; - while (size = fread(buf, 1, BUFSIZ, csv->_priv->temp)) { - fwrite(buf, 1, size, csv->_priv->file); - } - - /* Set temp file back to write */ - if (freopen(csv->_priv->tmpfp, "w", csv->_priv->temp) == NULL) { - _easycsv_printerror(csv->_priv, EASYCSV_REOPENFAIL); - easycsv_free(csv); - return -1; - } - - /* Set file back to read */ - if (freopen(csv->_priv->fp, "r", csv->_priv->file) == NULL) { - _easycsv_printerror(csv->_priv, EASYCSV_REOPENFAIL); - easycsv_free(csv); - return -1; - } - - return 0; -} - -int -_easycsv_rows(_easycsv *_priv, - const EASYCSV_MODE mode) -{ - // no need to check _priv for NULL - - if (_easycsv_rewind(_priv, mode) < 0) - return -1; - - int rows = 1; - char c; - - /* Go through each character in the file and count the number of \n - in it */ - while ((c = fgetc(_priv->file)) != EOF) { - if (c == '\n') rows++; - } - - return rows; -} - -int -_easycsv_columns(_easycsv *_priv, - const EASYCSV_MODE mode) -{ - // no need to check _priv for NULL - - /* Prepare it for reading */ - if (_easycsv_rewind(_priv, mode) < 0) return -1; - - /* - 1. check if empty file - 2. check if only one column -> 0 commas - 3. if >1 column, n commas = n+1 columns - */ - - int col = 1; - char c; - - while ((c = fgetc(_priv->file)) != '\n') { - if (c == ',') col++; - } - - return col; -} - -char* -_easycsv_getrow(const easycsv *csv, - const unsigned int row) -{ - /* ARGS CHECK */ - if (csv == NULL) { - _easycsv_printerror(csv->_priv, EASYCSV_NULLCSV); - return NULL; - } - - if (row > csv->_priv->rows) { - _easycsv_printerror(csv->_priv, EASYCSV_OVERMAXROW); - return NULL; - } - - if (row == 0) { - _easycsv_printerror(csv->_priv, EASYCSV_ZEROROW); - return NULL; - } - /* END ARGS CHECK */ - - /* Allocate memory */ - char *str = malloc(BUFSIZ); - - /* Set file pointer to start */ - rewind(csv->_priv->file); - - for (int i = 1; i < row; i++) - { - /* skip until row is reached */ - fscanf(csv->_priv->file, "%*[^\n]\n", NULL); - } - - /* Grab the row and store it in str */ - fscanf(csv->_priv->file, "%s\n", str); - - // printf("row: %s\n", str); - - return str; -} - -int -_easycsv_rewind(_easycsv *_priv, - const EASYCSV_MODE mode) -{ - /* Check if empty file */ - if (fscanf(_priv->file, "\n") == EOF) { - _easycsv_printerror(_priv, EASYCSV_EMPTYCSV); - return -1; - } - - /* Check if file is readable */ - if (mode != EASYCSV_R) { - _easycsv_printerror(_priv, EASYCSV_UNREADABLE); - return -1; - } - - /* Set file pointer to the start */ - rewind(_priv->file); - - return 0; -} - -int -_easycsv_getcolumn(const easycsv *csv, - const char *col) -{ - /* ARGS CHECK */ - if (_easycsv_checkcsvandstring_one(csv, col) < 0) - return -1; - /* ARGS CHECK */ - - /* Grab str of row 1 */ - char *firstrow = _easycsv_getrow(csv, 1); - - if (firstrow == NULL) { - _easycsv_printerror(csv->_priv, EASYCSV_ROWNOTEXIST); - return -1; - } - - unsigned int commas = 0; - - // printf("FIRST COLUMN: %s\n", firstrow); - - /* Find first occurance of col in firstrow */ - char *str = strstr(firstrow, col); - - if (str == NULL) { - _easycsv_printerror(csv->_priv, EASYCSV_COLNOTEXIST); - return -1; - } - - /* Count numbers of commas following str */ - char *c = strpbrk(str, ","); - while (c != NULL) { - commas++; - c = strpbrk(c + 1, ","); - } - - /* no need to free c as it is already NULL at this point */ - // free((char*) str); apparently invalid pointer - - // printf("ROW: %i\nCOL: %i\n", row, csv->_priv->cols - commas); - /* -#ifdef EASYCSV_DEBUG - printf("[%i] rcv_commas: %i\n", clock() - csv->_priv->start, commas); -#endif - */ - free(firstrow); - - return csv->_priv->cols - commas; -} - -/* -int _easycsv_checkifvalue(struct easycsv *csv, const int col, const int row) -{ - const char *rowstr = _easycsv_getrow(csv, row); - - return 0; -} -*/ - -char* -_easycsv_getvalueinrow(const _easycsv *_priv, - const char *row, - const unsigned int col) -{ - size_t st; - char *pch = NULL; - - /* If not first column */ - if (col != 1) { - - /* Get first occurance of comma in str, - the first value is ommited but not the comma */ - char *pch = strpbrk(row, ","); - - /* Repeat until desired col is found */ - for (int i = 2; i < col; i++) { - pch = strpbrk(pch + 1, ","); - } - } - - /* Get span from start of string to first occurence - of comma */ - st = strcspn(pch + 1, ","); - - /* If 0, no string exists! */ - if (st == 0) { - _easycsv_printerror(_priv, EASYCSV_EMPTYVALUE); - return NULL; - } - - char *val = malloc(st + 1); - strncpy(val, pch + 1, st); - strncat(val, "\0", 1); - - return val; -} - -static char* -_easycsv_setcharptovalue(const _easycsv *_priv, - const char *rowstr, - const unsigned int col) -{ - char *pch = rowstr; - - for (unsigned int i = 1; i < col; i++) { - pch = strchr(rowstr, ','); - if (pch == NULL) { - _easycsv_printerror(_priv, EASYCSV_NULLPTR); - return NULL; - } - pch++; - } - - return pch; -} - -void -_easycsv_printerror(const _easycsv *_priv, - const EASYCSV_ERROR error) -{ - switch (_priv->error) { - case EASYCSV_ERROROFF: return; - case EASYCSV_ERRORSTDOUT: _easycsv_geterror(_priv, error, stdout); break; - case EASYCSV_ERRORSTDERR: - default: _easycsv_geterror(_priv, error, stderr); return; - } -} - -void -_easycsv_geterror(const _easycsv *_priv, - const EASYCSV_ERROR error, - FILE *fs) -{ -#ifdef EASYCSV_DEBUG - fprintf(stderr, "[%i] ", clock() - _priv->start); -#endif - - fputs("easycsv: ", fs); - - switch (error) { - - /* Generic errors */ - case EASYCSV_NOERROR: fputs("no error", fs); break; - case EASYCSV_NULLCSV: fputs("easycsv pointer is NULL", fs); break; - case EASYCSV_NULLPTR: fputs("pointer is NULL", fs); break; - case EASYCSV_EMPTYSTRING: fputs("string is empty", fs); break; - case EASYCSV_EMPTYVALUE: fputs("value in CSV file is empty", fs); break; - case EASYCSV_OVERMAXROW: fprintf(fs, "int exceeds row limit %i", _priv->rows); break; - case EASYCSV_OVERMAXCOL: fprintf(fs, "int exceeds column limit %i", _priv->cols); break; - case EASYCSV_ZEROROW: fputs("parameterised row number is zero", fs); break; - case EASYCSV_ZEROCOL: fputs("parameterised column number is zero", fs); break; - - /* File input/output errors */ - case EASYCSV_UNKNOWNIOMODE: fputs("unknown file IO mode", fs); break; - case EASYCSV_OPENFAIL: fputs("failed to open file", fs); break; - case EASYCSV_REOPENFAIL: fputs("failed to reopen file", fs); break; - case EASYCSV_EMPTYCSV: fputs("CSV file is empty", fs); break; - case EASYCSV_UNWRITABLE: fputs("CSV file is not in a writable mode", fs); break; - case EASYCSV_UNREADABLE: fputs("CSV file is not in a readable mode", fs); break; - case EASYCSV_UPDATEFAIL: fputs("CSV file has failed to update", fs); break; - case EASYCSV_UPDATETEMPFAIL: fputs("failed to update temp CSV file", fs); break; - case EASYCSV_FILEPTRFAIL: fputs("failed to move FILE pointer", fs); break; - - /* Non-existant elements */ - case EASYCSV_ROWNOTEXIST: fputs("given row does not exist", fs); break; - case EASYCSV_COLNOTEXIST: fputs("given column does not exist", fs); break; - - /* User-facing failure */ - case EASYCSV_PUSHCOLFAIL: fputs("failed to push value under column", fs); break; - case EASYCSV_COLNUMFAIL: fputs("failed to determine the column number of a value in the first row", fs); break; - default: fputs("unknown error, easycsv* is possibly NULL", fs); break; - } - - if (_priv->fp != NULL) - fprintf(fs, " in %s", _priv->fp); - - fputc('\n', fs); -} - -int -_easycsv_checkcsvandstring_one(const easycsv *csv, - const char *one) -{ - if (csv == NULL) { - _easycsv_printerror(csv->_priv, EASYCSV_NULLCSV); - return -1; - } - - if (one == NULL) { - _easycsv_printerror(csv->_priv, EASYCSV_EMPTYSTRING); - return -1; - } - - return 0; -} - -int -_easycsv_checkcsvandstring_two(const easycsv *csv, - const char *one, - const char *two) -{ - if (_easycsv_checkcsvandstring_one(csv, one) < 0) - return -1; - - if (two == NULL) { - _easycsv_printerror(csv->_priv, EASYCSV_EMPTYSTRING); - return -1; - } - - return 0; -} diff --git a/src/easycsv_error.h b/src/easycsv_error.h new file mode 100644 index 0000000..8482aaf --- /dev/null +++ b/src/easycsv_error.h @@ -0,0 +1,39 @@ +#ifndef EASYCSV_ERROR +#define EASYCSV_ERROR + +/* Error flags */ +typedef enum { + + /* Generic errors */ + EASYCSV_NOERROR, // no error + EASYCSV_NULLCSV, // easycsv* is NULL + EASYCSV_NULLPTR, // generic pointer is NULL + EASYCSV_EMPTYSTRING, // empty string + EASYCSV_EMPTYVALUE, // value is empty + EASYCSV_OVERMAXROW, // int exceeds row limit + EASYCSV_OVERMAXCOL, // int exceeds col limit + EASYCSV_ZEROROW, + EASYCSV_ZEROCOL, + + /* File input/output errors */ + EASYCSV_UNKNOWNIOMODE, // unknown file IO mode + EASYCSV_OPENFAIL, // fail to open + EASYCSV_REOPENFAIL, // fail to reopen + EASYCSV_EMPTYCSV, // csv is empty or does not exist + EASYCSV_UNWRITABLE, // csv mode not at EASYCSV_W + EASYCSV_UNREADABLE, // csv mode not at EASYCSV_R + EASYCSV_UPDATEFAIL, // update file fail = temp -> file + EASYCSV_UPDATETEMPFAIL, // update = -> temp + EASYCSV_FILEPTRFAIL, // move file pointer fail + + /* Non-existant elements */ + EASYCSV_ROWNOTEXIST, // row does not exist + EASYCSV_COLNOTEXIST, // column does not exist + + /* User-facing failure */ + EASYCSV_PUSHCOLFAIL, // push column value fail + EASYCSV_COLNUMFAIL, // column number retrieval fail + EASYCSV_READVALUEFAIL, // read value fail +} EASYCSV_ERROR; + +#endif diff --git a/src/internal/easycsv_error.h b/src/internal/easycsv_error.h deleted file mode 100644 index e69de29..0000000