Compare commits

...

28 Commits

Author SHA1 Message Date
Pradana AUMARS 9ac6ee03e4 Add easycsv_string testing 11 months ago
Pradana AUMARS 9cdf20e7a7 Create libeasycsv_string library 11 months ago
Pradana AUMARS 924e47bacc Move purely string-manipulation function to a separate file 11 months ago
Pradana AUMARS b0e3062d59 Add easycsv_get_row and easycsv_set_charp_to_value 11 months ago
Pradana AUMARS 959ffce49f easycsv_insert_value documentation fixed 11 months ago
Pradana AUMARS 27fdceb684 Add write mode tests 11 months ago
Pradana AUMARS d6f0b0260e Fixed easycsv_init for write mode 11 months ago
Pradana AUMARS 4b3c7bbb97 Add EASYCSV_MEMALLOC error flag 11 months ago
Pradana AUMARS 99995d7b0f Add more tests 11 months ago
Pradana AUMARS 638af0080d In easycsv_print_columns/rows, update docs 11 months ago
Pradana AUMARS 006cd346e9 In easycsv_print_columns/rows, check NULL pointer 11 months ago
Pradana AUMARS 679160e208 Fix easycsv_find_num_value 11 months ago
Pradana AUMARS 042667e538 Add more tests for easycsv_read_value 11 months ago
Pradana AUMARS 0793a5a1c6 In easycsv_read_value, check if row and col are valid 11 months ago
Pradana AUMARS 46ed839860 Add testing for easycsv_find_num_value 12 months ago
Pradana AUMARS 7ce936b8d1 Add easycsv_find_num_value (errorenous), fixed easycsv_read_value 12 months ago
Pradana AUMARS cba239de98 Remove unnessary rewind 12 months ago
Pradana AUMARS c19760c62f Fixed easycsv_find_num_value documentation 12 months ago
Pradana AUMARS 1a0e8e5bcb Add easycsv_find_value 12 months ago
Pradana AUMARS 4647b72551 Add error message for easycsv_find_value fail 12 months ago
Pradana AUMARS 61618b72bc Fix easycsv_find_value documentation 12 months ago
Pradana AUMARS 3178e0eccf Corrected cell names 12 months ago
Pradana AUMARS 39059b3e49 Remove unneeded variables and initialisations in easycsv_read_value 12 months ago
Pradana AUMARS 3304163ab0 Fix easycsv_read_value with more tests 12 months ago
Pradana AUMARS 2fa4ca384c Fix easycsv_read_value 12 months ago
Pradana AUMARS bb1e4aef4f Specify that easycsv_read_value returns heap-allocated string pointer 12 months ago
Pradana AUMARS 769322ec6b Modify 1.csv to be more logical 12 months ago
Pradana AUMARS d4b53ede9b All private members are now public members. 12 months ago
  1. 388
      include/easycsv.h
  2. 14
      src/Makefile.am
  3. 506
      src/_easycsv.c
  4. 178
      src/_easycsv.h
  5. 977
      src/easycsv.c
  6. 60
      src/easycsv_error.c
  7. 13
      src/easycsv_error.h
  8. 270
      src/easycsv_p.c
  9. 113
      src/easycsv_p.h
  10. 67
      src/easycsv_string.c
  11. 32
      src/easycsv_string.h
  12. 12
      tests/Makefile.am
  13. 115
      tests/check_easycsv.c
  14. 35
      tests/check_easycsv_string.c
  15. 9
      tests/samples/1.csv

388
include/easycsv.h

