#ifndef SORM_CLI_H
#define SORM_CLI_H
#include "sorm.h"
#include <fcntl.h>
#include <readline/history.h>
#include <readline/readline.h>
#include <rlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
const char *history_filename = ".sorm_history";
int _sorm_readline_accept_line(int count, int key) {
(void)count;
(void)key;
if (strchr(rl_line_buffer, ';')) {
rl_done = 1;
return 0;
}
rl_insert_text("\n");
return 0;
}
char *_sorm_autocompletion_generator(const char *text, int state) {
const char *completions[] = {"exit", sorm_last_query, sorm_last_query_expanded, "python", "history", "memory", "truncate", NULL};
int list_index;
if (!state) {
list_index = 0;
}
while (completions[list_index] != NULL) {
if (strncmp(completions[list_index], text, strlen(text)) == 0) {
return strdup(completions[list_index++]);
}
list_index++;
}
return NULL;
}
char **_sorm_autocomplete(const char *text, int start, int end) {
(void)start;
(void)end;
rl_attempted_completion_over = 1;
return rl_completion_matches(text, _sorm_autocompletion_generator);
}
int _hs_read_file(const char *filename, char *buffer, size_t size) {
int fd;
ssize_t bytes_read;
fd = open(filename, O_RDONLY);
if (fd < 0)
return -1;
bytes_read = read(fd, buffer, size);
close(fd);
if (bytes_read < 0 || (size_t)bytes_read != size)
return -1;
return 0;
}
int sorm_cli_history_dump(const char *filename) {
register int line_start, line_end;
char *input;
struct stat finfo;
size_t file_size;
if (stat(filename, &finfo) < 0)
return -1;
file_size = (size_t)finfo.st_size;
input = (char *)malloc(file_size + 1);
if (!input)
return -1;
if (_hs_read_file(filename, input, file_size) < 0) {
free(input);
return -1;
}
input[file_size] = '\0';
for (line_start = line_end = 0; (size_t)line_end < file_size; line_end++) {
if (input[line_end] == '\n') {
input[line_end] = '\0';
printf("%s\n", input + line_start);
line_start = line_end + 1;
}
}
if ((size_t)line_start < file_size)
printf("%s\n", input + line_start);
free(input);
return where_history();
}
char sorm_history_filename[4096];
void sorm_cli_init(const char *history_filename) {
strcpy(sorm_history_filename, history_filename);
rl_bind_key('\n', NULL);
rl_bind_key('\r', NULL);
rl_add_defun("custom-accept-line", _sorm_readline_accept_line, '\n');
rl_add_defun("custom-accept-line-cr", _sorm_readline_accept_line, '\r');
rl_variable_bind("enable-bracketed-paste", "on");
rl_attempted_completion_function = _sorm_autocomplete;
rl_variable_bind("show-all-if-ambiguous", "on");
rl_variable_bind("menu-complete-display-prefix", "on");
using_history();
read_history(sorm_history_filename);
}
char sorm_cli_previous_command[sizeof(rl_line_buffer)];
char *sorm_cli_readline(char *prompt) {
char *result = readline(prompt);
if (strcmp(rl_line_buffer, sorm_cli_previous_command)) {
add_history((const char *)result);
write_history(sorm_history_filename);
}
strcpy(sorm_cli_previous_command, rl_line_buffer);
return result;
}
bool sormrepl_handle_command(char *command) {
if (!strncmp(command, "history", 7)) {
sorm_cli_history_dump(history_filename);
return true;
}
return false;
}
void sormrepl(int sorm) {
sorm_cli_init(history_filename);
char *query;
while ((query = sorm_cli_readline("sql> "))) {
if (sormrepl_handle_command(query))
continue;
sorm_ptr res = sormq(sorm, query);
if (res) {
if (sormqt(query) == SORM_SELECT) {
sormfmtd(res);
free(res);
} else if (sormqt(query) == SORM_DELETE) {
printf("%d records affected.\n", res);
} else if (sormqt(query) == SORM_INSERT) {
printf("Last insert id: %d.\n", res);
}
}
printf("Rows: %lld, Execute %s, Format: %s\n", sorm_row_count, format_time(_sorm_query_duration),
format_time(_sorm_result_format_duration));
printf("%s\n", rmalloc_stats());
}
}
#endif