Initial import of WIP records abstraction lib i began to make rtl_power mysql/sqlite/... compliant

This commit is contained in:
2020-07-25 14:05:03 +02:00
commit b5a105ea60
4 changed files with 317 additions and 0 deletions

179
src/mysql_backend.c Normal file
View File

@@ -0,0 +1,179 @@
/*
Copyright (c) 2020 Gérald Colangelo <gcolangelo@ospow.com>
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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "smart_records_internals.h"
//#include <mysql.h>
#define URI_SCHEME "mysql://user[:password]@host[:port]/db_name.table"
typedef struct mysql_uri {
char *host;
char *user;
char *passwd;
char *db;
char *table;
unsigned int port;
} mysql_uri_t;
void mysql_free_uri(mysql_uri_t * uri)
{
if (!uri)
return;
if (uri->host)
free(uri->host);
if (uri->user)
free(uri->user);
if (uri->passwd)
free(uri->passwd);
if (uri->db)
free(uri->db);
if (uri->table)
free(uri->table);
free(uri);
}
mysql_uri_t *mysql_parse_uri( /* MYSQL *mysql, */ const char *uri, char **error)
{
int conv;
mysql_uri_t *r=NULL;
char *p1=NULL, *p2=NULL, *p3=NULL, *tmp=NULL;
if(!uri) {
set_error_and_fails("URI can't be null");
}
r = malloc(sizeof(mysql_uri_t));
memset(r,0,sizeof(mysql_uri_t));
/* Split the URI in 3 group: identifier, host identifier, db identifier */
conv = sscanf(uri, "mysql://%m[^@]@%m[^/]/%ms", &p1, &p2, &p3);
if (conv != 3) {
set_error_and_fails("URI doesn't respect the scheme");
}
/* Parse identifier */
/* We consider that 'login:' stands for empty password */
/* XXX: there's a leak here when : is present. Must fix !*/
conv = sscanf(p1, "%m[^:]%m[:]%ms", &r->user, &tmp, &r->passwd);
if (!conv) {
set_error_and_fails("Bad URI: no identifier provided");
}
else if (conv == 1) {
#ifdef _WITH_INTERACTIVE_TERMINAL // XXX: is there a way to detect this at runtime ?
char *tmp = malloc(128);
size_t n = 128, read;
fprintf(stdout, "Please, enter password for connection to %s\n", uri);
read = getline(&tmp, &n, stdin);
if (read >= 1)
/* Remove trailing \n */
r->passwd = strndup(tmp, strlen(tmp) - 1);
free(tmp);
#else
set_error_and_fails("No password provided and built without support of INTERACTIVE_TERMINAL");
#endif
}
free(p1);
p1 = NULL;
/* Parse host identifier */
conv = sscanf(p2, "%m[^:]:%d", &r->host, &r->port);
if (!conv) {
set_error_and_fails("Bad URI: need a port number after host:");
}
else if (conv == 1) {
r->port = 3306;
}
free(p2);
p2 = NULL;
/* Par db identifier */
conv = sscanf(p3, "%m[^.].%ms", &r->db, &r->table);
if (conv != 2) {
set_error_and_fails("Bad URI: need a database.table syntax");
}
free(p3);
p3 = NULL;
return r;
failed:
if (tmp)
free(tmp);
if (r)
mysql_free_uri(r);
if (p1)
free(p1);
if (p2)
free(p2);
if (p3)
free(p3);
return NULL;
}
#ifdef _TEST
char *tests[7][2] = {
{ "Every info provided",
"mysql://leon:bruxelles@lafrite:1024/STOCK_PATATE.avril" },
/*
{ "Every info provided except password",
"mysql://leon@lafrite:1024/STOCK_PATATE.avril" },
*/
{ "Every info provided but empty password",
"mysql://leon:@lafrite:1024/STOCK_PATATE.avril" },
{ "Every info provided except port number",
"mysql://leon:coin@lafrite/STOCK_PATATE.avril" },
/*
{ "Bad URI #1", "mysql://lafrite/PATATE.avril" },
{ "Bad URI #1", "mysql://lafrite/" },
*/
{ NULL, NULL },
};
int main(int ac, char **av)
{
mysql_uri_t *r;
char *error = NULL;
int i = 0;
while (tests[i][0]) {
printf("## %s ##\nURI: %s\nResult:\n", tests[i][0], tests[i][1]);
r = mysql_parse_uri(tests[i][1], &error);
if (r) {
printf("\tr->host=%s\n\tr->port=%d\n\tr->user=%s\n\tr->password=%s\n\tr->db=%s\n\tr->table=%s\n",
r->host, r->port, r->user, r->passwd, r->db, r->table);
mysql_free_uri(r);
} else {
if(error) {
printf("mysql_parse_uri : got error %s !\n", error);
free(error);
}
}
i++;
}
}
#endif

