184 lines
4.6 KiB
C
184 lines
4.6 KiB
C
|
#ifndef SORM_CLI_H
|
||
|
#define SORM_CLI_H
|
||
|
#include <rlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <unistd.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <readline/readline.h>
|
||
|
#include <readline/history.h>
|
||
|
#include "sorm.h"
|
||
|
|
||
|
const char * history_filename = ".sorm_history";
|
||
|
|
||
|
int _sorm_readline_accept_line(int count, int 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) {
|
||
|
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; 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 (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_t * db = sormg(sorm);
|
||
|
char sql[4097];
|
||
|
|
||
|
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){
|
||
|
int length = sormlv(res);
|
||
|
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
|