From 53ab9ae05a579a19c626e8be0c1e2cf9244bf863 Mon Sep 17 00:00:00 2001 From: gramanas Date: Fri, 28 Jan 2022 13:45:30 +0200 Subject: sha1 sum and others --- src/eval.c | 23 ++++++++++ src/lib.c | 48 ++++++++++++++++++++ src/lib.h | 7 +++ src/parser.h | 6 +++ src/pbg.c | 1 + src/pbg.h | 1 + src/search.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++ src/search.h | 2 + src/search_stuff.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/teeny-sha1.c | 1 + src/types.c | 64 +++++++++++++++++++++++++-- src/types.h | 7 +++ 12 files changed, 401 insertions(+), 3 deletions(-) create mode 100644 src/lib.c create mode 100644 src/lib.h create mode 120000 src/pbg.c create mode 120000 src/pbg.h create mode 100644 src/search_stuff.c create mode 120000 src/teeny-sha1.c (limited to 'src') diff --git a/src/eval.c b/src/eval.c index 8bc886a..57bfbb0 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1,5 +1,25 @@ #include "eval.h" #include "util.h" +#include + +extern int +sha1digest(uint8_t *digest, char *hexdigest, const uint8_t *data, size_t databytes); + +void +create_hash(recipe * r) +{ + char data[65536] = "\0"; + + for (int i = 0; i < r->in; i++) { + strcat(data, r->i[i]->name); + strcat(data, r->i[i]->qty); + } + if (r->sn) { + for (int i = 0; i < r->sn; i++) + strcat(data, r->s[i]->inst); + } + sha1digest(NULL, r->sha1, (uint8_t *)data, strlen(data)); +} recipe * eval(recipe * r) @@ -10,7 +30,10 @@ eval(recipe * r) merge_items(_r, r); merge_steps(_r, r); copy_metadata(_r, r); + copy_subrecipes(_r, r); + create_hash(_r); + return _r; } diff --git a/src/lib.c b/src/lib.c new file mode 100644 index 0000000..f43bdc2 --- /dev/null +++ b/src/lib.c @@ -0,0 +1,48 @@ +#include "lib.h" +#include "util.h" + +int +collect_library(char *** dst, char * argv[], int argc, int optind) +{ + int n = 0; + FILE *fp; + char path[1035]; + + char ** lib = NULL; + + for (int i = optind; i < argc; i++) { + lib = realloc(lib, sizeof(char **) * (n + 1)); + lib[n] = strdup(argv[i]); + fdebug("%d: %s\n", n, lib[n]); + n = n + 1; + } + + fp = popen("/bin/find /home/gramanas/code/foodtools/lib/ -name '*.rcp'", "r"); + if (fp == NULL) { + fprintf(stderr, "Couldn't run /bin/find\n"); + exit(1); + } + + /* Read the output a line at a time */ + while (fgets(path, sizeof(path), fp) != NULL) { + lib = realloc(lib, sizeof(char **) * (n + 1)); + trim(path); + lib[n] = strdup(path); + fdebug("%d: %s\n", n, lib[n]); + n = n + 1; + } + + /* close */ + pclose(fp); + + *dst = lib; + return n; // no of items +} + +void +free_library(char ** lib, int n) { + for (int i = 0; i < n; i++) { + free(lib[i]); + } + free(lib); +} diff --git a/src/lib.h b/src/lib.h new file mode 100644 index 0000000..005a330 --- /dev/null +++ b/src/lib.h @@ -0,0 +1,7 @@ +#ifndef __LIB_H +#define __LIB_H + +int collect_library(char *** lib, char * argv[], int argc, int optind); +void free_library(char ** lib, int n); + +#endif /* __LIB_H */ diff --git a/src/parser.h b/src/parser.h index 2680da5..d47bad5 100644 --- a/src/parser.h +++ b/src/parser.h @@ -5,6 +5,12 @@ #define LINE_SIZE 4096 +/** +* Return a recipe struct after parsing file in path. +* +* Path can be relative or full, ~ will be resolved as $HOME, and - will accept +* input from stdin +*/ recipe * parse(char * path, const char * prev); diff --git a/src/pbg.c b/src/pbg.c new file mode 120000 index 0000000..c707a6b --- /dev/null +++ b/src/pbg.c @@ -0,0 +1 @@ +../pbg/pbg.c \ No newline at end of file diff --git a/src/pbg.h b/src/pbg.h new file mode 120000 index 0000000..36a1da6 --- /dev/null +++ b/src/pbg.h @@ -0,0 +1 @@ +../pbg/pbg.h \ No newline at end of file diff --git a/src/search.c b/src/search.c index cf2eab9..a038cfb 100644 --- a/src/search.c +++ b/src/search.c @@ -1,5 +1,115 @@ #include "util.h" #include "search.h" +#include "pbg.h" + +static char * +form_string(const recipe * r, const char * s, int strict) +{ + char _s[4048] = ""; + int l = 0; + char buf[256] = ""; + + for (int i = 0; i < strlen(s); i++) { + if (s[i] == '(' || + s[i] == ')' || + s[i] == ' ') { + if (strlen(buf)) { + if (!strcmp(buf, "not") || + !strcmp(buf, "NOT") || + !strcmp(buf, "!")) { + _s[l++] = '!'; + } + else if (!strcmp(buf, "and") || + !strcmp(buf, "AND") || + !strcmp(buf, "&&") || + !strcmp(buf, "&")) { + _s[l++] = '&'; + } + else if (!strcmp(buf, "or") || + !strcmp(buf, "OR") || + !strcmp(buf, "||") || + !strcmp(buf, "|")) { + _s[l++] = '|'; + } + else { + fdebug("querying %s for %s\n", r->title, buf); + if (query_for_items(r, buf, strict)) { + strcat(_s, "TRUE"); + l+=4; + } + else { + strcat(_s, "FALSE"); + l+=5; + } + } + strcpy(buf, ""); + } + _s[l++] = s[i]; + } + else { + int k = strlen(buf); + buf[k] = s[i]; + buf[k+1] = '\0'; + } + } + _s[l] = '\0'; + + return strdup(_s); +} + +int +query_for_items_pbn(const recipe * r, const char * s, int strict) +{ + if (!strlen(s)) { + return 0; + } + + char * query = NULL; + + if (s[0] != '(') { + if (strstr(s, "and ") || + strstr(s, "or ") || + strstr(s, "not ")) { + query = (char *)malloc(sizeof(char) * strlen(s) + 3); + strcpy(query, "("); + strcat(query, s); + strcat(query, ")"); + } else { + return query_for_items(r, s, strict); + } + } else { + query = strdup(s); + } + + pbg_error err; + pbg_expr e; + int result; + + fdebug("PBG Query string: %s\n", query); + char* str = form_string(r, query, strict); + fdebug("PBG Query eval'd string: %s\n", str); + + /* Parse the expression string and check if + * there were any compilation errors. */ + pbg_parse(&e, &err, str); + if(pbg_iserror(&err)) { + fprintf(stderr, "Parsing error: %s => %s\n", s, str); + free(query); free(str); free(err._data); + return -1; + } + + /* Evaluate the expression string and check if + * there were any runtime errors. */ + result = pbg_evaluate(&e, &err, NULL); + if(pbg_iserror(&err)) { + fprintf(stderr, "Eval error: %s => %s\n", s, str); + free(query); free(str); pbg_free(&e); free(err._data); + return -1; + } + + free(query); free(str); pbg_free(&e); + return (result == PBG_TRUE) ? 1 : 0; +} /** * Query recipe `r` for input `s` and return 1 if found 0 otherwise @@ -17,3 +127,11 @@ query_for_items(const recipe * r, const char * s, int strict) } return 0; } + +int +check_hash(const recipe * r, const char * s) +{ + char _sha1[9]; + sprintf(_sha1, "%.*s", 8, r->sha1); + return (!strcmp(s, _sha1) || !strcmp(s, r->sha1)) ? 1 : 0; +} diff --git a/src/search.h b/src/search.h index 1295cd4..1c7c61f 100644 --- a/src/search.h +++ b/src/search.h @@ -3,6 +3,8 @@ #include "types.h" +int check_hash(const recipe * r, const char * s); int query_for_items(const recipe * r, const char * s, int strict); +int query_for_items_pbn(const recipe * r, const char * s, int strict); #endif diff --git a/src/search_stuff.c b/src/search_stuff.c new file mode 100644 index 0000000..5d4cb6c --- /dev/null +++ b/src/search_stuff.c @@ -0,0 +1,126 @@ +#include "util.h" +#include "search.h" + +char stk[4048]; +int p = 0; + +/* + * expr : (expr) | expr op expr | not expr | term + * op : and | or + * term : + * + */ + +void +reverse_str(char ** s) +{ + int l = strlen(*s); + char * rev_s = strdup(*s); + int j = 0; + for (int i = l - 1; i >= 0; i--, j++) { + rev_s[j] = (*s)[i]; + } + rev_s[j] = '\0'; + free(*s); + *s = rev_s; +} + + +/* + * Implementing https://www.javatpoint.com/convert-infix-to-prefix-notation + * + * ascii values: + * & -> 38 + * | -> 124 + * ( -> 40 + * ) -> 41 + * a-z -> 97-122 + * A-Z -> 64-90 + * + * precidence: + * & > | + * (http://www.cs.ucc.ie/~gavin/cs1001/Notes/chap40/ch40_16.html) + */ +int +precedence(char c) +{ + switch (c) { + case '&': + return 100; + case '|': + return 50; + default: + return 0; + } +} + +void +infix_to_prefix(char ** s) +{ + char * prefixed = malloc(sizeof(char) * strlen(*s) * 2); + prefixed[0] = '\0'; + char * rev_s = strdup(*s); + reverse_str(&rev_s); + + for (int i = 0; i < strlen(rev_s); i++) { + if (rev_s[i] == '&' || + rev_s[i] == '|') { + if (p == 0) { + stk[p++] = rev_s[i]; + } else { + if (precedence(rev_s[i] > precedence(stk[p - 1]))) { + stk[p++] = rev_s[i]; + } else { + int k = strlen(prefixed); + for (int j = p; j > 0 || precedence(rev_s[i]) < precedence(stk[p - 1]); j--) { + prefixed[k++] = stk[j - 1]; + p--; + } + prefixed[k] = '\0'; + stk[p++] = rev_s[i]; + } + } + } + else if (rev_s[i] == '(') { + stk[p++] = rev_s[i]; + } + else if (rev_s[i] == ')') { + int k = strlen(prefixed); + prefixed[k++] = rev_s[i]; + for (int j = p; j > 0 && stk[j] != ')'; j--) { + prefixed[k++] = stk[j - 1]; + p--; + } + prefixed[k] = '\0'; + } + else { + int k = strlen(prefixed); + prefixed[k] = rev_s[i]; + prefixed[k+1] = '\0'; + } + } + + int k = strlen(prefixed); + prefixed[k++] = ' '; // add space after the first operator + for (int j = p; j > 0; j--) { + prefixed[k++] = stk[j - 1]; + p--; + } + prefixed[k] = '\0'; + + printf("rev %s\n", prefixed); + for (int i = 0; i < strlen(prefixed); i++) { + if (prefixed[i] == '(' && + i < strlen(prefixed) && + (prefixed[i+1] == '&' || prefixed[i+1] == '|')) { + prefixed[i] = prefixed[i+1]; + prefixed[i+1] = '('; + } + } + + printf("rev fixed %s\n", prefixed); + reverse_str(&prefixed); + free(rev_s); + free(*s); + *s = prefixed; +} diff --git a/src/teeny-sha1.c b/src/teeny-sha1.c new file mode 120000 index 0000000..4208eb3 --- /dev/null +++ b/src/teeny-sha1.c @@ -0,0 +1 @@ +../teeny-sha1/teeny-sha1.c \ No newline at end of file diff --git a/src/types.c b/src/types.c index dbc7458..3233323 100644 --- a/src/types.c +++ b/src/types.c @@ -21,6 +21,7 @@ new_recipe() r->filename = NULL; r->path = NULL; r->title = NULL; + r->sha1[0] = '\0'; return r; } @@ -136,6 +137,12 @@ pprint_items(recipe * r) printf("\n"); } +void +listing(recipe * r) +{ + printf("%.*s %d:%d\t%d\t%s\n", 8, (strcmp(r->sha1, "") ? r->sha1 : "neval"), r->in, r->sn, r->rn, r->title); +} + void show(recipe * r) { @@ -158,7 +165,9 @@ tojson(recipe * r) printf("{\"filename\":\"%s\",", r->filename); printf("\"dirname\":\"%s\",", r->path); printf("\"title\":\"%s\",", r->title); - printf("\"n\":\"%d\"", r->n); + printf("\"n\":\"%d\",", r->n); + printf("\"sha1_short\":\"%.*s\",", 8, r->sha1); + printf("\"sha1\":\"%s\"", r->sha1); if (r->rn) { printf(",\"subrecipes\":["); int i = 0; @@ -189,16 +198,51 @@ tojson(recipe * r) void tohtml(recipe * r) { - printf("todo\n"); + printf("
\n"); + printf("\n", r->path, r->filename); + printf("

