{"thread":{"id":"36094","subject":"[PATCH v7 02/11] trailer: process trailers from stdin and arguments","startedAt":"2014-03-06T22:13:59Z","lastAt":"2014-03-06T22:13:59Z","messageCount":1,"participants":["Christian Couder"],"isPatch":true,"patchVersion":7,"patchTotal":11},"messages":[{"id":"236246","messageId":"20140306221409.29648.22636.chriscool@tuxfamily.org","threadId":"36094","inReplyTo":null,"subject":"[PATCH v7 02/11] trailer: process trailers from stdin and arguments","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2014-03-06T22:13:59Z","receivedAt":"2014-03-06T22:13:59Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Implement the logic to process trailers from stdin and arguments.\n\nAt the beginning trailers from stdin are in their own in_tok\ndoubly linked list, and trailers from arguments are in their own\narg_tok doubly linked list.\n\nThe lists are traversed and when an arg_tok should be \"applied\",\nit is removed from its list and inserted into the in_tok list.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n trailer.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 198 insertions(+)\n\ndiff --git a/trailer.c b/trailer.c\nindex db93a63..52108c2 100644\n--- a/trailer.c\n+++ b/trailer.c\n@@ -47,3 +47,201 @@ static size_t alnum_len(const char *buf, size_t len)\n \t\tlen--;\n \treturn len;\n }\n+\n+static void free_trailer_item(struct trailer_item *item)\n+{\n+\tfree(item->conf.name);\n+\tfree(item->conf.key);\n+\tfree(item->conf.command);\n+\tfree((char *)item->token);\n+\tfree((char *)item->value);\n+\tfree(item);\n+}\n+\n+static void add_arg_to_input_list(struct trailer_item *in_tok,\n+\t\t\t\t  struct trailer_item *arg_tok)\n+{\n+\tif (arg_tok->conf.where == WHERE_AFTER) {\n+\t\targ_tok->next = in_tok->next;\n+\t\tin_tok->next = arg_tok;\n+\t\targ_tok->previous = in_tok;\n+\t\tif (arg_tok->next)\n+\t\t\targ_tok->next->previous = arg_tok;\n+\t} else {\n+\t\targ_tok->previous = in_tok->previous;\n+\t\tin_tok->previous = arg_tok;\n+\t\targ_tok->next = in_tok;\n+\t\tif (arg_tok->previous)\n+\t\t\targ_tok->previous->next = arg_tok;\n+\t}\n+}\n+\n+static int check_if_different(struct trailer_item *in_tok,\n+\t\t\t      struct trailer_item *arg_tok,\n+\t\t\t      int alnum_len, int check_all)\n+{\n+\tenum action_where where = arg_tok->conf.where;\n+\tdo {\n+\t\tif (!in_tok)\n+\t\t\treturn 1;\n+\t\tif (same_trailer(in_tok, arg_tok, alnum_len))\n+\t\t\treturn 0;\n+\t\t/*\n+\t\t * if we want to add a trailer after another one,\n+\t\t * we have to check those before this one\n+\t\t */\n+\t\tin_tok = (where == WHERE_AFTER) ? in_tok->previous : in_tok->next;\n+\t} while (check_all);\n+\treturn 1;\n+}\n+\n+static void apply_arg_if_exists(struct trailer_item *in_tok,\n+\t\t\t\tstruct trailer_item *arg_tok,\n+\t\t\t\tint alnum_len)\n+{\n+\tswitch (arg_tok->conf.if_exists) {\n+\tcase EXISTS_DO_NOTHING:\n+\t\tfree_trailer_item(arg_tok);\n+\t\tbreak;\n+\tcase EXISTS_OVERWRITE:\n+\t\tfree((char *)in_tok->value);\n+\t\tin_tok->value = xstrdup(arg_tok->value);\n+\t\tfree_trailer_item(arg_tok);\n+\t\tbreak;\n+\tcase EXISTS_ADD:\n+\t\tadd_arg_to_input_list(in_tok, arg_tok);\n+\t\tbreak;\n+\tcase EXISTS_ADD_IF_DIFFERENT:\n+\t\tif (check_if_different(in_tok, arg_tok, alnum_len, 1))\n+\t\t\tadd_arg_to_input_list(in_tok, arg_tok);\n+\t\telse\n+\t\t\tfree_trailer_item(arg_tok);\n+\t\tbreak;\n+\tcase EXISTS_ADD_IF_DIFFERENT_NEIGHBOR:\n+\t\tif (check_if_different(in_tok, arg_tok, alnum_len, 0))\n+\t\t\tadd_arg_to_input_list(in_tok, arg_tok);\n+\t\telse\n+\t\t\tfree_trailer_item(arg_tok);\n+\t\tbreak;\n+\t}\n+}\n+\n+static void remove_from_list(struct trailer_item *item,\n+\t\t\t     struct trailer_item **first)\n+{\n+\tif (item->next)\n+\t\titem->next->previous = item->previous;\n+\tif (item->previous)\n+\t\titem->previous->next = item->next;\n+\telse\n+\t\t*first = item->next;\n+}\n+\n+static struct trailer_item *remove_first(struct trailer_item **first)\n+{\n+\tstruct trailer_item *item = *first;\n+\t*first = item->next;\n+\tif (item->next) {\n+\t\titem->next->previous = NULL;\n+\t\titem->next = NULL;\n+\t}\n+\treturn item;\n+}\n+\n+static void process_input_token(struct trailer_item *in_tok,\n+\t\t\t\tstruct trailer_item **arg_tok_first,\n+\t\t\t\tenum action_where where)\n+{\n+\tstruct trailer_item *arg_tok;\n+\tstruct trailer_item *next_arg;\n+\n+\tint after = where == WHERE_AFTER;\n+\tint tok_alnum_len = alnum_len(in_tok->token, strlen(in_tok->token));\n+\n+\tfor (arg_tok = *arg_tok_first; arg_tok; arg_tok = next_arg) {\n+\t\tnext_arg = arg_tok->next;\n+\t\tif (!same_token(in_tok, arg_tok, tok_alnum_len))\n+\t\t\tcontinue;\n+\t\tif (arg_tok->conf.where != where)\n+\t\t\tcontinue;\n+\t\tremove_from_list(arg_tok, arg_tok_first);\n+\t\tapply_arg_if_exists(in_tok, arg_tok, tok_alnum_len);\n+\t\t/*\n+\t\t * If arg has been added to input,\n+\t\t * then we need to process it too now.\n+\t\t */\n+\t\tif ((after ? in_tok->next : in_tok->previous) == arg_tok)\n+\t\t\tin_tok = arg_tok;\n+\t}\n+}\n+\n+static void update_last(struct trailer_item **last)\n+{\n+\tif (*last)\n+\t\twhile ((*last)->next != NULL)\n+\t\t\t*last = (*last)->next;\n+}\n+\n+static void update_first(struct trailer_item **first)\n+{\n+\tif (*first)\n+\t\twhile ((*first)->previous != NULL)\n+\t\t\t*first = (*first)->previous;\n+}\n+\n+static void apply_arg_if_missing(struct trailer_item **in_tok_first,\n+\t\t\t\t struct trailer_item **in_tok_last,\n+\t\t\t\t struct trailer_item *arg_tok)\n+{\n+\tstruct trailer_item **in_tok;\n+\tenum action_where where;\n+\n+\tswitch (arg_tok->conf.if_missing) {\n+\tcase MISSING_DO_NOTHING:\n+\t\tfree_trailer_item(arg_tok);\n+\t\tbreak;\n+\tcase MISSING_ADD:\n+\t\twhere = arg_tok->conf.where;\n+\t\tin_tok = (where == WHERE_AFTER) ? in_tok_last : in_tok_first;\n+\t\tif (*in_tok) {\n+\t\t\tadd_arg_to_input_list(*in_tok, arg_tok);\n+\t\t\t*in_tok = arg_tok;\n+\t\t} else {\n+\t\t\t*in_tok_first = arg_tok;\n+\t\t\t*in_tok_last = arg_tok;\n+\t\t}\n+\t\tbreak;\n+\t}\n+}\n+\n+static void process_trailers_lists(struct trailer_item **in_tok_first,\n+\t\t\t\t   struct trailer_item **in_tok_last,\n+\t\t\t\t   struct trailer_item **arg_tok_first)\n+{\n+\tstruct trailer_item *in_tok;\n+\tstruct trailer_item *arg_tok;\n+\n+\tif (!*arg_tok_first)\n+\t\treturn;\n+\n+\t/* Process input from end to start */\n+\tfor (in_tok = *in_tok_last; in_tok; in_tok = in_tok->previous)\n+\t\tprocess_input_token(in_tok, arg_tok_first, WHERE_AFTER);\n+\n+\tupdate_last(in_tok_last);\n+\n+\tif (!*arg_tok_first)\n+\t\treturn;\n+\n+\t/* Process input from start to end */\n+\tfor (in_tok = *in_tok_first; in_tok; in_tok = in_tok->next)\n+\t\tprocess_input_token(in_tok, arg_tok_first, WHERE_BEFORE);\n+\n+\tupdate_first(in_tok_first);\n+\n+\t/* Process args left */\n+\twhile (*arg_tok_first) {\n+\t\targ_tok = remove_first(arg_tok_first);\n+\t\tapply_arg_if_missing(in_tok_first, in_tok_last, arg_tok);\n+\t}\n+}\n-- \n1.8.5.2.204.gcfe299d.dirty\n"}]}