Created a WHERE query builder and implemented a TYPE to char * method for database values
This commit is contained in:
@@ -6,6 +6,8 @@
|
|||||||
#include "db_transaction.h"
|
#include "db_transaction.h"
|
||||||
#include "db_column.h"
|
#include "db_column.h"
|
||||||
#include "db_query.h"
|
#include "db_query.h"
|
||||||
|
#include "db_value.h"
|
||||||
|
#include "db_where-builder.h"
|
||||||
|
|
||||||
void sessionEnd(void);
|
void sessionEnd(void);
|
||||||
|
|
||||||
|
|||||||
188
src/db_value.c
Normal file
188
src/db_value.c
Normal 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
9
src/db_value.h
Normal 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
719
src/db_where-builder.c
Normal 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
72
src/db_where-builder.h
Normal 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
221
src/strext.c
Normal 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
32
src/strext.h
Normal 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__
|
||||||
Reference in New Issue
Block a user