@ -1,13 +1,73 @@
#ifndef EASYCSV_H
#define EASYCSV_H
#include "../src/_easycsv.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <stdint.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 ***/
/** 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;
/*** Structures ***/
/** Public easycsv members */
typedef struct easycsv {
EASYCSV_MODE mode;
_easycsv *_priv;
} easycsv;
/**
* easycsv:
*
* A CSV file.
*/
typedef struct _easycsv easycsv;
struct _easycsv {
FILE *file; ///< original CSV file
FILE *temp; ///< temporary CSV file for writing
char fp[BUFSIZ];
// char *tmpfp;
unsigned int rows;
unsigned int cols;
// EASYCSV_ERRORMSG error;
EASYCSV_MODE mode;
};
/*** Constructors ***/
@ -21,17 +81,17 @@ easycsv*
easycsv_init(const char*,
const EASYCSV_MODE);
/**
* 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);
/* /\** */
/* * 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); */
/**
* Destroy easycsv structure
@ -40,75 +100,85 @@ easycsv_init_errormsg(const char*,
void
easycsv_free(easycsv*);
/*** Error handling ***/
/**
* Get error message
* @return easycsv error message
*/
char*
easycsv_get_error();
/*** Access, find ***/
/**
* 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
* @param[out] pointer to column number, unchanged if error
* @param[out] pointer to row number, unchanged if error
* @return 0 if success, -1 if error
*/
int
easycsv_findvalue(const easycsv*,
const char*,
unsigned int*,
unsigned int*);
easycsv_find_value(const easycsv*,
const char*,
unsigned int*,
unsigned int*);
/**
* Find number of instances of value
* @param[in] constant pointer to easycsv structure
* @param[in] value to find
* @return number of instances
* @return positive integer if success, -1 if error
*/
int
easycsv_findnumvalue(const easycsv*,
const char*);
easycsv_find_num_value(const easycsv*,
const char*);
/*** Access, read ***/
/**
* Read string in a specific cell
* String is heap-allocated, it must be destroyed (free'd) manually
* @param[in] constant pointer to easycsv structure
* @param[in] row number
* @param[in] column number
* @return string value of cell, NULL if empty cell
* @return string value of cell, NULL if error
*/
char*
easycsv_readvalue(const easycsv*,
easycsv_read_value(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);
/* /\** */
/* * 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); */
/*** Access, print ***/
/**
* Return number of rows
* @param[in] constant pointer to easycsv structure
* @return number of rows
* @return number of rows, -1 if error
*/
int
easycsv_printrows(const easycsv*);
easycsv_print_rows(const easycsv*);
/**
* Return number of columns
* @param[in] constant pointer to easycsv structure
* @return number of columns
* @return number of columns, -1 if error
*/
int
easycsv_printcolumns(const easycsv*);
easycsv_print_columns(const easycsv*);
/*** Modifications, sort ***/
@ -138,25 +208,25 @@ easycsv_sortcolumn(easycsv*,
/*** Modifications, insert ***/
/**
* Insert row into CSV file
* @param[in] pointer to easycsv structure
* @param[in] cell value
* @param[in] row number
* @return easycsv error code
*/
int
easycsv_insertrow(easycsv*,
const char*,
int);
/* /\** */
/* * Insert row into CSV file */
/* * @param[in] pointer to easycsv structure */
/* * @param[in] cell value */
/* * @param[in] row number */
/* * @return easycsv error code */
/* *\/ */
/* int */
/* easycsv_insertrow(easycsv*, */
/* const char*, */
/* int); */
/**
* Insert string in a specific cell
* Insert/replace string in a specific cell
* @param[in] pointer to easycsv structure
* @param[in] cell value
* @param[in] row number
* @param[in] cell value (cell value will not be modified if there is an error)
* @param[in] column number
* @return easycsv error code
* @param[in] row number
* @return 0 if no error, -1 if error
*/
int
easycsv_insertvalue(easycsv*,
@ -164,75 +234,75 @@ easycsv_insertvalue(easycsv*,
unsigned int,
unsigned int);
/**
* Insert string in a specific cell with specific mode
* @param[in] pointer to easycsv structure
* @param[in] cell value
* @param[in] row number
* @param[in] column number
* @param[in] easycsv value mode
* @return easycsv error code
*/
int
easycsv_insertvaluemode(easycsv*,
const char*,
unsigned int,
unsigned int,
EASYCSV_VALMODE);
/**
* Insert string in a specific cell with named column in a given row
* @param[in] pointer to easycsv structure
* @param[in] cell value
* @param[in] row number
* @param[in] column value
* @return easycsv error code
*/
int
easycsv_insertcolumnvalue(easycsv*,
const char*,
unsigned int,
const char*);
/**
* Insert string in a specific cell with named column in a given row with specific mode
* @param[in] pointer to easycsv structure
* @param[in] cell value
* @param[in] row number
* @param[in] column value
* @param[in] easycsv value mode
* @return easycsv error code
*/
int
easycsv_insertcolumnvaluemode(easycsv*,
const char*,
unsigned int,
const char*,
EASYCSV_VALMODE);
/* /\** */
/* * Insert string in a specific cell with specific mode */
/* * @param[in] pointer to easycsv structure */
/* * @param[in] cell value */
/* * @param[in] row number */
/* * @param[in] column number */
/* * @param[in] easycsv value mode */
/* * @return easycsv error code */
/* *\/ */
/* int */
/* easycsv_insertvaluemode(easycsv*, */
/* const char*, */
/* unsigned int, */
/* unsigned int, */
/* EASYCSV_VALMODE); */
/* /\** */
/* * Insert string in a specific cell with named column in a given row */
/* * @param[in] pointer to easycsv structure */
/* * @param[in] cell value */
/* * @param[in] row number */
/* * @param[in] column value */
/* * @return easycsv error code */
/* *\/ */
/* int */
/* easycsv_insertcolumnvalue(easycsv*, */
/* const char*, */
/* unsigned int, */
/* const char*); */
/* /\** */
/* * Insert string in a specific cell with named column in a given row with specific mode */
/* * @param[in] pointer to easycsv structure */
/* * @param[in] cell value */
/* * @param[in] row number */
/* * @param[in] column value */
/* * @param[in] easycsv value mode */
/* * @return easycsv error code */
/* *\/ */
/* int */
/* easycsv_insertcolumnvaluemode(easycsv*, */
/* const char*, */
/* unsigned int, */
/* const char*, */
/* EASYCSV_VALMODE); */
/*** Modifications, push ***/
/**
* Create new column on the right-hand side of an existing one
* @param[in] pointer to easycsv structure
* @param[in] column value
* @return easycsv error code
*/
int
easycsv_pushcolumn(easycsv*,
const char*);
/**
* Insert string in a vacant cell under a named column
* @param[in] pointer to easycsv structure
* @param[in] column value
* @param[in] cell value
* @return easycsv error code
*/
int
easycsv_pushcolumnvalue(easycsv*,
const char*,
const char*);
/* /\** */
/* * Create new column on the right-hand side of an existing one */
/* * @param[in] pointer to easycsv structure */
/* * @param[in] column value */
/* * @return easycsv error code */
/* *\/ */
/* int */
/* easycsv_pushcolumn(easycsv*, */
/* const char*); */
/* /\** */
/* * Insert string in a vacant cell under a named column */
/* * @param[in] pointer to easycsv structure */
/* * @param[in] column value */
/* * @param[in] cell value */
/* * @return easycsv error code */
/* *\/ */
/* int */
/* easycsv_pushcolumnvalue(easycsv*, */
/* const char*, */
/* const char*); */
/*** Modifications, delete ***/
@ -248,24 +318,24 @@ easycsv_deletevalue(easycsv*,
unsigned int,
unsigned int);
/**
* Delete numbered column
* @param[in] pointer to easycsv structure
* @param[in] column number
* @return easycsv error code
*/
int
easycsv_deletecolumnint(easycsv*,
unsigned int);
/** Delete named column
* @param[in] pointer to easycsv structure
* @param[in] column value
* @return easycsv error code
*/
int
easycsv_deletecolumnstr(easycsv*,
const char*);
/* /\** */
/* * Delete numbered column */
/* * @param[in] pointer to easycsv structure */
/* * @param[in] column number */
/* * @return easycsv error code */
/* *\/ */
/* int */
/* easycsv_deletecolumnint(easycsv*, */
/* unsigned int); */
/* /\** Delete named column */
/* * @param[in] pointer to easycsv structure */
/* * @param[in] column value */
/* * @return easycsv error code */
/* *\/ */
/* int */
/* easycsv_deletecolumnstr(easycsv*, */
/* const char*); */
/* Delete numered row */
@ -273,24 +343,24 @@ easycsv_deletecolumnstr(easycsv*,
/*** Modifications, append ***/
/**
* Append two CSV files
* @param[in] destination CSV file
* @param[in] source CSV file
* @return easycsv error code
*/
int
easycsv_appendcsv(easycsv*,
easycsv*);
/* /\** */
/* * Append two CSV files */
/* * @param[in] destination CSV file */
/* * @param[in] source CSV file */
/* * @return easycsv error code */
/* *\/ */
/* int */
/* easycsv_appendcsv(easycsv*, */
/* easycsv*); */
/*** Modifications, miscellenaeous ***/
/**
* Compress a CSV file
* @param[in] pointer to easycsv structure
* @return easycsv error code
*/
int
easycsv_compress(easycsv*);
/* /\** */
/* * Compress a CSV file */
/* * @param[in] pointer to easycsv structure */
/* * @return easycsv error code */
/* *\/ */
/* int */
/* easycsv_compress(easycsv*); */
#endif /* EASYCSV_H */

14
src/Makefile.am

@ -1,6 +1,12 @@
lib_LTLIBRARIES = libeasycsv.la
lib_LTLIBRARIES = libeasycsv.la libeasycsv_string.la
libeasycsv_la_SOURCES = \
_easycsv.c \
_easycsv.h \
easycsv.c
easycsv.c \
easycsv_error.h \
easycsv_error.c \
easycsv_p.h \
easycsv_p.c
libeasycsv_la_LIBADD = libeasycsv_string.la
libeasycsv_string_la_SOURCES = \
easycsv_string.h \
easycsv_string.c
include_HEADERS = ../include/easycsv.h

506
src/_easycsv.c

@ -1,506 +0,0 @@
#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;
}

178
src/_easycsv.h

@ -1,178 +0,0 @@
#ifndef _EASYCSV
#define _EASYCSV
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <stdint.h>
#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

977
src/easycsv.c

File diff suppressed because it is too large Load Diff

60
src/easycsv_error.c

@ -0,0 +1,60 @@
#include <limits.h>
#include "../include/easycsv.h"
#include "easycsv_error.h"
/* 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; */
/* } */
/* } */
static char s_error_msg[SCHAR_MAX];
void
easycsv_error(EASYCSV_ERROR error,
const char *error_msg)
{
switch (error) {
case EASYCSV_NOERROR: sprintf(s_error_msg, "no error"); return;
case EASYCSV_NULLCSV: sprintf(s_error_msg, "easycsv pointer is NULL"); return;
case EASYCSV_NULLPTR: sprintf(s_error_msg, "pointer is NULL"); return;
case EASYCSV_EMPTYSTRING: sprintf(s_error_msg, "string is empty"); return;
case EASYCSV_EMPTYVALUE: sprintf(s_error_msg, "value in CSV file is empty"); return;
case EASYCSV_OVERMAXROW: sprintf(s_error_msg, "int exceeds row limit of %s", error_msg); return;
case EASYCSV_OVERMAXCOL: sprintf(s_error_msg, "int exceeds column limit of %s", error_msg); return;
case EASYCSV_ZEROROW: sprintf(s_error_msg, "parameterised row number is zero"); return;
case EASYCSV_ZEROCOL: sprintf(s_error_msg, "parameterised column number is zero"); return;
case EASYCSV_MEMALLOC: sprintf(s_error_msg, "memory allocation failure"); return;
case EASYCSV_UNKNOWNIOMODE: sprintf(s_error_msg, "unknown file IO mode"); return;
case EASYCSV_OPENFAIL: sprintf(s_error_msg, "failed to open file"); return;
case EASYCSV_REOPENFAIL: sprintf(s_error_msg, "failed to reopen file"); return;
case EASYCSV_EMPTYCSV: sprintf(s_error_msg, "CSV file is empty"); return;
case EASYCSV_UNWRITABLE: sprintf(s_error_msg, "CSV file is not in a writable mode"); return;
case EASYCSV_UNREADABLE: sprintf(s_error_msg, "CSV file is not in a readable mode"); return;
case EASYCSV_UPDATEFAIL: sprintf(s_error_msg, "CSV file has failed to update"); return;
case EASYCSV_UPDATETEMPFAIL: sprintf(s_error_msg, "failed to update temp CSV file"); return;
case EASYCSV_FILEPTRFAIL: sprintf(s_error_msg, "failed to move FILE pointer"); return;
case EASYCSV_ROWNOTEXIST: sprintf(s_error_msg, "given row does not exist"); return;
case EASYCSV_COLNOTEXIST: sprintf(s_error_msg, "given column does not exist"); return;
case EASYCSV_PUSHCOLFAIL: sprintf(s_error_msg, "failed to push value under column"); return;
case EASYCSV_COLNUMFAIL: sprintf(s_error_msg, "failed to determine the column number of a value in the first row"); return;
case EASYCSV_FINDVALUEFAIL: sprintf(s_error_msg, "cannot find the value %s", error_msg); return;
default: sprintf(s_error_msg, "unknown error"); return;
}
}
char*
easycsv_get_error()
{
return s_error_msg;
}

13
src/easycsv_error.h

@ -1,9 +1,8 @@
#ifndef EASYCSV_ERROR
#define EASYCSV_ERROR
#ifndef EASYCSV_ERROR_H
#define EASYCSV_ERROR_H
/* Error flags */
typedef enum {
typedef enum EASYCSV_ERROR {
/* Generic errors */
EASYCSV_NOERROR, // no error
EASYCSV_NULLCSV, // easycsv* is NULL
@ -14,6 +13,7 @@ typedef enum {
EASYCSV_OVERMAXCOL, // int exceeds col limit
EASYCSV_ZEROROW,
EASYCSV_ZEROCOL,
EASYCSV_MEMALLOC, ///< memory allocation failure
/* File input/output errors */
EASYCSV_UNKNOWNIOMODE, // unknown file IO mode
@ -34,6 +34,11 @@ typedef enum {
EASYCSV_PUSHCOLFAIL, // push column value fail
EASYCSV_COLNUMFAIL, // column number retrieval fail
EASYCSV_READVALUEFAIL, // read value fail
EASYCSV_FINDVALUEFAIL, // find value fail
} EASYCSV_ERROR;
void
easycsv_error(EASYCSV_ERROR,
const char*);
#endif

270
src/easycsv_p.c

@ -0,0 +1,270 @@
#include "easycsv_p.h"
#include "easycsv_error.h"
/* 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; */
/* } */
/*** Accès ***/
int
easycsv_rows(const easycsv *csv)
{
if (easycsv_rewind(csv) < 0) return -1;
int rows = 1;
char c;