Created a WHERE query builder and implemented a TYPE to char * method for database values

This commit is contained in:
2020-09-23 13:08:06 +01:00
parent f15017501c
commit 18490c014a
7 changed files with 1243 additions and 0 deletions

View File

@@ -6,6 +6,8 @@
#include "db_transaction.h"
#include "db_column.h"
#include "db_query.h"
#include "db_value.h"
#include "db_where-builder.h"
void sessionEnd(void);

188
src/db_value.c Normal file
View File

@@ -0,0 +1,188 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
#include <errno.h>
#include <mysql.h>
#include "strext.h"
#include "db_value.h"
char *db_value(char **str, size_t *len, e_column_type type, uint32_t n_args, ...)
{
va_list args;
char *ret;
va_start(args, n_args);
ret = db_value_va(str, len, type, n_args, args);
va_end(args);
return ret;
}
char *db_value_va(char **str, size_t *len, e_column_type type, uint32_t n_args, va_list args)
{
char buf[32], *tmp_str = 0, *esc_str = 0;
size_t tmp_len = 0, esc_len = 0;
MYSQL *sql;
if (n_args == 0) {
return 0;
}
memset(buf, 0, 32);
switch(type) {
case TYPE_BOOL:
{
sprintf(buf, "%s", va_arg(args, int) == 0 ? "FALSE" : "TRUE");
break;
}
case TYPE_INT8:
{
vsprintf(buf, "%"PRIi8, args);
break;
}
case TYPE_UINT8:
{
vsprintf(buf, "%"PRIu8, args);
break;
}
case TYPE_INT16:
{
vsprintf(buf, "%"PRIi16, args);
break;
}
case TYPE_UINT16:
{
vsprintf(buf, "%"PRIu16, args);
break;
}
case TYPE_INT32:
{
vsprintf(buf, "%"PRIi32, args);
break;
}
case TYPE_TIMESTAMP:
case TYPE_UINT32:
{
vsprintf(buf, "%"PRIu32, args);
break;
}
case TYPE_INT64:
{
vsprintf(buf, "%"PRIi64, args);
break;
}
case TYPE_UINT64:
{
vsprintf(buf, "%"PRIu64, args);
break;
}
case TYPE_FLOAT:
{
vsprintf(buf, "%f", args);
break;
}
case TYPE_DOUBLE:
{
vsprintf(buf, "%lf", args);
break;
}
case TYPE_STRING:
{
tmp_str = va_arg(args, char *);
if (n_args == 1) {
tmp_len = strlen(tmp_str);
} else {
tmp_len = va_arg(args, size_t);
}
__attribute__((fallthrough));
}
case TYPE_BLOB:
{
if (tmp_str == 0) {
tmp_str = (char *)va_arg(args, void *);
tmp_len = va_arg(args, size_t);
}
if (tmp_str == 0) {
esc_str = (char *)malloc(5);
if (esc_str == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
memcpy(esc_str, "NULL", 4);
esc_str[4] = '\0';
esc_len = 4;
break;
}
sql = mysql_init(NULL);
if (sql == 0) {
fprintf(stderr, "[%d]mysql_init: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
esc_str = (char *)malloc(tmp_len * 2 + 1 + 2);
if (esc_str == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
mysql_close(sql);
return 0;
}
esc_str[0] = '\'';
esc_len = mysql_real_escape_string(sql, esc_str + 1, tmp_str, tmp_len);
esc_str[esc_len + 1] = '\'';
esc_str[esc_len + 2] = '\0';
esc_len += 2;
mysql_close(sql);
tmp_str = esc_str;
esc_str = (char *)realloc(esc_str, esc_len + 1);
if (esc_str == 0) {
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
break;
}
case TYPE_RAW:
{
tmp_str = va_arg(args, char *);
tmp_len = va_arg(args, size_t);
esc_str = (char *)malloc(tmp_len + 1);
if (esc_str == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
memcpy(esc_str, tmp_str, tmp_len);
esc_str[tmp_len] = '\0';
break;
}
}
if (esc_str == 0) {
if (strmemcpy(buf, strlen(buf), &esc_str, &esc_len) != 0) {
return 0;
}
}
if (str != 0) {
*str = esc_str;
*len = esc_len;
}
return esc_str;
}

9
src/db_value.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef H__DB_VALUE__
#define H__DB_VALUE__
#include "db_column.h"
char *db_value(char **str, size_t *len, e_column_type type, uint32_t n_args, ...);
char *db_value_va(char **str, size_t *len, e_column_type type, uint32_t n_args, va_list args);
#endif // H__DB_VALUE__

719
src/db_where-builder.c Normal file
View File

@@ -0,0 +1,719 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include "db_where-builder.h"
#include "db_connection.h"
#include "db_value.h"
#include "strext.h"
struct where_logic_t {
where_builder *up;
e_where_logic logic_type;
where_builder **constructs;
size_t n_constructs;
size_t n_alloc;
};
typedef struct where_logic_t where_logic;
struct where_clause_t {
where_builder *up;
e_where_logic logic_type;
// Table
char *table;
size_t table_len;
// Column
char *col;
size_t col_len;
// Op
e_where_op op;
// Values
char **values;
size_t *values_len;
size_t n_values;
size_t n_alloc;
};
typedef struct where_clause_t where_clause;
// private:
void freeLogic(where_logic **logic_ptr)
{
where_logic *logic;
where_builder *construct;
logic = *logic_ptr;
while (logic->n_constructs > 0) {
construct = logic->constructs[logic->n_constructs - 1];
construct->up = 0;
destroyWhereBuilder(&construct);
logic->n_constructs--;
}
if (logic->constructs != 0) {
free(logic->constructs);
logic->constructs = 0;
}
free(*logic_ptr);
*logic_ptr = 0;
}
where_logic *createLogic(e_where_logic type, size_t initial_size)
{
where_logic *logic = (where_logic *)malloc(sizeof(where_logic));
if (logic == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
memset(logic, 0, sizeof(where_logic));
logic->logic_type = type;
if (initial_size == 0) {
return logic;
}
logic->constructs = (where_builder **)malloc(sizeof(where_builder *) * initial_size);
if (logic->constructs == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
freeLogic(&logic);
return 0;
}
memset(logic->constructs, 0, sizeof(where_builder *) * initial_size);
logic->n_constructs = 0;
logic->n_alloc = initial_size;
return logic;
}
where_builder *appendClause(where_builder *wb, where_builder *wb_clause)
{
where_logic *logic = (where_logic *)wb;
where_builder **old_ptr;
size_t new_size;
if (wb_clause == 0) {
return wb;
}
if (!(wb->logic_type == AND || wb->logic_type == OR)) {
fprintf(stderr, "[%d]appendClause: Where-builder stack corrupted!\n", __LINE__);
return wb;
}
if (logic->n_constructs == logic->n_alloc) {
old_ptr = (where_builder **)logic->constructs;
new_size = sizeof(where_builder *) * (logic->n_alloc + 1);
logic->constructs = (where_builder **)realloc(logic->constructs, new_size);
if (logic->constructs == 0) {
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
logic->constructs = old_ptr;
return wb;
}
logic->n_alloc++;
}
logic->constructs[logic->n_constructs] = wb_clause;
logic->n_constructs++;
wb_clause->up = (where_builder *)logic;
return wb;
}
int ensureValueSize(where_clause *clause, size_t new_size)
{
size_t *old_lens;
char **old_values;
if (clause->n_alloc >= new_size) {
return 0;
}
old_values = clause->values;
clause->values = (char **)realloc(clause->values, sizeof(char *) * new_size);
if (clause->values == 0) {
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
clause->values = old_values;
return 1;
}
old_lens = clause->values_len;
clause->values_len = (size_t *)realloc(clause->values_len, sizeof(size_t) * new_size);
if (clause->values_len == 0) {
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
clause->values_len = old_lens;
return 1;
}
(clause->n_alloc)++;
return 0;
}
where_clause *createWhere(const char *tbl, const char *col, e_where_op op)
{
where_clause *clause;
clause = (where_clause *)malloc(sizeof(where_clause));
if (clause == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
memset(clause, 0, sizeof(where_clause));
clause->logic_type = CLAUSE;
clause->op = op;
if (tbl != 0) {
if (strmemcpy(tbl, strlen(tbl), &clause->table, &clause->table_len) != 0) {
freeWhere((where_builder **)&clause);
return 0;
}
}
if (strmemcpy(col, strlen(col), &clause->col, &clause->col_len) != 0) {
freeWhere((where_builder **)&clause);
return 0;
}
clause->values = (char **)malloc(sizeof(char *));
clause->values_len = (size_t *)malloc(sizeof(size_t));
if (clause->values == 0 || clause->values_len == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
freeWhere((where_builder **)&clause);
return 0;
}
clause->n_alloc = 1;
return clause;
}
where_builder *where_And_Or(where_builder *wb, where_builder *wb_clause, e_where_logic and_or)
{
where_logic *logic;
if (wb == 0) {
wb = (where_builder *)createLogic(and_or, 2);
if (wb == 0) {
return wb_clause;
}
}
switch(wb->logic_type) {
case UNK:
{
if ((logic = createLogic(and_or, 2)) == 0) {
destroyWhereBuilder(&wb_clause);
return wb;
}
free(wb);
if (wb_clause != 0) {
logic->constructs[0] = wb_clause;
logic->n_constructs++;
wb_clause->up = (where_builder *)logic;
}
wb = (where_builder *)logic;
break;
}
case CLAUSE:
{
if ((logic = createLogic(and_or, 2)) == 0) {
destroyWhereBuilder(&wb_clause);
return wb;
}
logic->constructs[0] = wb;
logic->n_constructs++;
wb->up = (where_builder *)logic;
if (wb_clause != 0) {
logic->constructs[1] = wb_clause;
logic->n_constructs++;
wb_clause->up = (where_builder *)logic;
}
wb = (where_builder *)logic;
break;
}
case OR:
{
if (and_or == AND) {
if ((logic = createLogic(AND, 2)) == 0) {
destroyWhereBuilder(&wb_clause);
return wb;
}
if (whereOr(wb, (where_builder *)logic) == 0) {
freeLogic(&logic);
destroyWhereBuilder(&wb_clause);
return wb;
}
wb = appendClause((where_builder *)logic, wb_clause);
} else {
wb = appendClause(wb, wb_clause);
}
break;
}
case AND:
{
if (and_or == AND) {
wb = appendClause(wb, wb_clause);
} else {
if ((logic = createLogic(OR, 2)) == 0) {
destroyWhereBuilder(&wb_clause);
return wb;
}
if (whereAnd(wb, (where_builder *)logic) == 0) {
freeLogic(&logic);
destroyWhereBuilder(&wb_clause);
return wb;
}
wb = appendClause((where_builder *)logic, wb_clause);
}
break;
}
}
return wb;
}
where_builder *where_In_notIn_va(where_builder *wb, const char *tbl, const char *col, e_where_op op,
e_column_type type, uint32_t n_args, va_list args)
{
where_clause *clause;
where_builder *wb_clause;
if (wb == 0) {
return where_va(tbl, col, op, type, n_args, args);
}
switch (wb->logic_type) {
case UNK:
{
free(wb);
return where_va(tbl, col, op, type, n_args, args);
}
case CLAUSE:
{
clause = (where_clause *)wb;
if (clause->op != op
|| (tbl != 0 && clause->table == 0)
|| (tbl != 0 && clause->table != 0 && strcmp(clause->table, tbl) != 0)
|| (col != 0 && clause->col == 0)
|| (col != 0 && clause->col != 0 && strcmp(clause->col, col) != 0)) {
if (wb->up == 0) {
fprintf(stderr, "[%d]whereIn_notIn: Where-builder stack corrupted!\n", __LINE__);
return wb;
}
return where_In_notIn_va(wb->up, tbl, col, op, type, n_args, args);
}
return setWhereValue_va((where_builder *)clause, type, n_args, args);
}
case AND:
case OR:
{
if ((wb_clause = where_va(tbl, col, op, type, n_args, args)) == 0) {
return wb;
}
if (wb->logic_type == AND) {
whereAnd(wb, wb_clause);
} else {
whereOr(wb, wb_clause);
}
return wb_clause;
}
}
return wb;
}
where_builder *where_In_notIn(where_builder *wb, const char *tbl, const char *col, e_where_op op,
e_column_type type, uint32_t n_args, ...)
{
where_builder *ret;
va_list args;
va_start(args, n_args);
ret = where_In_notIn_va(wb, tbl, col, op, type, n_args, args);
va_end(args);
return ret;
}
// public:
where_builder *createWhereBuilder(where_builder *initial_clause)
{
if (initial_clause != 0) {
return initial_clause;
}
where_builder *wb = (where_builder *)malloc(sizeof(where_builder));
if (wb == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
memset(wb, 0, sizeof(where_builder));
return wb;
}
void destroyWhereBuilder(where_builder **wb_ptr)
{
where_builder *wb = finalizeWhere(*wb_ptr);
if (*wb_ptr == 0) {
return;
}
switch(wb->logic_type) {
case CLAUSE:
{
freeWhere(&wb);
break;
}
case OR:
case AND:
{
freeLogic((where_logic **)&wb);
break;
}
case UNK:
{
free(*wb_ptr);
break;
}
}
*wb_ptr = 0;
}
where_builder *where(const char *tbl, const char *col, e_where_op op, e_column_type type,
uint32_t n_args, ...)
{
va_list args;
where_builder *ret;
va_start(args, n_args);
ret = where_va(tbl, col, op, type, n_args, args);
va_end(args);
return ret;
}
where_builder *where_va(const char *tbl, const char *col, e_where_op op, e_column_type type,
uint32_t n_args, va_list args)
{
where_builder *wb_clause = (where_builder *)createWhere(tbl, col, op);
if (wb_clause == 0) {
return 0;
}
return setWhereValue_va(wb_clause, type, n_args, args);
}
void freeWhere(where_builder **wb_clause_ptr)
{
where_clause *clause = (where_clause *)(*wb_clause_ptr);
if (wb_clause_ptr == 0 || (*wb_clause_ptr)->logic_type != CLAUSE) {
fprintf(stderr, "[%d]freeWhere: Where-builder stack corrupted!\n", __LINE__);
return;
}
while (clause->n_values > 0) {
free(clause->values[clause->n_values - 1]);
clause->n_values--;
}
if (clause->values != 0) {
free(clause->values);
clause->values = 0;
}
if (clause->values_len != 0) {
free(clause->values_len);
clause->values_len = 0;
}
if (clause->col != 0) {
free(clause->col);
clause->col = 0;
}
if (clause->table) {
free(clause->table);
clause->table = 0;
}
free(clause);
*wb_clause_ptr = 0;
}
where_builder *clearWhereValue(where_builder *wb_clause)
{
where_clause *clause = (where_clause *)wb_clause;
if (wb_clause->logic_type != CLAUSE) {
fprintf(stderr, "[%d]clearWhereValue: Where-builder stack corrupted!\n", __LINE__);
return wb_clause;
}
while (clause->n_values > 0) {
clause->n_values--;
free(clause->values[clause->n_values]);
clause->values[clause->n_values] = 0;
clause->values_len[clause->n_values] = 0;
}
return wb_clause;
}
where_builder *setWhereValue(where_builder *wb_clause, e_column_type type, uint32_t n_args, ...)
{
va_list args;
where_builder *ret;
va_start(args, n_args);
ret = setWhereValue_va(wb_clause, type, n_args, args);
va_end(args);
return ret;
}
where_builder *setWhereValue_va(where_builder *wb_clause,
e_column_type type, uint32_t n_args, va_list args)
{
where_clause *clause = (where_clause *)wb_clause;
char *value;
size_t value_len;
if (wb_clause->logic_type != CLAUSE) {
fprintf(stderr, "[%d]setWhereValue: Where-builder stack corrupted!\n", __LINE__);
return wb_clause;
}
switch (clause->op) {
case EQ:
case NEQ:
case GT:
case GTE:
case LT:
case LTE:
{
clearWhereValue(wb_clause);
db_value_va(&value, &value_len, type, n_args, args);
if (value != 0) {
clause->values[clause->n_values] = value;
clause->values_len[clause->n_values] = value_len;
}
clause->n_values++;
break;
}
case IS_NULL:
case NOT_NULL:
{
break;
}
case IN:
case NOT_IN:
{
if (ensureValueSize(clause, clause->n_values + n_args) != 0) {
freeWhere(&wb_clause);
return 0;
}
for (uint32_t i = 0; i < n_args; i++) {
db_value_va(&value, &value_len, type, 1, args);
if (value != 0) {
clause->values[clause->n_values] = value;
clause->values_len[clause->n_values] = value_len;
}
clause->n_values++;
}
break;
}
}
return wb_clause;
}
where_builder *whereAnd(where_builder *wb, where_builder *wb_clause)
{
return where_And_Or(wb, wb_clause, AND);
}
where_builder *whereOr(where_builder *wb, where_builder *wb_clause)
{
return where_And_Or(wb, wb_clause, OR);
}
where_builder *whereIn(where_builder *wb, const char *tbl, const char *col,
e_column_type type, uint32_t n_args, ...)
{
where_builder *ret;
va_list args;
va_start(args, n_args);
ret = whereIn_va(wb, tbl, col, type, n_args, args);
va_end(args);
return ret;
}
where_builder *whereIn_va(where_builder *wb, const char *tbl, const char *col,
e_column_type type, uint32_t n_args, va_list args)
{
return where_In_notIn_va(wb, tbl, col, IN, type, n_args, args);
}
where_builder *whereNotIn(where_builder *wb, const char *tbl, const char *col,
e_column_type type, uint32_t n_args, ...)
{
where_builder *ret;
va_list args;
va_start(args, n_args);
ret = whereIn_va(wb, tbl, col, type, n_args, args);
va_end(args);
return ret;
}
where_builder *whereNotIn_va(where_builder *wb, const char *tbl, const char *col,
e_column_type type, uint32_t n_args, va_list args)
{
return where_In_notIn_va(wb, tbl, col, NOT_IN, type, n_args, args);
}
where_builder *whereNext(where_builder *wb)
{
if (wb->up == 0) {
fprintf(stderr, "[%d]whereEnd: Where-builder stack corrupted!\n", __LINE__);
return wb;
}
return wb->up;
}
where_builder *finalizeWhere(where_builder *wb)
{
while (wb->up != 0) {
wb = wb->up;
}
return wb;
}
int compileWhere(where_builder *wb, char **str, size_t *str_len)
{
where_logic *logic;
where_clause *clause;
struct str_builder_t *sb;
char *tmp;
size_t tmp_len;
size_t idx;
sb = strbld_create();
if (sb == 0) {
return -1;
}
switch(wb->logic_type) {
case UNK:
strbld_destroy(&sb);
return -1;
case CLAUSE:
{
clause = (where_clause *)wb;
// Column
if (clause->table != 0) {
strbld_char(sb, '`');
strbld_str(sb, clause->table, clause->table_len);
strbld_char(sb, '`');
strbld_char(sb, '.');
}
strbld_char(sb, '`');
strbld_str(sb, clause->col, clause->col_len);
strbld_char(sb, '`');
strbld_char(sb, ' ');
// Op
switch(clause->op) {
case EQ:
strbld_char(sb, '=');
break;
case NEQ:
strbld_char(sb, '!');
strbld_char(sb, '=');
break;
case GT:
strbld_char(sb, '>');
break;
case GTE:
strbld_char(sb, '>');
strbld_char(sb, '=');
break;
case LT:
strbld_char(sb, '<');
break;
case LTE:
strbld_char(sb, '<');
strbld_char(sb, '=');
break;
case IS_NULL:
strbld_str(sb, "IS NULL", 7);
break;
case NOT_NULL:
strbld_str(sb, "IS NOT NULL", 11);
break;
case IN:
strbld_str(sb, "IN(", 3);
break;
case NOT_IN:
strbld_str(sb, "NOT IN(", 7);
break;
}
// Value
for (idx = 0; idx < clause->n_values; idx++) {
strbld_char(sb, ' ');
strbld_str(sb, clause->values[idx], clause->values_len[idx]);
if (idx < clause->n_values - 1 && (clause->op == IN || clause->op == NOT_IN)) {
strbld_char(sb, ',');
}
}
if (clause->op == IN || clause->op == NOT_IN) {
strbld_char(sb, ' ');
strbld_char(sb, ')');
}
}
break;
case OR:
case AND:
{
logic = (where_logic *)wb;
if (logic->n_constructs == 0) {
break;
}
strbld_char(sb, '(');
for (size_t i = 0; i < logic->n_constructs; i++) {
if (compileWhere(logic->constructs[i], &tmp, &tmp_len) == 0) {
strbld_str(sb, tmp, tmp_len);
free(tmp);
}
if (i < (logic->n_constructs - 1)) {
strbld_str(sb, (wb->logic_type == OR ? " OR " : " AND "), (wb->logic_type == OR ? 4 : 5));
}
}
strbld_char(sb, ')');
break;
}
}
return strbld_finalize_or_destroy(&sb, str, str_len);
}

72
src/db_where-builder.h Normal file
View File

@@ -0,0 +1,72 @@
#ifndef DB_WHEREBUILDER_H
#define DB_WHEREBUILDER_H
#include <stddef.h>
#include "db_column.h"
enum e_where_logic_t {
UNK,
CLAUSE,
AND,
OR
};
enum e_where_op_t {
EQ,
NEQ,
GT,
GTE,
LT,
LTE,
IS_NULL,
NOT_NULL,
IN,
NOT_IN
};
struct where_builder_t {
struct where_builder_t *up;
enum e_where_logic_t logic_type;
};
typedef enum e_where_logic_t e_where_logic;
typedef enum e_where_op_t e_where_op;
typedef struct where_builder_t where_builder;
where_builder *createWhereBuilder(where_builder *initial_clause);
void destroyWhereBuilder(where_builder **wb_ptr);
where_builder *where(const char *tbl, const char *col, e_where_op op, e_column_type type,
uint32_t n_args, ...);
where_builder *where_va(const char *tbl, const char *col, e_where_op op, e_column_type type,
uint32_t n_args, va_list args);
void freeWhere(where_builder **wb_clause_ptr);
where_builder *clearWhereValue(where_builder *wb_clause);
where_builder *setWhereValue(where_builder *wb_clause, e_column_type type, uint32_t n_args, ...);
where_builder *setWhereValue_va(where_builder *wb_clause,
e_column_type type, uint32_t n_args, va_list args);
where_builder *whereAnd(where_builder *wb, where_builder *wb_clause);
where_builder *whereOr(where_builder *wb, where_builder *wb_clause);
where_builder *whereIn(where_builder *wb, const char *tbl, const char *col,
e_column_type type, uint32_t n_args, ...);
where_builder *whereIn_va(where_builder *wb, const char *tbl, const char *col,
e_column_type type, uint32_t n_args, va_list args);
where_builder *whereNotIn(where_builder *wb, const char *tbl, const char *col,
e_column_type type, uint32_t n_args, ...);
where_builder *whereNotIn_va(where_builder *wb, const char *tbl, const char *col,
e_column_type type, uint32_t n_args, va_list args);
where_builder *whereNext(where_builder *wb);
where_builder *finalizeWhere(where_builder *wb);
int compileWhere(where_builder *wb, char **str, size_t *str_len);
#endif // DB_WHEREBUILDER_H

221
src/strext.c Normal file
View File

@@ -0,0 +1,221 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include "strext.h"
size_t strlen_norm(const char *str, size_t str_len)
{
if (str == 0) {
return 0;
}
if (str_len == 0) {
return strlen(str);
}
while (str[str_len - 1] == '\0') {
str_len--;
}
return str_len;
}
int strmemcpy(const char *str, size_t str_len, char **new_str, size_t *new_len)
{
if (str == 0) {
return -1;
}
str_len = strlen_norm(str, str_len);
*new_str = (char *)malloc(str_len + 1);
if (*new_str == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return -errno;
}
memcpy(*new_str, str, str_len);
(*new_str)[str_len] = '\0';
(*new_len) = str_len;
return 0;
}
size_t strapp(char **out, const char *a, size_t a_len)
{
size_t s_len;
if (a[a_len - 1] == '\0') {
a_len -= 1;
}
if (*out == 0) {
s_len = 0;
*out = (char *)malloc(a_len + 1);
if (*out == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
} else {
s_len = strlen(*out);
*out = (char *)realloc(*out, s_len + a_len + 1);
if (*out == 0) {
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
}
strncpy(*out + s_len, a, a_len);
*(*out + s_len + a_len) = '\0';
return s_len + a_len;
}
size_t strcmb(char **out, const char *a, size_t a_len, const char *b, size_t b_len)
{
size_t s_len, t_len;
if (a_len == 0) {
a_len = strlen(a);
} else if (a[a_len - 1] == '\0') {
a_len -= 1;
}
if (b_len == 0) {
b_len = strlen(b);
} else if (b[b_len - 1] == '\0') {
b_len -= 1;
}
t_len = a_len + b_len;
if (*out == 0) {
s_len = 0;
*out = (char *)malloc(t_len + 1);
if (*out == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
} else {
s_len = strlen(*out);
*out = (char *)realloc(*out, s_len + t_len + 1);
if (*out == 0) {
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
}
strncpy(*out + s_len, a, a_len);
strncpy(*out + s_len + a_len, b, b_len);
*(*out + s_len + t_len) = '\0';
return s_len + t_len;
}
str_builder *strbld_create()
{
str_builder *sb = malloc(sizeof(str_builder));
if (sb == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
sb->str = (char *)malloc(32);
if (sb == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
free(sb);
return 0;
}
memset(sb->str, '\0', 32);
sb->alloc = 32;
sb->len = 0;
sb->fails = 0;
return sb;
}
void strbld_destroy(str_builder **sbp)
{
str_builder *sb = *sbp;
if (sb->alloc > 0 && sb->str != 0) {
free(sb->str);
sb->alloc = 0;
sb->str = 0;
}
free(sb);
*sbp = 0;
}
void strbld_finalize(str_builder **sbp, char **str, size_t *len)
{
str_builder *sb = *sbp;
*str = sb->str;
*len = sb->len;
sb->alloc = 0;
strbld_destroy(sbp);
}
int strbld_finalize_or_destroy(str_builder **sbp, char **str, size_t *len)
{
if ((*sbp)->fails > 0) {
strbld_destroy(sbp);
return -1;
} else {
strbld_finalize(sbp, str, len);
return 0;
}
}
int strbld_ensure_len(str_builder *sb, size_t len, int absolute)
{
char *new_str;
if (sb->alloc > len) {
return 1;
}
if (absolute) {
sb->alloc = len;
} else {
while (sb->alloc <= len) {
sb->alloc <<= 1;
}
}
new_str = (char *)realloc(sb->str, sb->alloc);
if (new_str == 0) {
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
sb->str = new_str;
memset(sb->str + sb->len, '\0', sb->alloc - sb->len);
return 1;
}
int strbld_str(str_builder *sb, const char *str, size_t len)
{
if (sb->fails > 0) {
return 0;
}
if (len == 0) {
len = strlen(str);
}
if (str[len - 1] == '\0') {
len--;
}
if (!strbld_ensure_len(sb, sb->len + len, 0)) {
sb->fails++;
return 0;
}
memmove(sb->str + sb->len, str, len);
sb->len += len;
return 1;
}
int strbld_char(str_builder *sb, const char c)
{
if (sb->fails > 0) {
return 0;
}
if (!strbld_ensure_len(sb, sb->len + 1, 0)) {
sb->fails++;
return 0;
}
*(sb->str + sb->len) = c;
sb->len++;
return 1;
}

32
src/strext.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef H__STRCMB__
#define H__STRCMB__
#include <stddef.h>
#define STR_LEN(x) (sizeof(x)/sizeof(x[0])-1)
struct str_builder_t {
char *str;
size_t alloc;
size_t len;
size_t fails;
};
typedef struct str_builder_t str_builder;
size_t strlen_norm(const char *str, size_t str_len);
int strmemcpy(const char *str, size_t str_len, char **new_str, size_t *new_len);
size_t strapp(char **out, const char *a, size_t a_len);
size_t strcmb(char **out, const char *a, size_t a_len, const char *b, size_t b_len);
str_builder *strbld_create(void);
void strbld_destroy(str_builder **sb);
void strbld_finalize(str_builder **sb, char **str, size_t *len);
int strbld_finalize_or_destroy(str_builder **sb, char **str, size_t *len);
int strbld_ensure_len(str_builder *sb, size_t len, int absolute);
int strbld_str(str_builder *sb, const char *str, size_t len);
int strbld_char(str_builder *sb, const char c);
#endif // H__STRCMB__