summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/eval.c23
-rw-r--r--src/lib.c48
-rw-r--r--src/lib.h7
-rw-r--r--src/parser.h6
l---------src/pbg.c1
l---------src/pbg.h1
-rw-r--r--src/search.c118
-rw-r--r--src/search.h2
-rw-r--r--src/search_stuff.c126
l---------src/teeny-sha1.c1
-rw-r--r--src/types.c64
-rw-r--r--src/types.h7
12 files changed, 401 insertions, 3 deletions
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 <stdint.h>
+
+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 : <string>
+ *
+ */
+
+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;
}
@@ -137,6 +138,12 @@ pprint_items(recipe * r)
}
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)
{
printf("Filename\t%s\n", r->filename);
@@ -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("<div class=\"recipe\">\n");
+ printf("<!-- %s/%s -->\n", r->path, r->filename);
+ printf("<h1>%s</h1>\n\n", r->title);
+ if (r->rn) {
+ printf("<ul class=\"list items subrecipes\">\n");
+ for (int i = 0; i < r->rn; i++) {
+ printf("<li>!%s/%s</li>\n", r->r[i]->path, r->r[i]->filename);
+ }
+ printf("</ul>\n");
+ }
+ if (r->in) {
+ printf("<ul class=\"list items\">\n");
+ for (int i = 0; i < r->in; i++) {
+ printf("<li>%s = %s</li>\n", r->i[i]->name, r->i[i]->qty);
+ }
+ printf("</ul>\n");
+ }
+ if (r->sn) {
+ printf("<br><p>---</p><br>\n");
+ printf("<ul class=\"list steps\">\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("<li>%c %s</li>\n", c, r->s[i]->inst);
+ }
+ printf("</ul>\n");
+ }
+ printf("<hr>\n</div>\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);
@@ -218,6 +262,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)
{
if (!dst || !src) return;
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);
@@ -52,6 +54,11 @@ void torcp(recipe * r);
/**
* Copy metadata from `src` to `dst`
*/
+void copy_subrecipes(recipe * dst, recipe * src);
+
+/**
+ * Copy metadata from `src` to `dst`
+ */
void copy_metadata(recipe * dst, recipe * src);
/**