%s

\n\n", r->title); + if (r->rn) { + printf("
    \n"); + for (int i = 0; i < r->rn; i++) { + printf("
  • !%s/%s
  • \n", r->r[i]->path, r->r[i]->filename); + } + printf("
\n"); + } + if (r->in) { + printf("
    \n"); + for (int i = 0; i < r->in; i++) { + printf("
  • %s = %s
  • \n", r->i[i]->name, r->i[i]->qty); + } + printf("
\n"); + } + if (r->sn) { + printf("

---


\n"); + printf("
    \n"); + for (int i = 0; i < r->sn; i++) { + char c; + if (r->s[i]->type == PREP) + c = '-'; + else if (r->s[i]->type == COOK) + c = '>'; + else + c = '+'; + printf("
  • %c %s
  • \n", c, r->s[i]->inst); + } + printf("
\n"); + } + printf("
\n
\n"); } void torcp(recipe * r) { printf("# %s/%s\n\n", r->path, r->filename); + if (r->sha1[0] != '\0') { + printf("# %s\n\n", r->sha1); + } printf("@%s\n\n", r->title); for (int i = 0; i < r->rn; i++) { - printf("!%s/%s\n", r->r[i]->path, r->r[i]->filename); + printf("%s!%s/%s\n", (r->sha1[0] != '\0') ? "# ": "", r->r[i]->path, r->r[i]->filename); } for (int i = 0; i < r->in; i++) printf("%s = %s\n", r->i[i]->name, r->i[i]->qty); @@ -217,6 +261,20 @@ torcp(recipe * r) } } +void +copy_subrecipes(recipe * dst, recipe * src) +{ + if (!dst || !src) return; + for (int i = 0; i < src->rn; i++) { + recipe * r = new_recipe(); + r->title = strdup(src->r[i]->title); + r->path = strdup(src->r[i]->path); + r->filename = strdup(src->r[i]->filename); + r->n = src->r[i]->n; + new_subrecipe(dst, r); + } +} + void copy_metadata(recipe * dst, recipe * src) { diff --git a/src/types.h b/src/types.h index 2c58537..867368b 100644 --- a/src/types.h +++ b/src/types.h @@ -30,6 +30,7 @@ typedef struct recipe_t { int sn; struct recipe_t **r; int rn; + char sha1[41]; } recipe; recipe * new_recipe(); @@ -42,6 +43,7 @@ void free_item(item * i); void free_step(step * s); void pprint_items(recipe * r); +void listing(recipe * r); void show(recipe * r); void tojson(recipe * r); void tohtml(recipe * r); @@ -49,6 +51,11 @@ void torcp(recipe * r); /* Operations */ +/** + * Copy metadata from `src` to `dst` + */ +void copy_subrecipes(recipe * dst, recipe * src); + /** * Copy metadata from `src` to `dst` */ -- cgit v1.2.3