trailer: clarify failure modes in parse_trailer

The parse_trailer function has a few modes of operation, all depending on whether the separator is present in its input, and if yes, the separator's position. Some of these modes are failure modes, and these failure modes are handled differently depending on whether the trailer line was sourced from a file or from a command-line argument. Extract a function to find the separator, allowing the invokers of parse_trailer to determine how to handle the failure modes instead of making parse_trailer do it. In this function, also take in the list of separators, so that we can distinguish between command line arguments (which allow '=' as separator) and file input (which does not allow '=' as separator). Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathan Tan committed Oct 21, 2016 at 10:55 UTC fdbf4510aeb7e7b860c2ee77b8a4a3c5787fe182
1 file changed +53 -22
trailer.c
+53 -22
@@ -543,29 +543,37 @@ static int token_matches_item(const char *tok, struct arg_item *item, int tok_le
543 return item->conf.key ? !strncasecmp(tok, item->conf.key, tok_len) : 0;
544 }
545
546 -static int parse_trailer(struct strbuf *tok, struct strbuf *val,
547 - const struct conf_info **conf, const char *trailer)
546 +/*
547 + * Return the location of the first separator in line, or -1 if there is no
548 + * separator.
549 + */
550 +static int find_separator(const char *line, const char *separators)
551 +{
552 + int loc = strcspn(line, separators);
553 + if (!line[loc])
554 + return -1;
555 + return loc;
556 +}
557 +
558 +/*
559 + * Obtain the token, value, and conf from the given trailer.
560 + *
561 + * separator_pos must not be 0, since the token cannot be an empty string.
562 + *
563 + * If separator_pos is -1, interpret the whole trailer as a token.
564 + */
565 +static void parse_trailer(struct strbuf *tok, struct strbuf *val,
566 + const struct conf_info **conf, const char *trailer,
567 + int separator_pos)
568 {
549 - size_t len;
550 - struct strbuf seps = STRBUF_INIT;
569 struct arg_item *item;
570 int tok_len;
571 struct list_head *pos;
572
555 - strbuf_addstr(&seps, separators);
556 - strbuf_addch(&seps, '=');
557 - len = strcspn(trailer, seps.buf);
558 - strbuf_release(&seps);
559 - if (len == 0) {
560 - int l = strlen(trailer);
561 - while (l > 0 && isspace(trailer[l - 1]))
562 - l--;
563 - return error(_("empty trailer token in trailer '%.*s'"), l, trailer);
564 - }
565 - if (len < strlen(trailer)) {
566 - strbuf_add(tok, trailer, len);
573 + if (separator_pos != -1) {
574 + strbuf_add(tok, trailer, separator_pos);
575 strbuf_trim(tok);
568 - strbuf_addstr(val, trailer + len + 1);
576 + strbuf_addstr(val, trailer + separator_pos + 1);
577 strbuf_trim(val);
578 } else {
579 strbuf_addstr(tok, trailer);
@@ -587,8 +595,6 @@ static int parse_trailer(struct strbuf *tok, struct strbuf *val,
595 break;
596 }
597 }
590 -
591 - return 0;
598 }
599
600 static void add_trailer_item(struct list_head *head, char *tok, char *val)
@@ -619,6 +625,12 @@ static void process_command_line_args(struct list_head *arg_head,
625 const struct conf_info *conf;
626 struct list_head *pos;
627
628 + /*
629 + * In command-line arguments, '=' is accepted (in addition to the
630 + * separators that are defined).
631 + */
632 + char *cl_separators = xstrfmt("=%s", separators);
633 +
634 /* Add an arg item for each configured trailer with a command */
635 list_for_each(pos, &conf_head) {
636 item = list_entry(pos, struct arg_item, list);
@@ -631,12 +643,25 @@ static void process_command_line_args(struct list_head *arg_head,
643
644 /* Add an arg item for each trailer on the command line */
645 for_each_string_list_item(tr, trailers) {
634 - if (!parse_trailer(&tok, &val, &conf, tr->string))
646 + int separator_pos = find_separator(tr->string, cl_separators);
647 + if (separator_pos == 0) {
648 + struct strbuf sb = STRBUF_INIT;
649 + strbuf_addstr(&sb, tr->string);
650 + strbuf_trim(&sb);
651 + error(_("empty trailer token in trailer '%.*s'"),
652 + (int) sb.len, sb.buf);
653 + strbuf_release(&sb);
654 + } else {
655 + parse_trailer(&tok, &val, &conf, tr->string,
656 + separator_pos);
657 add_arg_item(arg_head,
658 strbuf_detach(&tok, NULL),
659 strbuf_detach(&val, NULL),
660 conf);
661 + }
662 }
663 +
664 + free(cl_separators);
665 }
666
667 static struct strbuf **read_input_file(const char *file)
@@ -775,11 +800,17 @@ static int process_input_file(FILE *outfile,
800
801 /* Parse trailer lines */
802 for (i = trailer_start; i < trailer_end; i++) {
778 - if (lines[i]->buf[0] != comment_line_char &&
779 - !parse_trailer(&tok, &val, NULL, lines[i]->buf))
803 + int separator_pos;
804 + if (lines[i]->buf[0] == comment_line_char)
805 + continue;
806 + separator_pos = find_separator(lines[i]->buf, separators);
807 + if (separator_pos >= 1) {
808 + parse_trailer(&tok, &val, NULL, lines[i]->buf,
809 + separator_pos);
810 add_trailer_item(head,
811 strbuf_detach(&tok, NULL),
812 strbuf_detach(&val, NULL));
813 + }
814 }
815
816 return trailer_end;