Separated private and public methods
This commit is contained in:
parent
83662a410e
commit
fc57b7639b
@ -1,132 +1,145 @@
|
|||||||
#ifndef EASYCSV_H
|
#ifndef EASYCSV_H
|
||||||
#define EASYCSV_H
|
#define EASYCSV_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "../src/_easycsv.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>
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
typedef struct _easycsv _easycsv;
|
typedef struct _easycsv _easycsv;
|
||||||
|
|
||||||
/* Public easycsv members */
|
/** Public easycsv members */
|
||||||
typedef struct easycsv {
|
typedef struct easycsv {
|
||||||
EASYCSV_MODE mode; // end users able to easily modify mode to their needs
|
EASYCSV_MODE mode;
|
||||||
_easycsv *_priv; // private members
|
_easycsv *_priv;
|
||||||
} easycsv;
|
} easycsv;
|
||||||
|
|
||||||
/*
|
/*** Constructors ***/
|
||||||
* ============================
|
|
||||||
* FUNCTION PROTOTYPES - PUBLIC
|
/**
|
||||||
* ============================
|
* 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*
|
||||||
easycsv_init(const char*,
|
easycsv_init(const char*,
|
||||||
const EASYCSV_MODE);
|
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*
|
||||||
easycsv_init_errormsg(const char*,
|
easycsv_init_errormsg(const char*,
|
||||||
const EASYCSV_MODE,
|
const EASYCSV_MODE,
|
||||||
const EASYCSV_ERRORMSG);
|
const EASYCSV_ERRORMSG);
|
||||||
|
|
||||||
/* (Destructor) Free easycsv memory */
|
/**
|
||||||
|
* Destroy easycsv structure
|
||||||
|
* @param[in] Pointer to easycsv stucture
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
easycsv_free(easycsv*);
|
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
|
int
|
||||||
easycsv_findvalue(const easycsv*,
|
easycsv_findvalue(const easycsv*,
|
||||||
const char*,
|
const char*,
|
||||||
unsigned int*,
|
unsigned int*,
|
||||||
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
|
int
|
||||||
easycsv_findnumvalue(const easycsv*,
|
easycsv_findnumvalue(const easycsv*,
|
||||||
const char*);
|
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
|
int
|
||||||
easycsv_sortrow(easycsv*,
|
easycsv_sortrow(easycsv*,
|
||||||
const char*,
|
const char*,
|
||||||
const EASYCSV_SORT);
|
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
|
int
|
||||||
easycsv_sortcolumn(easycsv*,
|
easycsv_sortcolumn(easycsv*,
|
||||||
const char*,
|
const char*,
|
||||||
const EASYCSV_SORT);
|
const EASYCSV_SORT);
|
||||||
|
|
||||||
/* Append to CSV files */
|
/*** Modifications, insert ***/
|
||||||
int
|
|
||||||
easycsv_appendcsv(easycsv*,
|
|
||||||
easycsv*);
|
|
||||||
|
|
||||||
int
|
int
|
||||||
easycsv_compress(easycsv*);
|
easycsv_insertrow(easycsv*,
|
||||||
|
const char*,
|
||||||
/* READ VALUE */
|
const int);
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
/* Insert string in a specific cell */
|
/* Insert string in a specific cell */
|
||||||
int
|
int
|
||||||
@ -158,7 +171,7 @@ easycsv_insertcolumnvaluemode(easycsv*,
|
|||||||
const char*,
|
const char*,
|
||||||
const EASYCSV_VALMODE);
|
const EASYCSV_VALMODE);
|
||||||
|
|
||||||
/* PUSH VALUE */
|
/* Modifications, push */
|
||||||
|
|
||||||
/* Create new column on the RHS of an existing one */
|
/* Create new column on the RHS of an existing one */
|
||||||
int
|
int
|
||||||
@ -171,7 +184,7 @@ easycsv_pushcolumnvalue(easycsv*,
|
|||||||
const char*,
|
const char*,
|
||||||
const char*);
|
const char*);
|
||||||
|
|
||||||
/* DELETE VALUES -- use INSERT VALUE with empty string*/
|
/* Modifications, delete */
|
||||||
|
|
||||||
/* Delete CSV value */
|
/* Delete CSV value */
|
||||||
int
|
int
|
||||||
@ -193,4 +206,16 @@ easycsv_deletecolumnstr(easycsv*,
|
|||||||
|
|
||||||
/* Delete named row */
|
/* Delete named row */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Modifications, append */
|
||||||
|
int
|
||||||
|
easycsv_appendcsv(easycsv*,
|
||||||
|
easycsv*);
|
||||||
|
|
||||||
|
/*** Modifications, miscellenaeous ***/
|
||||||
|
|
||||||
|
int
|
||||||
|
easycsv_compress(easycsv*);
|
||||||
|
|
||||||
#endif /* EASYCSV_H */
|
#endif /* EASYCSV_H */
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
lib_LTLIBRARIES = libeasycsv.la
|
lib_LTLIBRARIES = libeasycsv.la
|
||||||
libeasycsv_la_SOURCES = easycsv.c
|
libeasycsv_la_SOURCES = \
|
||||||
|
_easycsv.c \
|
||||||
|
_easycsv.h \
|
||||||
|
easycsv.c
|
||||||
include_HEADERS = ../include/easycsv.h
|
include_HEADERS = ../include/easycsv.h
|
||||||
|
506
src/_easycsv.c
Normal file
506
src/_easycsv.c
Normal file
@ -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;
|
||||||
|
}
|
178
src/_easycsv.h
Normal file
178
src/_easycsv.h
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
#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
|
719
src/easycsv.c
719
src/easycsv.c
@ -1,185 +1,8 @@
|
|||||||
|
#include "_easycsv.h"
|
||||||
#include "../include/easycsv.h"
|
#include "../include/easycsv.h"
|
||||||
|
|
||||||
/* Generic type definitions for internal use */
|
// typedef struct _easycsv _easycsv;
|
||||||
|
// _easycsv* _easycsv_priv_init(const char *fp, const EASYCSV_MODE mode, const EASYCSV_ERRORMSG error);
|
||||||
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 == */
|
|
||||||
|
|
||||||
/* CONSTRUCTORS AND DESTRUCTORS */
|
/* CONSTRUCTORS AND DESTRUCTORS */
|
||||||
|
|
||||||
@ -248,7 +71,7 @@ easycsv_readvalue(const easycsv *csv,
|
|||||||
}
|
}
|
||||||
/* END ARGS CHECK */
|
/* END ARGS CHECK */
|
||||||
|
|
||||||
char *str = _easycsv_getrow(csv, row);
|
char *str = _easycsv_getrow(csv->_priv, row);
|
||||||
if (str == NULL) {
|
if (str == NULL) {
|
||||||
_easycsv_printerror(csv->_priv, EASYCSV_ROWNOTEXIST);
|
_easycsv_printerror(csv->_priv, EASYCSV_ROWNOTEXIST);
|
||||||
_easycsv_printerror(csv->_priv, EASYCSV_READVALUEFAIL);
|
_easycsv_printerror(csv->_priv, EASYCSV_READVALUEFAIL);
|
||||||
@ -270,7 +93,7 @@ easycsv_readcolumnvalue(const easycsv *csv,
|
|||||||
const unsigned int row)
|
const unsigned int row)
|
||||||
{
|
{
|
||||||
/* ARGS CHECK */
|
/* ARGS CHECK */
|
||||||
if (_easycsv_checkcsvandstring_one(csv, col) < 0)
|
if (_easycsv_checkcsvandstring_one(csv->_priv, col) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (row > csv->_priv->rows) {
|
if (row > csv->_priv->rows) {
|
||||||
@ -279,7 +102,7 @@ easycsv_readcolumnvalue(const easycsv *csv,
|
|||||||
}
|
}
|
||||||
/* END ARGS CHECK */
|
/* END ARGS CHECK */
|
||||||
|
|
||||||
int i = _easycsv_getcolumn(csv, col);
|
int i = _easycsv_getcolumn(csv->_priv, col);
|
||||||
if (i < 1) {
|
if (i < 1) {
|
||||||
_easycsv_printerror(csv->_priv, EASYCSV_COLNUMFAIL);
|
_easycsv_printerror(csv->_priv, EASYCSV_COLNUMFAIL);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -319,7 +142,7 @@ easycsv_insertvaluemode(easycsv *csv,
|
|||||||
const EASYCSV_VALMODE valmode)
|
const EASYCSV_VALMODE valmode)
|
||||||
{
|
{
|
||||||
/* ARGS CHECK */
|
/* ARGS CHECK */
|
||||||
if (_easycsv_checkcsvandstring_one(csv, val) < 0)
|
if (_easycsv_checkcsvandstring_one(csv->_priv, val) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (col == 0) {
|
if (col == 0) {
|
||||||
@ -337,7 +160,7 @@ easycsv_insertvaluemode(easycsv *csv,
|
|||||||
if (row > csv->_priv->rows) {
|
if (row > csv->_priv->rows) {
|
||||||
}
|
}
|
||||||
|
|
||||||
char *rowstr = _easycsv_getrow(csv, row);
|
char *rowstr = _easycsv_getrow(csv->_priv, row);
|
||||||
if (rowstr == NULL)
|
if (rowstr == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -415,7 +238,7 @@ easycsv_insertvaluemode(easycsv *csv,
|
|||||||
|
|
||||||
/* Copy rows before newstr in csv to temp */
|
/* Copy rows before newstr in csv to temp */
|
||||||
for (unsigned int i = 1; i < row; i++) {
|
for (unsigned int i = 1; i < row; i++) {
|
||||||
str = _easycsv_getrow(csv, i);
|
str = _easycsv_getrow(csv->_priv, i);
|
||||||
if (col > csv->_priv->cols) {
|
if (col > csv->_priv->cols) {
|
||||||
str = realloc(str, strlen(str) + commas + 1);
|
str = realloc(str, strlen(str) + commas + 1);
|
||||||
for (size_t j = 0; j < commas; j++) {
|
for (size_t j = 0; j < commas; j++) {
|
||||||
@ -464,7 +287,7 @@ easycsv_insertvaluemode(easycsv *csv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update csv */
|
/* Update csv */
|
||||||
if (_easycsv_update(csv) < 0)
|
if (_easycsv_update(csv->_priv) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* END UPDATE CSV */
|
/* END UPDATE CSV */
|
||||||
@ -492,7 +315,7 @@ easycsv_insertcolumnvaluemode(easycsv *csv,
|
|||||||
const EASYCSV_VALMODE valmode)
|
const EASYCSV_VALMODE valmode)
|
||||||
{
|
{
|
||||||
/* ARGS CHECK */
|
/* ARGS CHECK */
|
||||||
if (_easycsv_checkcsvandstring_two(csv, col, val) < 0)
|
if (_easycsv_checkcsvandstring_two(csv->_priv, col, val) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (row == 0) {
|
if (row == 0) {
|
||||||
@ -501,7 +324,7 @@ easycsv_insertcolumnvaluemode(easycsv *csv,
|
|||||||
}
|
}
|
||||||
/* END ARGS CHECK */
|
/* END ARGS CHECK */
|
||||||
|
|
||||||
int colnum = _easycsv_getcolumn(csv, col);
|
int colnum = _easycsv_getcolumn(csv->_priv, col);
|
||||||
if (colnum < 0) {
|
if (colnum < 0) {
|
||||||
_easycsv_printerror(csv->_priv, EASYCSV_COLNUMFAIL);
|
_easycsv_printerror(csv->_priv, EASYCSV_COLNUMFAIL);
|
||||||
return -1;
|
return -1;
|
||||||
@ -517,7 +340,7 @@ easycsv_pushcolumn(easycsv *csv,
|
|||||||
const char *col)
|
const char *col)
|
||||||
{
|
{
|
||||||
/* ARGS CHECK */
|
/* ARGS CHECK */
|
||||||
if (_easycsv_checkcsvandstring_one(csv, col) < 0)
|
if (_easycsv_checkcsvandstring_one(csv->_priv, col) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
/* END ARGS CHECK */
|
/* END ARGS CHECK */
|
||||||
|
|
||||||
@ -539,7 +362,7 @@ easycsv_pushcolumn(easycsv *csv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Grab first row */
|
/* Grab first row */
|
||||||
char *str = _easycsv_getrow(csv, 1);
|
char *str = _easycsv_getrow(csv->_priv, 1);
|
||||||
char *pch = NULL;
|
char *pch = NULL;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
@ -586,11 +409,11 @@ easycsv_pushcolumnvalue(easycsv *csv,
|
|||||||
const char *val)
|
const char *val)
|
||||||
{
|
{
|
||||||
/* ARGS CHECK */
|
/* ARGS CHECK */
|
||||||
if (_easycsv_checkcsvandstring_two(csv, col, val) < 0)
|
if (_easycsv_checkcsvandstring_two(csv->_priv, col, val) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
/* ARGS CHECK */
|
/* ARGS CHECK */
|
||||||
|
|
||||||
int colnum = _easycsv_getcolumn(csv, col);
|
int colnum = _easycsv_getcolumn(csv->_priv, col);
|
||||||
if (colnum < 0) {
|
if (colnum < 0) {
|
||||||
_easycsv_printerror(csv->_priv, EASYCSV_COLNUMFAIL);
|
_easycsv_printerror(csv->_priv, EASYCSV_COLNUMFAIL);
|
||||||
return -1;
|
return -1;
|
||||||
@ -662,11 +485,11 @@ easycsv_deletecolumnstr(easycsv *csv,
|
|||||||
const char *col)
|
const char *col)
|
||||||
{
|
{
|
||||||
/* ARGS CHECK */
|
/* ARGS CHECK */
|
||||||
if (_easycsv_checkcsvandstring_one(csv, col) < 0)
|
if (_easycsv_checkcsvandstring_one(csv->_priv, col) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
/* END ARGS CHECK */
|
/* END ARGS CHECK */
|
||||||
|
|
||||||
int colnum = _easycsv_getcolumn(csv, col);
|
int colnum = _easycsv_getcolumn(csv->_priv, col);
|
||||||
if (colnum < 0)
|
if (colnum < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -679,509 +502,3 @@ easycsV_deleterowint(easycsv *csv,
|
|||||||
{
|
{
|
||||||
return 0;
|
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;
|
|
||||||
}
|
|
||||||
|
39
src/easycsv_error.h
Normal file
39
src/easycsv_error.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user