#ifndef SORM_CLI_H #define SORM_CLI_H #include #include #include #include #include #include #include #include #include #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