commit 3400cb5bab00f8d69b1b0930c4e2aa5011908a44
Author: Claudio Alessi <smoppy@gmail.com>
Date: Wed, 24 Feb 2016 00:07:29 +0100
Just in case.
Diffstat:
A | core.c | | | 388 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | databases.stfl | | | 8 | ++++++++ |
A | tables.stfl | | | 8 | ++++++++ |
A | test.c | | | 227 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
4 files changed, 631 insertions(+), 0 deletions(-)
diff --git a/core.c b/core.c
@@ -0,0 +1,388 @@
+/* cc -D_BSD_SOURCE -std=c99 -O0 -Wall -pedantic -o core core.c $(mysql_config --cflags) -lmysqlclient -lstfl -lncursesw */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <mysql.h>
+#include <stfl.h>
+
+#include <langinfo.h>
+#include <locale.h>
+
+#define LENGTH(X) (sizeof X / sizeof X[0])
+
+typedef union {
+ int i;
+ unsigned int ui;
+ float f;
+ const void *v;
+} Arg;
+
+typedef struct Item Item;
+struct Item {
+ char *name;
+ int len;
+ unsigned int flags;
+ Item *next;
+};
+
+typedef struct {
+ const char *mode;
+ const wchar_t *modkey;
+ void (*func)(const Arg *);
+ const Arg arg;
+} Key;
+
+typedef struct {
+ const char *mode;
+ const wchar_t *modkey;
+ const wchar_t *var;
+} Stflkey;
+
+typedef struct {
+ const char *name;
+ void (*func)(void);
+} Mode;
+
+typedef struct View View;
+struct View {
+ Mode *mode;
+ Item *items;
+ struct stfl_form *form;
+ View *next;
+};
+
+/* function declarations */
+void die(const char *errstr, ...);
+void databases(void);
+void tables(void);
+void records(void);
+void text(void);
+MYSQL_RES *mysql_exec(char *sql);
+Item *mysql_items(MYSQL_RES *res);
+void attach(View *v);
+void detach(View *v);
+void *ecalloc(size_t nmemb, size_t size);
+void cleanupview(View *v);
+void flagas(const Arg *arg);
+void apply(const Arg *arg);
+void quit(const Arg *arg);
+void setmode(const Arg *arg);
+void viewprev(const Arg *arg);
+void usedb(const Arg *arg);
+void usetable(const Arg *arg);
+void userecord(const Arg *arg);
+
+/* config.h > */
+
+/* XXX command line arguments */
+#define DBHOST "localhost"
+#define DBUSER "root"
+#define DBPASS "m0r3s3cur3"
+
+static Mode modes[] = {
+ /* name show function */
+ { "databases", databases }, /* first entry is default */
+ { "tables", tables },
+ { "records", records },
+ { "text", text },
+};
+
+static Key keys[] = {
+ /* mode modkey function argument */
+ { NULL, L"Q", quit, {.i = 0} },
+ { NULL, L"q", viewprev, {0} },
+ { NULL, L"D", setmode, {.v = &modes[0]} },
+ { NULL, L"T", setmode, {.v = &modes[1]} },
+ { NULL, L"R", setmode, {.v = &modes[2]} },
+ { NULL, L"E", setmode, {.v = &modes[3]} },
+ { "databases", L"q", quit, {.i = 1} },
+ { "databases", L"ENTER", usedb, {.v = &modes[1]} },
+ { "tables", L"ENTER", usetable, {0} },
+ { "records", L"ENTER", userecord, {0} },
+ { "records", L"d", flagas, {.v = "D"} },
+ { "records", L"t", flagas, {.v = "*"} },
+ { "records", L"$", apply, {0} },
+};
+
+static Stflkey stflkeys[] = {
+ /* mode modkey stfl variable */
+ { NULL, L"k UP", L"bind_up" },
+ { NULL, L"j DOWN", L"bind_down" },
+};
+
+/* < config.h */
+
+/* variables */
+static int running = 1;
+static MYSQL *mysql = NULL;
+static View *views, *selview;
+static struct stfl_ipool *ipool;
+
+/* function implementations */
+void
+quit(const Arg *arg) {
+ if(arg->i) {
+ /* XXX ask for confirmation */
+ }
+ running = 0;
+}
+
+void
+attach(View *v) {
+ v->next = views;
+ views = v;
+}
+
+void
+detach(View *v) {
+ View **tv;
+
+ for (tv = &views; *tv && *tv != v; tv = &(*tv)->next);
+ *tv = v->next;
+}
+
+void
+setmode(const Arg *arg) {
+ const Mode *m = arg->v;
+ View *v;
+ unsigned int i;
+
+ if(selview && !strcmp(arg->v, m->name))
+ return;
+
+ for(v = views; v; v = v->next)
+ if(!strcmp(v->mode->name, m->name))
+ break;
+ if(!v) {
+ v = ecalloc(1, sizeof(View));
+ for(i = 0; i < LENGTH(modes); ++i)
+ if(!strcmp(modes[i].name, m->name))
+ v->mode = &modes[i];
+ attach(v);
+
+ selview = v;
+ selview->mode->func();
+
+ /* bind stfl keys */
+ for(i = 0; i < LENGTH(stflkeys); ++i)
+ if(!(stflkeys[i].mode && strcmp(stflkeys[i].mode, selview->mode->name)))
+ stfl_set(selview->form, stflkeys[i].var, stflkeys[i].modkey);
+ }
+ else {
+ selview = v;
+ selview->mode->func();
+ }
+
+ /* XXX Throwing a visual error instead of die... */
+ if(!selview->form)
+ die("%s: mode is broken.\n", m->name);
+}
+
+void
+cleanupview(View *v) {
+ detach(v);
+
+ /* XXX
+ while(v->items)
+ cleanupitem(v->items);
+ */
+
+ /* XXX cleanup items */
+ if(v->form)
+ stfl_free(v->form);
+ free(v);
+}
+
+MYSQL_RES *
+mysql_exec(char *sql) {
+ MYSQL_RES *res;
+
+ if(mysql_real_query(mysql, sql, strlen(sql)))
+ return NULL;
+ res = mysql_store_result(mysql);
+ if(!res)
+ return NULL; /* XXX if(mysql_field_count(mysql)) error; */
+ return res;
+}
+
+Item *
+mysql_items(MYSQL_RES *res) {
+ MYSQL_ROW row;
+ Item *items, *item;
+ int i, nfds;
+
+ nfds = mysql_num_fields(res);
+
+ items = NULL;
+ while((row = mysql_fetch_row(res))) {
+ item = ecalloc(1, sizeof(Item));
+ item->name = ecalloc(256, sizeof(char));
+
+ for(i = 0; i < nfds; ++i)
+ snprintf(item->name, 22, "%s", row[i]);
+
+ item->next = items;
+ items = item;
+ }
+
+ return items;
+}
+
+void
+databases(void) {
+ MYSQL_RES *res;
+ Item *item;
+ char txt[256];
+ int i;
+
+ if(selview->form)
+ return;
+
+ if(!(res = mysql_exec("show databases")))
+ die("databases");
+
+ /* XXX Previously allocated items are never freed, only the LAST
+ * allocation gets freed by cleanupview(). */
+ selview->items = mysql_items(res);
+ mysql_free_result(res);
+
+ selview->form = stfl_create(L"<databases.stfl>");
+ i = 0;
+ for(item = selview->items; item; item = item->next) {
+ snprintf(txt, sizeof txt, "listitem[%d] text:\"%s\"", i++, item->name);
+ stfl_modify(selview->form, L"databases", L"append", stfl_ipool_towc(ipool, txt));
+ }
+}
+
+void
+tables(void) {
+ MYSQL_RES *res;
+ Item *item;
+ char txt[256];
+ int i;
+
+ if(!(res = mysql_exec("show tables")))
+ die("tables\n");
+
+ /*
+ XXX
+ if(selview->items)
+ free items
+ */
+
+ selview->items = mysql_items(res);
+ mysql_free_result(res);
+
+ if(!selview->form)
+ selview->form = stfl_create(L"<tables.stfl>");
+ i = 0;
+ stfl_modify(selview->form, L"tables", L"replace_inner", L"vbox"); /* clear */
+ for(item = selview->items; item; item = item->next) {
+ snprintf(txt, sizeof txt, "listitem[%d] text:\"%s\"", i++, item->name);
+ stfl_modify(selview->form, L"tables", L"append", stfl_ipool_towc(ipool, txt));
+ }
+}
+
+void
+records(void) {
+}
+
+void
+text(void) {
+}
+
+void
+usedb(const Arg *arg) {
+ Item *item;
+ int i = 0;
+
+ int pos = atoi(stfl_ipool_fromwc(ipool, stfl_get(selview->form, L"pos")));
+
+ for(item = selview->items; item; item = item->next)
+ if(i++ == pos)
+ break;
+
+ mysql_select_db(mysql, item->name);
+ setmode(arg);
+}
+
+void
+usetable(const Arg *arg) {
+}
+
+void
+userecord(const Arg *arg) {
+}
+
+void
+viewprev(const Arg *arg) {
+ if(!selview->next)
+ return;
+ selview = selview->next;
+ selview->mode->func();
+}
+
+void
+flagas(const Arg *arg) {
+}
+
+void
+apply(const Arg *arg) {
+}
+
+void
+die(const char *errstr, ...) {
+ va_list ap;
+
+ va_start(ap, errstr);
+ vfprintf(stderr, errstr, ap);
+ va_end(ap);
+ exit(1);
+}
+
+void *
+ecalloc(size_t nmemb, size_t size) {
+ void *p;
+
+ if (!(p = calloc(nmemb, size)))
+ die("Cannot allocate memory.");
+ return p;
+}
+
+int
+main(int argc, char **argv) {
+ Arg a = {.v = &modes[0]};
+ Key *k;
+ const wchar_t *ev;
+ unsigned int i;
+
+ mysql = mysql_init(NULL);
+ if(mysql_real_connect(mysql, DBHOST, DBUSER, DBPASS, NULL, 0, NULL, 0) == NULL)
+ die("Cannot connect to the database.\n");
+
+ ipool = stfl_ipool_create(nl_langinfo(CODESET));
+ setmode(&a);
+
+ while(running) {
+ if(!(ev = stfl_run(selview->form, 0)))
+ continue;
+
+ k = NULL;
+ for(i = 0; i < LENGTH(keys); ++i)
+ if(!((keys[i].mode && strcmp(selview->mode->name, keys[i].mode))
+ || wcscmp(ev, keys[i].modkey)))
+ k = &keys[i];
+ if(k)
+ k->func(&k->arg);
+ }
+
+ while(views)
+ cleanupview(views);
+
+ stfl_reset();
+ stfl_ipool_destroy(ipool);
+ return 0;
+}
diff --git a/databases.stfl b/databases.stfl
@@ -0,0 +1,8 @@
+vbox[main]
+ .expand:w
+ list[databases]
+ @style_normal:fg=white,bg=black
+ @style_focus:fg=blue,bg=black
+ @bind_down[bind_down]:**
+ @bind_up[bind_up]:**
+ pos[pos]:0
diff --git a/tables.stfl b/tables.stfl
@@ -0,0 +1,8 @@
+vbox[main]
+ .expand:w
+ list[tables]
+ @style_normal:fg=white,bg=black
+ @style_focus:fg=blue,bg=black
+ @bind_down[bind_down]:**
+ @bind_up[bind_up]:**
+ pos[pos]:0
diff --git a/test.c b/test.c
@@ -0,0 +1,227 @@
+/* cc -D_BSD_SOURCE -std=c99 -O0 -Wall -pedantic -o test test.c $(mysql_config --cflags) -lmysqlclient */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <mysql.h>
+
+typedef struct {
+ char *name;
+ int len;
+ unsigned int flags;
+} Item;
+
+typedef struct {
+ char **fields;
+ Item **items;
+ int nfields;
+ int nvalues;
+} List;
+
+typedef struct {
+ MYSQL_FIELD *fields;
+ MYSQL_RES *res;
+ int nfields;
+ int nrows;
+} Query;
+
+
+/* globals */
+static MYSQL *mysql = NULL;
+
+/* function declarations */
+/* ... */
+
+/* function implementations */
+Item *
+newitem(char *name, int len) {
+ Item *item;
+
+ item = malloc(sizeof(Item));
+ item->name = malloc(sizeof(char) * len + 1);
+ snprintf(item->name, len + 1, "%s", name);
+ item->len = len;
+ item->flags = 0;
+ return item;
+}
+
+List *
+newlist(int nfields, int nvalues, char **fields, Item **items) {
+ List *list;
+
+ list = malloc(sizeof(List));
+ if(!list)
+ return NULL;
+ list->fields = fields;
+ list->items = items;
+ list->nfields = nfields;
+ list->nvalues = nvalues;
+ return list;
+}
+
+void
+free_list(List *l) {
+ int i;
+
+ for(i = 0; i < l->nvalues; ++i)
+ free(l->items[i]);
+ free(l);
+}
+
+void
+die(const char *errstr, ...) {
+ va_list ap;
+
+ va_start(ap, errstr);
+ vfprintf(stderr, errstr, ap);
+ va_end(ap);
+ exit(1);
+}
+
+/* XXX to be implemented */
+Query *
+mysql_vexec(char *sqlstr, ...) {
+ return NULL;
+}
+
+Query *
+mysql_exec(char *sql, Query *qry) {
+ MYSQL_RES *res;
+ int nfds;
+
+ if(mysql_real_query(mysql, sql, strlen(sql)))
+ return NULL;
+ res = mysql_store_result(mysql);
+ if(!res)
+ return NULL; /* XXX if(mysql_field_count(mysql)) error; */
+ nfds = mysql_num_fields(res);
+ if(!qry)
+ qry = malloc(sizeof(Query));
+ qry->res = res;
+ qry->nfields = nfds;
+ qry->nrows = mysql_num_rows(res);
+ qry->fields = mysql_fetch_fields(res);
+ return qry;
+}
+
+void
+mysql_free(Query *q) {
+ mysql_free_result(q->res);
+ free(q);
+}
+
+int
+mysql_main() {
+ mysql = mysql_init(NULL);
+ if(mysql_real_connect(mysql, "localhost", "root", "m0r3s3cur3", NULL, 0, NULL, 0) == NULL)
+ return 1;
+ return 0;
+}
+
+void
+mysql_end() {
+ mysql_close(mysql);
+}
+
+const char *
+mysql_err() {
+ return mysql_error(mysql);
+}
+
+List *
+mysql_query_to_list(Query *q) {
+ MYSQL_ROW row;
+ unsigned long *lens;
+ Item **items;
+ char **fields;
+ int i, j, len;
+
+ /* fields */
+ fields = malloc(sizeof(char *) * q->nfields);
+ for(i = 0; i < q->nfields; ++i) {
+ len = strlen(q->fields[i].name) + 1;
+ fields[i] = malloc(sizeof(char) * len);
+ snprintf(fields[i], len, "%s", q->fields[i].name);
+ }
+
+ /* items */
+ items = malloc(sizeof(Item *) * q->nrows * q->nfields);
+ for(i = 0; i < q->nrows; ++i) {
+ row = mysql_fetch_row(q->res);
+ lens = mysql_fetch_lengths(q->res);
+
+ for(j = 0; j < q->nfields; ++j)
+ items[i * q->nfields + j] = newitem(row[j], lens[j]);
+ }
+
+ return newlist(q->nfields, q->nrows, fields, items);
+}
+
+void
+d_query(Query *q) {
+ MYSQL_ROW row;
+ int i, j, nfds;
+
+ printf("%d field(s), %d row(s) queried.\n", q->nfields, q->nrows);
+ nfds = (q->nfields > 5 ? 5 : q->nfields); /* show max 5 cols */
+
+ for(i = 0; i < nfds; ++i)
+ printf("%18.16s", q->fields[i].name);
+ printf("\n");
+
+ mysql_data_seek(q->res, 0);
+ for(i = 0; i < q->nrows; ++i) {
+ row = mysql_fetch_row(q->res);
+ for(j = 0; j < nfds; ++j)
+ printf("%18.16s", row[j]);
+ printf("\n");
+ }
+}
+
+void
+d_list(List *l) {
+ int i, j, nfds;
+
+ printf("%d field(s), %d row(s) queried.\n", l->nfields, l->nvalues);
+ nfds = (l->nfields > 5 ? 5 : l->nfields); /* show max 5 cols */
+
+ for(i = 0; i < nfds; ++i)
+ printf("%18.16s", l->fields[i]);
+ printf("\n");
+
+ for(i = 0; i < l->nvalues; ++i) {
+ for(j = 0; j < nfds; ++j)
+ printf("%18.16s", l->items[i * l->nfields + j]->name);
+ printf("\n");
+ }
+}
+
+int
+main(int argc, char *argv[]) {
+ List *l;
+ Query *q;
+ int i;
+
+ if(mysql_main())
+ die("mysql_main()");
+ q = NULL;
+ for(i = 1; i < argc; ++i) {
+ if(!(q = mysql_exec(argv[i], q))) {
+ printf("%s\n", mysql_err());
+ continue;
+ }
+ l = mysql_query_to_list(q);
+ //d_query(q);
+ if(!l) {
+ printf("Cannot convert to list.\n");
+ continue;
+ }
+ d_list(l);
+ free_list(l);
+ }
+ if(q)
+ mysql_free(q);
+ mysql_end();
+ return 0;
+}