trailer: process command line trailer arguments

Parse the trailer command line arguments and put the result into an arg_tok doubly linked list. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Christian Couder committed Oct 13, 2014 at 20:16 UTC f0a90b4edff44af9a3cb3c30ff8e656a59581a2f
1 file changed +112
trailer.c
+112
@@ -1,4 +1,5 @@
1 #include "cache.h"
2 +#include "string-list.h"
3 /*
4 * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
5 */
@@ -462,3 +463,114 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)
463 }
464 return 0;
465 }
466 +
467 +static int parse_trailer(struct strbuf *tok, struct strbuf *val, const char *trailer)
468 +{
469 + size_t len;
470 + struct strbuf seps = STRBUF_INIT;
471 + strbuf_addstr(&seps, separators);
472 + strbuf_addch(&seps, '=');
473 + len = strcspn(trailer, seps.buf);
474 + strbuf_release(&seps);
475 + if (len == 0)
476 + return error(_("empty trailer token in trailer '%s'"), trailer);
477 + if (len < strlen(trailer)) {
478 + strbuf_add(tok, trailer, len);
479 + strbuf_trim(tok);
480 + strbuf_addstr(val, trailer + len + 1);
481 + strbuf_trim(val);
482 + } else {
483 + strbuf_addstr(tok, trailer);
484 + strbuf_trim(tok);
485 + }
486 + return 0;
487 +}
488 +
489 +static const char *token_from_item(struct trailer_item *item, char *tok)
490 +{
491 + if (item->conf.key)
492 + return item->conf.key;
493 + if (tok)
494 + return tok;
495 + return item->conf.name;
496 +}
497 +
498 +static struct trailer_item *new_trailer_item(struct trailer_item *conf_item,
499 + char *tok, char *val)
500 +{
501 + struct trailer_item *new = xcalloc(sizeof(*new), 1);
502 + new->value = val;
503 +
504 + if (conf_item) {
505 + duplicate_conf(&new->conf, &conf_item->conf);
506 + new->token = xstrdup(token_from_item(conf_item, tok));
507 + free(tok);
508 + } else {
509 + duplicate_conf(&new->conf, &default_conf_info);
510 + new->token = tok;
511 + }
512 +
513 + return new;
514 +}
515 +
516 +static int token_matches_item(const char *tok, struct trailer_item *item, int tok_len)
517 +{
518 + if (!strncasecmp(tok, item->conf.name, tok_len))
519 + return 1;
520 + return item->conf.key ? !strncasecmp(tok, item->conf.key, tok_len) : 0;
521 +}
522 +
523 +static struct trailer_item *create_trailer_item(const char *string)
524 +{
525 + struct strbuf tok = STRBUF_INIT;
526 + struct strbuf val = STRBUF_INIT;
527 + struct trailer_item *item;
528 + int tok_len;
529 +
530 + if (parse_trailer(&tok, &val, string))
531 + return NULL;
532 +
533 + tok_len = token_len_without_separator(tok.buf, tok.len);
534 +
535 + /* Lookup if the token matches something in the config */
536 + for (item = first_conf_item; item; item = item->next) {
537 + if (token_matches_item(tok.buf, item, tok_len))
538 + return new_trailer_item(item,
539 + strbuf_detach(&tok, NULL),
540 + strbuf_detach(&val, NULL));
541 + }
542 +
543 + return new_trailer_item(NULL,
544 + strbuf_detach(&tok, NULL),
545 + strbuf_detach(&val, NULL));
546 +}
547 +
548 +static void add_trailer_item(struct trailer_item **first,
549 + struct trailer_item **last,
550 + struct trailer_item *new)
551 +{
552 + if (!new)
553 + return;
554 + if (!*last) {
555 + *first = new;
556 + *last = new;
557 + } else {
558 + (*last)->next = new;
559 + new->previous = *last;
560 + *last = new;
561 + }
562 +}
563 +
564 +static struct trailer_item *process_command_line_args(struct string_list *trailers)
565 +{
566 + struct trailer_item *arg_tok_first = NULL;
567 + struct trailer_item *arg_tok_last = NULL;
568 + struct string_list_item *tr;
569 +
570 + for_each_string_list_item(tr, trailers) {
571 + struct trailer_item *new = create_trailer_item(tr->string);
572 + add_trailer_item(&arg_tok_first, &arg_tok_last, new);
573 + }
574 +
575 + return arg_tok_first;
576 +}