From 896c4369bb9cd38aa828516f084df54e35f1371e Mon Sep 17 00:00:00 2001 From: gramanas Date: Tue, 19 Mar 2019 22:20:53 +0200 Subject: Add interactive prompt with linenoise.c --- fcomp.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 96 insertions(+), 12 deletions(-) (limited to 'fcomp.c') diff --git a/fcomp.c b/fcomp.c index f4715f5..33944eb 100644 --- a/fcomp.c +++ b/fcomp.c @@ -21,7 +21,9 @@ #include "stdio.h" #include "string.h" #include "getopt.h" +#include "unistd.h" #include "ctype.h" +#include "linenoise.h" typedef struct slist { char **s; @@ -49,12 +51,14 @@ static int fuz(const char *str, const char *c); /** * stats for debugging */ typedef struct stats { + unsigned int discarded; char *search_results; char *tok_results; char *unique_results; } stats; static stats st = { + 0, NULL, NULL, NULL @@ -71,6 +75,9 @@ typedef struct config { int lisp_print; /** 0: off 1: on */ int print_count; /** 0: off 1: on */ int print_all; /** 0: off 1: on */ + int interactive; /** 0: off 1: on */ + int prompt; /** 0: off 1: on */ + int filestream; /** 0: off 1: on */ char *file; char *query; unsigned int min_word_size; @@ -93,6 +100,9 @@ static config cfg = { 0, 0, 0, + 0, + 1, + 0, NULL, NULL, 3, @@ -153,6 +163,10 @@ static void print_help(char *argv0) "Show debug information"); fprintf(stderr, "%8s %4s %15s %50s\n", "-s", "", "stats", "Print some stats"); + fprintf(stderr, "%8s %4s %15s %50s\n", "-I", "", "interactive", + "Run with interactive query input"); + fprintf(stderr, "%8s %4s %15s %50s\n", "", "", "", + "(Pass it twice to disable prompt)"); } static void print_cfg() @@ -184,6 +198,7 @@ static void print_cfg() static void print_stats() { fprintf(stderr, "\nStats:\n~~~~~~\n"); + fprintf(stderr, "Discarded chars:\t%d\n", st.discarded); if (st.tok_results) { fprintf(stderr, "%s", st.tok_results); free(st.tok_results); @@ -203,8 +218,19 @@ static int parse_cli(int argc, char *argv[]) if (argc < 2) return -1; char c; - while ((c = getopt(argc, argv, "-hxzsadclrf:i:v:w:t:")) != -1) { + while ((c = getopt(argc, argv, "-hIF:xzsadclrf:i:v:w:t:")) != -1) { switch (c) { + case 'I': + if (cfg.interactive) { + cfg.prompt = 0; + } + cfg.interactive = 1; + break; + case 'F': + cfg.stdin = 0; + cfg.filestream = 1; + cfg.file = optarg; + break; case 'h': cfg.help = 1; break; @@ -421,6 +447,7 @@ static void cfree(result * res) free(res->tok[i]); } free(res->tok); + res->n = 0; } /** @@ -433,6 +460,7 @@ static void sfree(slist * l) } if (l->s) free(l->s); + l->n = 0; } /** @@ -486,7 +514,7 @@ static int fuz(const char *str, const char *c) /** * Search an slist for @query and place the matches on @res * The search method is in the config struct */ -static int search(slist * l, const char *query, slist * res) +static int search(const slist * l, const char *query, slist * res) { int flag = 0; for (unsigned int i = 0; i < l->n; i++) { @@ -575,11 +603,12 @@ static void pc(const result * res) static int tokenize(FILE * f, slist * l) { unsigned int n = 0; - char c; + int c; char *tmp = NULL; while ((c = fgetc(f)) != EOF) { if (!is_valid(c)) { + st.discarded++; if (tmp) { finalize_str(tmp, n, l); free(tmp); @@ -622,7 +651,7 @@ static void get_slist_stats(slist * l) (char *) malloc((strlen(tmp) + snprintf(NULL, 0, "%d", l->n) + 3) * sizeof(char)); - sprintf(st.tok_results, "%s\t%d\n", tmp, l->n); + sprintf(st.tok_results, "%s\t\t%d\n", tmp, l->n); } } @@ -634,7 +663,7 @@ static void get_search_stats(slist * l) (char *) malloc((strlen(tmp) + snprintf(NULL, 0, "%d", l->n) + 3) * sizeof(char)); - sprintf(st.search_results, "%s\t%d\n", tmp, l->n); + sprintf(st.search_results, "%s\t\t%d\n", tmp, l->n); } } @@ -646,12 +675,55 @@ static void get_result_stats(result * r) (char *) malloc((strlen(tmp) + snprintf(NULL, 0, "%d", r->n) + 3) * sizeof(char)); - sprintf(st.unique_results, "%s\t%d\n", tmp, r->n); + sprintf(st.unique_results, "%s\t\t%d\n", tmp, r->n); + } +} + +void clean_stdin(void) +{ + int c; + do { + c = getchar(); + } while (c != '\n' && c != EOF); +} + +static void prompt(slist *l) +{ + int r = 0; + char p[20] = ""; + char *tmp = NULL; + if (cfg.prompt) sprintf(p, "[%d]> ", r); + fflush(NULL); + while((tmp = linenoise(p)) != NULL) { + slist search_res = { 0 }; + if (search(l, tmp, &search_res)) { + result count_res = { 0 }; + /* sort the results */ + qsort(&search_res.s[0], search_res.n, sizeof(char *), + cmpstringp); + + /* count the unique */ + count(&search_res, &count_res); + sort_by_count(&count_res); + + r = count_res.n; + /* print them */ + pc(&count_res); + + cfree(&count_res); + } + if (cfg.prompt) sprintf(p, "[%d]> ", r); + r = 0; + free(search_res.s); + free(tmp); + tmp = NULL; } + if (tmp) free(tmp); } int main(int argc, char *argv[]) { + int rc = 0; FILE *f; slist list = { 0 }; slist search_res = { 0 }; @@ -665,14 +737,20 @@ int main(int argc, char *argv[]) return -1; } - if (cfg.query == NULL && !cfg.print_all) { + if (cfg.query == NULL && !cfg.print_all && !cfg.interactive) { fprintf(stderr, "Query missing ... terminating\n"); return -1; } /* set input */ if (cfg.stdin) { + if (cfg.interactive) { + fprintf(stderr, "Can't read from stdin in interactive mode.\n"); + return -1; + } f = stdin; + } else if (cfg.filestream) { + f = fmemopen(cfg.file, strlen(cfg.file), "r"); } else { f = fopen(cfg.file, "r"); if (!f) { @@ -680,14 +758,20 @@ int main(int argc, char *argv[]) return -1; } } - /* tokenize */ - if (tokenize(f, &list)) - goto err; + if (tokenize(f, &list)) { + rc = -1; + goto done; + } if (cfg.stats) get_slist_stats(&list); + if (cfg.interactive) { + prompt(&list); + goto done; + } + if (cfg.print_all) { pp(&list); } else { @@ -721,8 +805,8 @@ int main(int argc, char *argv[]) if (cfg.stats) print_stats(); - err: +done: sfree(&list); fclose(f); - return 0; + return rc; } -- cgit v1.2.3