diff --git a/src/csv_backend/Makefile b/src/csv_backend/Makefile new file mode 100644 index 0000000..cd2cc1e --- /dev/null +++ b/src/csv_backend/Makefile @@ -0,0 +1,15 @@ +CFLAGS=-ggdb -Wall + +all: test csv_backend.a + +clean: + rm -f *.o *.a csv_backend_test + +test: csv_backend_test + +csv_backend.a: csv_backend.o + $(AR) -rcv $@ $? + +csv_backend_test: csv_backend.c + $(CC) $(CFLAGS) -D_TEST -o $@ $? + diff --git a/src/csv_backend/csv_backend.a b/src/csv_backend/csv_backend.a new file mode 100644 index 0000000..089731b Binary files /dev/null and b/src/csv_backend/csv_backend.a differ diff --git a/src/csv_backend/csv_backend.c b/src/csv_backend/csv_backend.c new file mode 100644 index 0000000..bbf3f91 --- /dev/null +++ b/src/csv_backend/csv_backend.c @@ -0,0 +1,179 @@ +/* +Copyright (c) 2020 Gérald Colangelo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../smart_records_internals.h" +#include "csv_backend_internals.h" + +void *csv_backend_init(char **error) +{ + csv_backend_ctx_t *ctx=NULL; + ctx = malloc(sizeof(csv_backend_ctx_t)); + memset(ctx, 0, sizeof(csv_backend_ctx_t)); + ctx->mode = 0644; + ctx->fmt = NULL; + ctx->pathname = NULL; + return ctx; +} + +int csv_backend_open_records_base(void *ctx, char **error, const char *uri) +{ + csv_backend_ctx_t *c; + if (!ctx || !uri) { + set_error_and_fails("invalid arguments while opening records base"); + } + c = (csv_backend_ctx_t *)ctx; + + // XXX: Implement mode parsing example: csv://: + c->pathname = strdup(strchr(uri,':')+1); + c->fd = open(c->pathname, O_CREAT|O_APPEND|O_WRONLY, c->mode); + if (c->fd < 0) { + /* And then, we're not POSIX anymore */ +#define _GNU_SOURCE + asprintf(error,"failed opening CSV file: %s", strerror(errno)); + goto failed; + } + return 0; +failed: + return -1; +} + +int csv_backend_set_format(void *ctx, char **error, const char *fmt) +{ + csv_backend_ctx_t *c; + if (!ctx || !fmt) { + set_error_and_fails("invalid parameters while setting format.") + } + c = (csv_backend_ctx_t *) ctx; + c->fmt = strdup(fmt); + return 0; +failed: + return -1; +} + +int csv_backend_write_record(void *ctx, char **error, ...) +{ + csv_backend_ctx_t *c; + int size=0; + va_list ap; + + if (!ctx) { + set_error_and_fails("invalid parameters while setting format.") + } + c = (csv_backend_ctx_t *) ctx; + + if (!c->fmt) { + set_error_and_fails("no format provided, please set it before writing any record"); + } + + va_start(ap,error); + size = vsnprintf(NULL, size, c->fmt, ap); + va_end(ap); + + va_start(ap,error); + if (vdprintf(c->fd, c->fmt, ap) != size) { + set_error_and_fails("vdprintf() failed"); + } + va_end(ap); + + return 0; +failed: + return -1; +} + +int csv_backend_close_records_base(void *ctx) +{ + csv_backend_ctx_t *c; + if(!ctx) + return -1; + c = (csv_backend_ctx_t *)ctx; + + if(c->fd > 0) + close(c->fd); + if(c->pathname) + free(c->pathname); + if(c->fmt) + free(c->fmt); + free(c); + + return 0; +} + + + +#ifdef _TEST + +#define dump_error_and_quit(func,error) \ + { \ + if (error) { \ + fprintf(stderr, "[ERROR] %s(): %s\n", func, error); \ + } else { \ + fprintf(stderr, "[ERROR] %s(): unknown error\n", func); \ + } \ + free(error); \ + exit(EXIT_FAILURE); \ + } + + +int main(int ac, char **av) +{ + void *ctx; + char *error=NULL; + int i=0; + + if(ac != 2) { + printf("Usage: %s \n \ + mysql_uri format is mysql://user[:password]@host[:port]/database.table\n \ + database shall exists and table must obey the following scheme:\n \ + CREATE TABLE (a INT, b INT, c VARCHAR(40))\n",av[0]); + exit(EXIT_FAILURE); + } + + ctx = csv_backend_init(&error); + if (ctx == NULL) { + dump_error_and_quit("csv_backend_init", error); + } + + if (csv_backend_set_format(ctx, &error, "%d;%d;%s;\n") < 0){ + dump_error_and_quit("csv_backend_set_format", error); + } + + if(csv_backend_open_records_base(ctx, &error, av[1]) < 0) { + dump_error_and_quit("csv_backend_set_open_records_base", error); + } + + for (i=0; i<4; i++) { + if (csv_backend_write_record(ctx, &error, i, i+10, "Text here") <0 ){ + dump_error_and_quit("csv_backend_write_record", error); + } + } + csv_backend_close_records_base(ctx); +} +#endif diff --git a/src/csv_backend/csv_backend.h b/src/csv_backend/csv_backend.h new file mode 100644 index 0000000..8fbcb4a --- /dev/null +++ b/src/csv_backend/csv_backend.h @@ -0,0 +1,13 @@ +#ifndef _SMART_RECORDS_CSV_BACKEND_H +#define _SMART_RECORDS_CSV_BACKEND_H + +#include + + +void *csv_backend_init(char **error); +int csv_backend_open_records_base(void *ctx, char **error, const char *uri); +int csv_backend_write_record(void *ctx, char **error, va_list ap); +int csv_backend_set_format(void *ctx, char **error, const char *format); +int csv_backend_close_records_base(void *ctx); + +#endif diff --git a/src/csv_backend/csv_backend.o b/src/csv_backend/csv_backend.o new file mode 100644 index 0000000..e0a99f3 Binary files /dev/null and b/src/csv_backend/csv_backend.o differ diff --git a/src/csv_backend/csv_backend_internals.h b/src/csv_backend/csv_backend_internals.h new file mode 100644 index 0000000..28facbb --- /dev/null +++ b/src/csv_backend/csv_backend_internals.h @@ -0,0 +1,11 @@ +#ifndef CSV_BACKEND_INTERNALS_H +#define CSV_BACKEND_INTERNALS_H + +typedef struct csv_backend_ctx_t { + int fd; + char *pathname; + char *fmt; + int mode; +} csv_backend_ctx_t; + +#endif diff --git a/src/csv_backend/csv_backend_test b/src/csv_backend/csv_backend_test new file mode 100755 index 0000000..9e55325 Binary files /dev/null and b/src/csv_backend/csv_backend_test differ