trailer: have function to describe trailer layout

Create a function that, taking a string, describes the position of its trailer block (if available) and the contents thereof, and make trailer use it. This makes it easier for other Git components, in the future, to interpret trailer blocks in the same way as trailer. In a subsequent patch, another component will be made to use this. Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathan Tan committed Nov 2, 2016 at 10:29 UTC e8c352c316f31a3869f3ad1dae0e8b33042cbaf4
2 files changed +107 -36
trailer.c
+82 -36
@@ -46,6 +46,8 @@ static LIST_HEAD(conf_head);
46
47 static char *separators = ":";
48
49 +static int configured;
50 +
51 #define TRAILER_ARG_STRING "$ARG"
52
53 static const char *git_generated_prefixes[] = {
@@ -546,6 +548,17 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)
548 return 0;
549 }
550
551 +static void ensure_configured(void)
552 +{
553 + if (configured)
554 + return;
555 +
556 + /* Default config must be setup first */
557 + git_config(git_trailer_default_config, NULL);
558 + git_config(git_trailer_config, NULL);
559 + configured = 1;
560 +}
561 +
562 static const char *token_from_item(struct arg_item *item, char *tok)
563 {
564 if (item->conf.key)
@@ -875,59 +888,43 @@ static int process_input_file(FILE *outfile,
888 const char *str,
889 struct list_head *head)
890 {
878 - int patch_start, trailer_start, trailer_end;
891 + struct trailer_info info;
892 struct strbuf tok = STRBUF_INIT;
893 struct strbuf val = STRBUF_INIT;
881 - struct trailer_item *last = NULL;
882 - struct strbuf *trailer, **trailer_lines, **ptr;
894 + int i;
895
884 - patch_start = find_patch_start(str);
885 - trailer_end = find_trailer_end(str, patch_start);
886 - trailer_start = find_trailer_start(str, trailer_end);
896 + trailer_info_get(&info, str);
897
898 /* Print lines before the trailers as is */
889 - fwrite(str, 1, trailer_start, outfile);
899 + fwrite(str, 1, info.trailer_start - str, outfile);
900
891 - if (!ends_with_blank_line(str, trailer_start))
901 + if (!info.blank_line_before_trailer)
902 fprintf(outfile, "\n");
903
894 - /* Parse trailer lines */
895 - trailer_lines = strbuf_split_buf(str + trailer_start,
896 - trailer_end - trailer_start,
897 - '\n',
898 - 0);
899 - for (ptr = trailer_lines; *ptr; ptr++) {
904 + for (i = 0; i < info.trailer_nr; i++) {
905 int separator_pos;
901 - trailer = *ptr;
902 - if (trailer->buf[0] == comment_line_char)
903 - continue;
904 - if (last && isspace(trailer->buf[0])) {
905 - struct strbuf sb = STRBUF_INIT;
906 - strbuf_addf(&sb, "%s\n%s", last->value, trailer->buf);
907 - strbuf_strip_suffix(&sb, "\n");
908 - free(last->value);
909 - last->value = strbuf_detach(&sb, NULL);
906 + char *trailer = info.trailers[i];
907 + if (trailer[0] == comment_line_char)
908 continue;
911 - }
912 - separator_pos = find_separator(trailer->buf, separators);
909 + separator_pos = find_separator(trailer, separators);
910 if (separator_pos >= 1) {
914 - parse_trailer(&tok, &val, NULL, trailer->buf,
911 + parse_trailer(&tok, &val, NULL, trailer,
912 separator_pos);
916 - last = add_trailer_item(head,
917 - strbuf_detach(&tok, NULL),
918 - strbuf_detach(&val, NULL));
913 + add_trailer_item(head,
914 + strbuf_detach(&tok, NULL),
915 + strbuf_detach(&val, NULL));
916 } else {
920 - strbuf_addbuf(&val, trailer);
917 + strbuf_addstr(&val, trailer);
918 strbuf_strip_suffix(&val, "\n");
919 add_trailer_item(head,
920 NULL,
921 strbuf_detach(&val, NULL));
925 - last = NULL;
922 }
923 }
928 - strbuf_list_free(trailer_lines);
924
930 - return trailer_end;
925 + trailer_info_release(&info);
926 +
927 + return info.trailer_end - str;
928 }
929
930 static void free_all(struct list_head *head)
@@ -978,9 +975,7 @@ void process_trailers(const char *file, int in_place, int trim_empty, struct str
975 int trailer_end;
976 FILE *outfile = stdout;
977
981 - /* Default config must be setup first */
982 - git_config(git_trailer_default_config, NULL);
983 - git_config(git_trailer_config, NULL);
978 + ensure_configured();
979
980 read_input_file(&sb, file);
981
@@ -1007,3 +1002,54 @@ void process_trailers(const char *file, int in_place, int trim_empty, struct str
1002
1003 strbuf_release(&sb);
1004 }
1005 +
1006 +void trailer_info_get(struct trailer_info *info, const char *str)
1007 +{
1008 + int patch_start, trailer_end, trailer_start;
1009 + struct strbuf **trailer_lines, **ptr;
1010 + char **trailer_strings = NULL;
1011 + size_t nr = 0, alloc = 0;
1012 + char **last = NULL;
1013 +
1014 + ensure_configured();
1015 +
1016 + patch_start = find_patch_start(str);
1017 + trailer_end = find_trailer_end(str, patch_start);
1018 + trailer_start = find_trailer_start(str, trailer_end);
1019 +
1020 + trailer_lines = strbuf_split_buf(str + trailer_start,
1021 + trailer_end - trailer_start,
1022 + '\n',
1023 + 0);
1024 + for (ptr = trailer_lines; *ptr; ptr++) {
1025 + if (last && isspace((*ptr)->buf[0])) {
1026 + struct strbuf sb = STRBUF_INIT;
1027 + strbuf_attach(&sb, *last, strlen(*last), strlen(*last));
1028 + strbuf_addbuf(&sb, *ptr);
1029 + *last = strbuf_detach(&sb, NULL);
1030 + continue;
1031 + }
1032 + ALLOC_GROW(trailer_strings, nr + 1, alloc);
1033 + trailer_strings[nr] = strbuf_detach(*ptr, NULL);
1034 + last = find_separator(trailer_strings[nr], separators) >= 1
1035 + ? &trailer_strings[nr]
1036 + : NULL;
1037 + nr++;
1038 + }
1039 + strbuf_list_free(trailer_lines);
1040 +
1041 + info->blank_line_before_trailer = ends_with_blank_line(str,
1042 + trailer_start);
1043 + info->trailer_start = str + trailer_start;
1044 + info->trailer_end = str + trailer_end;
1045 + info->trailers = trailer_strings;
1046 + info->trailer_nr = nr;
1047 +}
1048 +
1049 +void trailer_info_release(struct trailer_info *info)
1050 +{
1051 + int i;
1052 + for (i = 0; i < info->trailer_nr; i++)
1053 + free(info->trailers[i]);
1054 + free(info->trailers);
1055 +}
trailer.h
+25
@@ -1,7 +1,32 @@
1 #ifndef TRAILER_H
2 #define TRAILER_H
3
4 +struct trailer_info {
5 + /*
6 + * True if there is a blank line before the location pointed to by
7 + * trailer_start.
8 + */
9 + int blank_line_before_trailer;
10 +
11 + /*
12 + * Pointers to the start and end of the trailer block found. If there
13 + * is no trailer block found, these 2 pointers point to the end of the
14 + * input string.
15 + */
16 + const char *trailer_start, *trailer_end;
17 +
18 + /*
19 + * Array of trailers found.
20 + */
21 + char **trailers;
22 + size_t trailer_nr;
23 +};
24 +
25 void process_trailers(const char *file, int in_place, int trim_empty,
26 struct string_list *trailers);
27
28 +void trailer_info_get(struct trailer_info *info, const char *str);
29 +
30 +void trailer_info_release(struct trailer_info *info);
31 +
32 #endif /* TRAILER_H */