18
src/mysql_backend.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef _SMART_RECORDS_MYSQL_BACKEND_H
#define _SMART_RECORDS_MYSQL_BACKEND_H
#include <stdarg.h>
#include "smart_records_internals.h"
//#include <mysql.h>
typedef struct mysql_backend_ctx_t {
//MYSQL *mysql;
char *format;
} mysql_backend_ctx_t;
int mysql_backend_write_record(smart_records_ctx_t *ctx, char **error, va_list ap);
int mysql_backend_set_format(smart_records_ctx_t *ctx, char **error, char *format);
int mysql_backend_close_records_base(smart_records_ctx_t *ctx);
void *mysql_backend_init(smart_records_ctx_t *ctx, char **error);
#endif

108
src/smart_records.c Normal file
View File

@@ -0,0 +1,108 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "smart_records.h"
#include "smart_records_internals.h"
#ifdef _HAS_MYSQL
#include "mysql_backend.h"
#endif
#ifdef _HAS_SQLITE
#include "sqlite_backend.h"
#endif
#ifdef _HAS_UDP
#include "udp_backend.h"
#endif
#ifdef _HAS_CSV
#include "csv_backend.h"
#endif
// nothing but give a context for the moment
smart_records_ctx_t *smart_records_init(){
return malloc(sizeof(smart_records_ctx_t));
}
int smart_records_open_base(smart_records_ctx_t *ctx, char *uri, char **error)
{
int len_uri;
if(!uri) {
set_error_and_fails("URI is null");
}
len_uri = strlen(uri);
if(!strncmp("mysql://", uri, len_uri < 8 ? len_uri : 8)) {
#ifdef _HAS_MYSQL
ctx->CTX = malloc(sizeof(mysql_backend_ctx_t));
ctx->write_record = mysql_backend_write_record;
ctx->set_format = mysql_backend_set_format;
ctx->close_records_base = mysql_backend_close_records_base;
if ( mysql_backend_init(ctx->CTX, error) < 0)
goto failed;
#else
set_error_and_fails("built without support for mysql:// URIs");
goto failed;
#endif
}
else if(!strncmp("sqlite://", uri, len_uri < 9 ? len_uri : 9)) {
#ifdef _HAS_SQLITE
ctx->CTX = malloc(sizeof(sqlite_backend_ctx_t));
ctx->write_record = sqlite_backend_write_record(char *uri);
ctx->close_records_base = sqlite_backend_close_records_base(char *uri);
if ( sqlite_backend_init(ctx->CTX, error) < 0)
goto failed;
#else
if(error) *error = strdup("built without support for sqlite:// URIs");
goto failed;
}
#endif
else if(!strncmp("udp://", uri, len_uri < 8 ? len_uri : 8)) {
#ifdef _HAS_UDP
ctx->CTX = malloc(sizeof(udp_backend_ctx_t));
ctx->write_record = udp_backend_write_record(char *uri);
ctx->close_records_base = udp_backend_close_records_base(char *uri);
if ( udp_backend_init(ctx->CTX, error) < 0)
goto failed;
#else
if(error) *error = strdup("built without support for udp:// URIs");
goto failed;
}
#endif
else if(!strncmp("csv://", uri, len_uri < 8 ? len_uri : 8)) {
#ifdef _HAS_CSV
ctx->CTX = malloc(sizeof(csv_backend_ctx_t));
ctx->write_record = csv_backend_write_record(char *uri);
ctx->close_records_base = csv_backend_close_records_base(char *uri);
if ( csv_backend_init(ctx->CTX, error) < 0)
goto failed;
#else
if(error) *error = strdup("built without suppor fort csv:// URIs");
goto failed;
#endif
}
else {
if(error) *error = strdup("Unknown scheme or bad URI.");
goto failed;
}
return 0;
failed:
return -1;
}
int smart_records_close_base(smart_records_ctx_t *ctx)
{
return ctx->close_records_base(ctx);
}
int smart_records_write(smart_records_ctx_t *ctx, char **error, va_list ap)
{
return ctx->write_record(ctx, error, ap);
}

12
src/smart_records.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef _SMART_RECORDS_H
#define _SMART_RECORDS_H
#include <stdarg.h>
#include "smart_records_internals.h"
smart_records_ctx_t *smart_records_init();
int smart_records_open_base(smart_records_ctx_t *ctx, char *uri, char **error);
int smart_records_set_format(smart_records_ctx_t *ctx, char *fmt, char **error);
int smart_records_write(smart_records_ctx_t *ctx, char **error, va_list ap);
int smart_records_close_base(smart_records_ctx_t *ctx);
#endif