From 7b7240d50dd5e418bc17beff48aa5681b398b980 Mon Sep 17 00:00:00 2001 From: gramanas Date: Fri, 14 Oct 2022 22:11:50 +0300 Subject: More changes --- src/cookbook.c | 2 +- src/eval.c | 4 +- src/food.c | 75 ++++++++++++++++++++++++------------- src/foodopts.c | 21 ++++++++++- src/foodopts.h | 5 +++ src/lib.c | 4 +- src/parser.c | 28 +++++++++----- src/search.c | 8 ++-- src/types.c | 114 ++++++++++++++++++++++++++++++++++++++++++--------------- src/types.h | 4 +- src/util.h | 3 +- 11 files changed, 192 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/cookbook.c b/src/cookbook.c index 0fab1e2..b1a4f76 100644 --- a/src/cookbook.c +++ b/src/cookbook.c @@ -150,7 +150,7 @@ main(int argc, char * argv[]) free_library(lib, n); for (int i = 0; i < n; i++) { - listing(cookbook[i]); + listing(cookbook[i], ""); } for (int i = 0; i < n; i++) { diff --git a/src/eval.c b/src/eval.c index 1267b00..d6c8933 100644 --- a/src/eval.c +++ b/src/eval.c @@ -8,7 +8,7 @@ sha1digest(uint8_t *digest, char *hexdigest, const uint8_t *data, size_t databyt void create_hash(recipe * r) { - char data[FODD_MAX_ARRAY] = "\0"; + char data[FOOD_MAX_ARRAY] = "\0"; for (int i = 0; i < r->in; i++) { strcat(data, r->i[i]->name); @@ -30,7 +30,7 @@ eval(recipe * r) merge_items(_r, r); merge_steps(_r, r); copy_metadata(_r, r); - copy_subrecipes(_r, r); + copy_subrecipes(_r, r, 0 /* shallow copy off */); create_hash(_r); diff --git a/src/food.c b/src/food.c index 02cd280..95fde55 100644 --- a/src/food.c +++ b/src/food.c @@ -21,7 +21,9 @@ static struct opts { int eval; int add; int add_n; + int listi; int list; + char listfmt[2048]; int hash; int search; int search_strict; @@ -38,7 +40,9 @@ static struct opts { .add = 0, .add_n = 0, .title = 0, + .listi = 0, .list = 0, + .listfmt = "", .hash = 0, .search = 0, .search_strict = 0, @@ -69,26 +73,26 @@ main(int argc, char * argv[]) struct foodoption long_options[] = {/* name, has_arg, flag, val, help, arg */ - {"help", no_argument, 0, 'h', "Print this help", 0}, - {"no-eval", no_argument, 0, 'n', "Don't evaluate recipes", 0}, - {"to-json", no_argument, 0, 'j', "Format recipe to json", 0}, - {"to-html", no_argument, 0, 'w', "Format recipe to html", 0}, - {"to-rcp", no_argument, 0, 'r', "Format recipe to rcp", 0}, - {"add-item", required_argument, 0, 'a', "Add item to matched recipes", "ITEM"}, + {"help", no_argument, 0, 'h', "Print this help", 0, "General" }, + {"include", required_argument, 0, 'I', "Path to recipe library, can be passed multiple times", "PATH", 0 }, + {"no-eval", no_argument, 0, 'n', "Don't evaluate recipes", 0, 0 }, + {"to-json", no_argument, 0, 'j', "Format recipe to json", 0, "Output format" }, + {"to-html", no_argument, 0, 'w', "Format recipe to html", 0, 0 }, + {"to-rcp", no_argument, 0, 'r', "Format recipe to rcp", 0, 0 }, + {"list-ingredients", no_argument, 0, 'L', "List ingredients for matched recipes", 0, 0 }, + {"list", optional_argument, 0, 'l', "List matched recipes with optional FORMAT", "[FORMAT]", 0 }, + {"search", required_argument, 0, 's', "Return recipes matching QUERY", "QUERY", "Filters" }, + {"title", required_argument, 0, 't', "Return recipes matching TITLE", "TITLE", 0 }, + {"strict", required_argument, 0, 'S', "Return recipes matching QUERY, exactly", "QUERY", 0 }, + {"hash", required_argument, 0, 'H', "Return recipes by HASH", "HASH", 0 }, + {"add-item", required_argument, 0, 'a', "Add item to matched recipes", "ITEM", "Other" }, //{"add-step", required_argument, 0, 'o'},, 0 - {"format", required_argument, 0, 'f', "Select recipe formatting", "{json,html,rcp}"}, - {"include", required_argument, 0, 'I', "Path to recipe library, can be passed many times", "PATH"}, - {"search", required_argument, 0, 's', "Return recipes matching QUERY", "QUERY"}, - {"title", required_argument, 0, 't', "Return recipes matching TITLE", "TITLE"}, - {"strict", required_argument, 0, 'S', "Return recipes matching QUERY, exaclty", "QUERY"}, - {"hash", required_argument, 0, 'H', "Return recipes by HASH", "HASH"}, - {"list-ingredients", no_argument, 0, 'l', "List ingredients for matched recipes", 0}, {0, 0, 0, 0, 0} }; while (1) { int option_index = 0; - c = get_foodopt (argc, argv, "jnlhrwf:s:S:t:H:I:a:", + c = get_foodopt (argc, argv, ":jnLhrws:S:t:H:I:a:l:", long_options, &option_index); if (c == -1) @@ -98,15 +102,6 @@ main(int argc, char * argv[]) case 0: printf("Flag setting\n"); break; - case 'f': - if (!strcmp(optarg, "json")) - opt.json = 1; - else if (!strcmp(optarg, "rcp")) - opt.rcp = 1; - else if (!strcmp(optarg, "html")) - opt.html = 1; - else - fprintf(stderr, "invalid format: %s\n", optarg); break; case 'I': strcpy(opt.includes[opt.includes_n++], optarg); @@ -139,6 +134,10 @@ main(int argc, char * argv[]) break; case 'l': opt.list = 1; + strcpy(opt.listfmt, optarg); + break; + case 'L': + opt.listi = 1; break; case 'h': opt.help = 1; @@ -151,8 +150,21 @@ main(int argc, char * argv[]) strcpy(opt.add_val[opt.add_n++], optarg); break; case '?': + fprintf(stderr, "%s: option '%c' not recognised, try -h for help\n", argv[0], optopt); return -1; break; + case ':': + switch (optopt) { + case 'l': + opt.list = 1; + strcpy(opt.listfmt, "DEFAULT"); + break; + default: + fprintf(stderr, "%s: missing argument %s for -%c\n", argv[0], get_argument(optopt, long_options), optopt); + return -1; + break; + } + break; default: abort (); } @@ -163,6 +175,16 @@ main(int argc, char * argv[]) return 0; } + if (opt.json + opt.rcp + opt.html + opt.list + opt.listi > 1) { + fprintf(stderr, "%s: only one output format is allowed at a time\n", argv[0]); + return 1; + } + + if (opt.eval == 0 && opt.hash == 1) { + fprintf(stderr, "%s: can't search hash without evaluation\n", argv[0]); + return 1; + } + char ** lib = NULL; int n = collect_library(&lib, argv, argc, optind, @@ -208,15 +230,18 @@ main(int argc, char * argv[]) fprintf(stderr, "Error: %s\n", err); } } - if (opt.list) { + if (opt.listi) { pprint_items(r); } + if (opt.list) { + listing(r , opt.listfmt); + } else { if (opt.json) tojson(r); else if (opt.html) tohtml(r); else if (opt.rcp) torcp(r); else { - listing(r); + // listing(r); } } free_recipe(r); diff --git a/src/foodopts.c b/src/foodopts.c index 7a4cbbd..338b97e 100644 --- a/src/foodopts.c +++ b/src/foodopts.c @@ -11,6 +11,20 @@ get_foodopt(int argc, char *const argv[], (struct option *)longopts, longindex); } +const char * +get_argument(const char opt, + const struct foodoption *longopts) +{ + int i = 0; + while ((longopts[i].name) + && (longopts[i].val)) { + if (longopts[i].val == opt) + return longopts[i].arg; + i++; + } + return NULL; +} + void foodopt_help(char * argv0, const struct foodoption *longopts) @@ -22,11 +36,14 @@ foodopt_help(char * argv0, int i = 0; while ((longopts[i].name) && (longopts[i].val)) { + if (longopts[i].category) { + fprintf(stderr, "\n%s:\n", longopts[i].category); + } fprintf(stderr, "-%c, --%s%s%s: %s\n", longopts[i].val, longopts[i].name, - longopts[i].has_arg == required_argument ? " " : "", - longopts[i].has_arg == required_argument ? longopts[i].arg : "", + (longopts[i].has_arg == required_argument || longopts[i].has_arg == optional_argument) ? " " : "", + (longopts[i].has_arg == required_argument || longopts[i].has_arg == optional_argument) ? longopts[i].arg : "", longopts[i].help); i++; } diff --git a/src/foodopts.h b/src/foodopts.h index c8b0686..06349a1 100644 --- a/src/foodopts.h +++ b/src/foodopts.h @@ -19,6 +19,7 @@ struct foodoption { /* Extra values */ const char *help; const char *arg; + const char *category; }; int @@ -27,6 +28,10 @@ get_foodopt(int argc, char *const argv[], const struct foodoption *longopts, int *longindex); +const char * +get_argument(const char opt, + const struct foodoption *longopts); + void foodopt_help(char * argv0, const struct foodoption *longopts); diff --git a/src/lib.c b/src/lib.c index a1f1f29..e91fb03 100644 --- a/src/lib.c +++ b/src/lib.c @@ -8,7 +8,7 @@ const char * default_food_lib = "/usr/local/share/food"; const char * foodlib_env() { - char * env = getenv("FOOD_LIB"); + char * env = getenv("FOODLIB"); if (env) return env; @@ -67,6 +67,8 @@ collect_library(char *** dst, n = rcp_find(&lib, n, includes[i]); } + n = rcp_find(&lib, n, foodlib_env()); + *dst = lib; return n; // no of items } diff --git a/src/parser.c b/src/parser.c index e90b200..a5b1a11 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1,5 +1,3 @@ -#include - #include "parser.h" #include "util.h" @@ -23,14 +21,8 @@ parse_title(const char * s, recipe * r, pt * type) } int -parse_item(const char * s, recipe * r, pt * type, char * error) +try_include(const char * s, recipe * r, char * error) { - fdebug("^ item\n"); - if (!strcmp(s, "---")) { - if (type) *type = STEPS; - return 0; - } - /* 1 - 9 in ascii */ if ((s[0] > 48 && s[0] < 58) || s[0] == '!') { fdebug("INCLUDING: %s\n", s); @@ -80,6 +72,22 @@ parse_item(const char * s, recipe * r, pt * type, char * error) return 0; } + return -1; +} + +int +parse_item(const char * s, recipe * r, pt * type, char * error) +{ + fdebug("^ item\n"); + if (!strcmp(s, "---")) { + if (type) *type = STEPS; + return 0; + } + + int rc = try_include(s, r, error); + if (rc != -1) + return rc; + int l = strlen(s); int val = 1; /* key vs value flag */ int itemc = 0; @@ -123,7 +131,7 @@ parse_item(const char * s, recipe * r, pt * type, char * error) if (!strlen(buf)) { // sprintf(error, "empty ingredient quantity: %s", s); // return 1; - strcpy(buf, "*"); + strcpy(buf, ""); } for (int i = 0; i < itemc; i++) { diff --git a/src/search.c b/src/search.c index a038cfb..5278337 100644 --- a/src/search.c +++ b/src/search.c @@ -94,7 +94,8 @@ query_for_items_pbn(const recipe * r, const char * s, int strict) 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); + pbg_error_print(&err); + free(query); free(str); pbg_error_free(&err); return -1; } @@ -103,11 +104,12 @@ query_for_items_pbn(const recipe * r, const char * s, int strict) 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); + pbg_error_print(&err); + free(query); free(str); pbg_free(&e); pbg_error_free(&err); return -1; } - free(query); free(str); pbg_free(&e); + free(query); free(str); pbg_free(&e); pbg_error_free(&err); return (result == PBG_TRUE) ? 1 : 0; } diff --git a/src/types.c b/src/types.c index 5ce0203..9314f8d 100644 --- a/src/types.c +++ b/src/types.c @@ -132,15 +132,46 @@ void pprint_items(recipe * r) { printf("Ingredients for %s:\n", r->title); - for (int i = 0; i < r->in; i++) - printf("%s: %s\n", r->i[i]->name, r->i[i]->qty); + for (int i = 0; i < r->in; i++) { + if (strlen(r->i[i]->qty)) { + printf("%s: %s\n", r->i[i]->name, r->i[i]->qty); + } + else { + printf("%s\n", r->i[i]->name); + } + } printf("\n"); } +char * last_n(const char * s, size_t n) +{ + size_t length = strlen( s ); + return ( char * )( length < n ? s : s + length - n ); +} + void -listing(recipe * r) +listing(recipe * r, const char * fmt) { - printf("%.*s %d:%d\t%d\t%s\n", 8, (strcmp(r->sha1, "") ? r->sha1 : "neval"), r->in, r->sn, r->rn, r->title); + if (!strcmp(fmt, "title") || !strcmp(fmt, "t")) { + printf("%s\n", r->title); + } + else if (!strcmp(fmt, "path") || !strcmp(fmt, "p")) { + printf("%s/%s\n", r->path, r->filename); + } + else if (!strcmp(fmt, "hash") || !strcmp(fmt, "h")) { + printf("%s\n", strcmp(r->sha1, "") ? r->sha1 : "neval"); + } + else if (!strcmp(fmt, "shorthash") || !strcmp(fmt, "s")) { + printf("%.*s\n", 8, strcmp(r->sha1, "") ? r->sha1 : "neval"); + } + else { + printf("%.*s %10.10s %d:%d\t%d\t%s\n", + 8, (strcmp(r->sha1, "") ? r->sha1 : "neval"), + basename(r->path), + r->in, r->sn, + r->rn, + r->title); + } } void @@ -244,8 +275,14 @@ torcp(recipe * r) for (int i = 0; i < r->rn; i++) { 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); + for (int i = 0; i < r->in; i++) { + if (strlen(r->i[i]->qty)) { + printf("%s = %s\n", r->i[i]->name, r->i[i]->qty); + } + else { + printf("%s\n", r->i[i]->name); + } + } if (r->sn) { printf("\n---\n\n"); for (int i = 0; i < r->sn; i++) { @@ -261,20 +298,6 @@ 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) { @@ -309,6 +332,24 @@ copy_steps(recipe * dst, recipe * src) } } +void +copy_subrecipes(recipe * dst, recipe * src, int shallow_copy) +{ + 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; + if (!shallow_copy) { + copy_items(r, src->r[i]); + copy_steps(r, src->r[i]); + } + new_subrecipe(dst, r); + } +} + static void join_subrecipe_items(recipe * dst, recipe * src) { @@ -319,9 +360,13 @@ join_subrecipe_items(recipe * dst, recipe * src) new_item(dst); dst->i[dst->in - 1]->name = strdup(src->r[i]->i[j]->name); if (src->r[i]->n > 1) { - char tmp[2048] = ""; - sprintf(tmp, "%d X ( %s )", src->r[i]->n, src->r[i]->i[j]->qty); - dst->i[dst->in - 1]->qty = strdup(tmp); + if (strcmp(src->r[i]->i[j]->qty, "")) { + char tmp[2048] = ""; + sprintf(tmp, "%d X ( %s )", src->r[i]->n, src->r[i]->i[j]->qty); + dst->i[dst->in - 1]->qty = strdup(tmp); + } else { + dst->i[dst->in - 1]->qty = strdup(""); + } } else { dst->i[dst->in - 1]->qty = strdup(src->r[i]->i[j]->qty); @@ -373,12 +418,23 @@ distinct_sum_items(recipe * dst, recipe * src) for (int i = 0; i < src->in; i++) { int n = item_exists(src->i[i]->name, dst); if (n != -1) { - char tmp[FODD_MAX_ARRAY] = ""; - strcat(tmp, dst->i[n]->qty); - strcat(tmp, " + "); - strcat(tmp, src->i[i]->qty); - free(dst->i[n]->qty); - dst->i[n]->qty = strdup(tmp); + if (!strcmp(dst->i[n]->qty, "") + && !strcmp(src->i[i]->qty, "")) { + // noop + } else if (strlen(dst->i[n]->qty) + strlen(src->i[i]->qty) != 0) { + char tmp[FOOD_MAX_ARRAY] = ""; + strcat(tmp, dst->i[n]->qty); + strcat(tmp, src->i[i]->qty); + free(dst->i[n]->qty); + dst->i[n]->qty = strdup(tmp); + } else { + char tmp[FOOD_MAX_ARRAY] = ""; + strcat(tmp, dst->i[n]->qty); + strcat(tmp, " + "); + strcat(tmp, src->i[i]->qty); + free(dst->i[n]->qty); + dst->i[n]->qty = strdup(tmp); + } } else { new_item(dst); diff --git a/src/types.h b/src/types.h index 867368b..d589c79 100644 --- a/src/types.h +++ b/src/types.h @@ -43,7 +43,7 @@ void free_item(item * i); void free_step(step * s); void pprint_items(recipe * r); -void listing(recipe * r); +void listing(recipe * r, const char * fmt); void show(recipe * r); void tojson(recipe * r); void tohtml(recipe * r); @@ -54,7 +54,7 @@ void torcp(recipe * r); /** * Copy metadata from `src` to `dst` */ -void copy_subrecipes(recipe * dst, recipe * src); +void copy_subrecipes(recipe * dst, recipe * src, int shallow_copy); /** * Copy metadata from `src` to `dst` diff --git a/src/util.h b/src/util.h index 0015df2..dce8531 100644 --- a/src/util.h +++ b/src/util.h @@ -6,10 +6,11 @@ #include #include #include +#include #define MAX(A, B) ((A) > (B) ? (A) : (B)) -#define FODD_MAX_ARRAY 1048576 +#define FOOD_MAX_ARRAY 1048576 void fdebug(const char *fmt, ...); -- cgit v1.2.3