summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgramanas <anastasis.gramm2@gmail.com>2022-10-14 22:11:50 +0300
committergramanas <anastasis.gramm2@gmail.com>2022-10-14 22:11:50 +0300
commit7b7240d50dd5e418bc17beff48aa5681b398b980 (patch)
treeb521f1da139ce85974b71f1698cc140b1e7fed6c
parent433ce0f6795a4db89921b26274dd0b18fcccbb21 (diff)
downloadfoodtools-7b7240d50dd5e418bc17beff48aa5681b398b980.tar.gz
foodtools-7b7240d50dd5e418bc17beff48aa5681b398b980.tar.bz2
foodtools-7b7240d50dd5e418bc17beff48aa5681b398b980.zip
More changes
-rw-r--r--lib/cauliflower-bread.rcp22
-rw-r--r--lib/minced-meat.rcp2
-rw-r--r--lib/pasta-with-minced-meat.rcp2
-rw-r--r--lib/pasta.rcp2
-rw-r--r--lib/sandwiches/sandwich-base.rcp (renamed from lib/sandwich-base.rcp)0
-rw-r--r--lib/sandwiches/sandwich-sour.rcp (renamed from lib/sandwich-sour.rcp)0
-rw-r--r--lib/sandwiches/sandwich-xwriatiko.rcp13
-rw-r--r--lib/spetsofai.rcp21
-rw-r--r--src/cookbook.c2
-rw-r--r--src/eval.c4
-rw-r--r--src/food.c75
-rw-r--r--src/foodopts.c21
-rw-r--r--src/foodopts.h5
-rw-r--r--src/lib.c4
-rw-r--r--src/parser.c28
-rw-r--r--src/search.c8
-rw-r--r--src/types.c114
-rw-r--r--src/types.h4
-rw-r--r--src/util.h3
-rw-r--r--tests/parser.c6
20 files changed, 254 insertions, 82 deletions
diff --git a/lib/cauliflower-bread.rcp b/lib/cauliflower-bread.rcp
new file mode 100644
index 0000000..85b731a
--- /dev/null
+++ b/lib/cauliflower-bread.rcp
@@ -0,0 +1,22 @@
+@ cauliflower bread
+
+Parchment paper, Nonstick cooking spray, Cheesecloth
+cauliflower head = 1
+or cauliflower rice = 3 cups
+large egg lightly beaten = 1
+shredded part-skim mozzarella cheese = 1/2 cup
+salt
+ground black pepper
+
+---
+
+- Preheat oven to 220 C.
+- Line large baking sheet with parchment paper. Lightly coat with spray. Set aside.
+- Place half of cauliflower in food processor; pulse until cauliflower is chopped into pieces about the size of rice. Repeat with the other half. Place in microwave-safe bowl.
+- Fry cauliflower [for 5 to 10 minutes].
+- Place cauliflower on cheesecloth, in small batches; squeeze dry. (No cheesecloth? Use a heavy-duty paper towel.) Don't skip this step —cauliflower needs to be dry.
+- Combine cauliflower, egg, cheese, salt, and pepper in a medium bowl; mix well.
+- Place cauliflower mixture onto baking sheet in four even portions. Form into squares.
+- Bake [for 15 to 17 minutes, or until golden].
++ Cool for 10 minutes before carefully removing from baking sheet.
+
diff --git a/lib/minced-meat.rcp b/lib/minced-meat.rcp
index 1b25998..9feb48b 100644
--- a/lib/minced-meat.rcp
+++ b/lib/minced-meat.rcp
@@ -3,7 +3,7 @@
minced veal = 400g
minced pork = 100g
-salt, pepper = *
+salt, pepper
kayen pepper = 1/2 tbsp
cinamon = 1/2 tbsp
cumin = 1/2 tbsp
diff --git a/lib/pasta-with-minced-meat.rcp b/lib/pasta-with-minced-meat.rcp
index 3a4a6bc..c4c4a2d 100644
--- a/lib/pasta-with-minced-meat.rcp
+++ b/lib/pasta-with-minced-meat.rcp
@@ -1,4 +1,4 @@
@ pasta with minced meat
!pasta.rcp
-!minced-meat.rcp
+2!minced-meat.rcp
diff --git a/lib/pasta.rcp b/lib/pasta.rcp
index da71596..189c562 100644
--- a/lib/pasta.rcp
+++ b/lib/pasta.rcp
@@ -1,7 +1,7 @@
@pasta
pasta = 240g
-salt = *
+salt
olive oil = 1tblsp
---
diff --git a/lib/sandwich-base.rcp b/lib/sandwiches/sandwich-base.rcp
index 7a485b2..7a485b2 100644
--- a/lib/sandwich-base.rcp
+++ b/lib/sandwiches/sandwich-base.rcp
diff --git a/lib/sandwich-sour.rcp b/lib/sandwiches/sandwich-sour.rcp
index 7b614c4..7b614c4 100644
--- a/lib/sandwich-sour.rcp
+++ b/lib/sandwiches/sandwich-sour.rcp
diff --git a/lib/sandwiches/sandwich-xwriatiko.rcp b/lib/sandwiches/sandwich-xwriatiko.rcp
new file mode 100644
index 0000000..6b8c795
--- /dev/null
+++ b/lib/sandwiches/sandwich-xwriatiko.rcp
@@ -0,0 +1,13 @@
+@ sandwich xwriatiko
+
+!sandwich-base.rcp
+salt, peper, oregano = *
+tomato = *
+cucumber = *
+olive paste = 2 tbsp
+
+---
+
+> slice the $tomato and $cucumber
+- spread the ${olive paste} on the bread
+- add the veggies and season
diff --git a/lib/spetsofai.rcp b/lib/spetsofai.rcp
new file mode 100644
index 0000000..61935f8
--- /dev/null
+++ b/lib/spetsofai.rcp
@@ -0,0 +1,21 @@
+@spetsofai
+
+sausages = 4
+red peppers = 2
+green peppers = 2
+tomato = 2
+lemon = 1
+onion = 1
+garlic = 1 clove
+olive oil
+paprika, salt, pepper, oregano
+
+---
+
+- dice the veggies in ~2x2cm pieces
+- cut the sausage in similar sized bites
+> toss them all in an oven safe tray
+> add olive oil, salt, pepper, paprika and some oregano
+> squeeze in the lemon juice and toss again to combine
+> bake in the oven [until the saucage is done]
++ serve with some plain rice
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 <libgen.h>
-
#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++) {
@@ -262,20 +299,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)
{
if (!dst || !src) return;
@@ -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 <stdio.h>
#include <string.h>
#include <ctype.h>
+#include <libgen.h>
#define MAX(A, B) ((A) > (B) ? (A) : (B))
-#define FODD_MAX_ARRAY 1048576
+#define FOOD_MAX_ARRAY 1048576
void
fdebug(const char *fmt, ...);
diff --git a/tests/parser.c b/tests/parser.c
index 744c8ca..ddac924 100644
--- a/tests/parser.c
+++ b/tests/parser.c
@@ -117,15 +117,15 @@ START_TEST(check_parse_item)
is0(parse_item("noqty", r, (pt *)NULL, error));
ck_assert_str_eq(r->i[r->in - 1]->name, "noqty");
- ck_assert_str_eq(r->i[r->in - 1]->qty, "*");
+ ck_assert_str_eq(r->i[r->in - 1]->qty, "");
is0(parse_item("noqty2, noqty3", r, (pt *)NULL, error));
ck_assert_str_eq(r->i[r->in - 1]->name, "noqty3");
- ck_assert_str_eq(r->i[r->in - 1]->qty, "*");
+ ck_assert_str_eq(r->i[r->in - 1]->qty, "");
is0(parse_item("---", r, (pt *)NULL, error));
ck_assert_str_eq(r->i[r->in - 1]->name, "noqty3");
- ck_assert_str_eq(r->i[r->in - 1]->qty, "*");
+ ck_assert_str_eq(r->i[r->in - 1]->qty, "");
free_recipe(r);
}