trailer.con commit t1700: add tests for splitIndex.maxPercentChange (fcdbd95)
   1#include "cache.h"
   2#include "string-list.h"
   3#include "run-command.h"
   4#include "commit.h"
   5#include "tempfile.h"
   6#include "trailer.h"
   7#include "list.h"
   8/*
   9 * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
  10 */
  11
  12enum action_where { WHERE_END, WHERE_AFTER, WHERE_BEFORE, WHERE_START };
  13enum action_if_exists { EXISTS_ADD_IF_DIFFERENT_NEIGHBOR, EXISTS_ADD_IF_DIFFERENT,
  14                        EXISTS_ADD, EXISTS_REPLACE, EXISTS_DO_NOTHING };
  15enum action_if_missing { MISSING_ADD, MISSING_DO_NOTHING };
  16
  17struct conf_info {
  18        char *name;
  19        char *key;
  20        char *command;
  21        enum action_where where;
  22        enum action_if_exists if_exists;
  23        enum action_if_missing if_missing;
  24};
  25
  26static struct conf_info default_conf_info;
  27
  28struct trailer_item {
  29        struct list_head list;
  30        /*
  31         * If this is not a trailer line, the line is stored in value
  32         * (excluding the terminating newline) and token is NULL.
  33         */
  34        char *token;
  35        char *value;
  36};
  37
  38struct arg_item {
  39        struct list_head list;
  40        char *token;
  41        char *value;
  42        struct conf_info conf;
  43};
  44
  45static LIST_HEAD(conf_head);
  46
  47static char *separators = ":";
  48
  49static int configured;
  50
  51#define TRAILER_ARG_STRING "$ARG"
  52
  53static const char *git_generated_prefixes[] = {
  54        "Signed-off-by: ",
  55        "(cherry picked from commit ",
  56        NULL
  57};
  58
  59/* Iterate over the elements of the list. */
  60#define list_for_each_dir(pos, head, is_reverse) \
  61        for (pos = is_reverse ? (head)->prev : (head)->next; \
  62                pos != (head); \
  63                pos = is_reverse ? pos->prev : pos->next)
  64
  65static int after_or_end(enum action_where where)
  66{
  67        return (where == WHERE_AFTER) || (where == WHERE_END);
  68}
  69
  70/*
  71 * Return the length of the string not including any final
  72 * punctuation. E.g., the input "Signed-off-by:" would return
  73 * 13, stripping the trailing punctuation but retaining
  74 * internal punctuation.
  75 */
  76static size_t token_len_without_separator(const char *token, size_t len)
  77{
  78        while (len > 0 && !isalnum(token[len - 1]))
  79                len--;
  80        return len;
  81}
  82
  83static int same_token(struct trailer_item *a, struct arg_item *b)
  84{
  85        size_t a_len, b_len, min_len;
  86
  87        if (!a->token)
  88                return 0;
  89
  90        a_len = token_len_without_separator(a->token, strlen(a->token));
  91        b_len = token_len_without_separator(b->token, strlen(b->token));
  92        min_len = (a_len > b_len) ? b_len : a_len;
  93
  94        return !strncasecmp(a->token, b->token, min_len);
  95}
  96
  97static int same_value(struct trailer_item *a, struct arg_item *b)
  98{
  99        return !strcasecmp(a->value, b->value);
 100}
 101
 102static int same_trailer(struct trailer_item *a, struct arg_item *b)
 103{
 104        return same_token(a, b) && same_value(a, b);
 105}
 106
 107static inline int is_blank_line(const char *str)
 108{
 109        const char *s = str;
 110        while (*s && *s != '\n' && isspace(*s))
 111                s++;
 112        return !*s || *s == '\n';
 113}
 114
 115static inline void strbuf_replace(struct strbuf *sb, const char *a, const char *b)
 116{
 117        const char *ptr = strstr(sb->buf, a);
 118        if (ptr)
 119                strbuf_splice(sb, ptr - sb->buf, strlen(a), b, strlen(b));
 120}
 121
 122static void free_trailer_item(struct trailer_item *item)
 123{
 124        free(item->token);
 125        free(item->value);
 126        free(item);
 127}
 128
 129static void free_arg_item(struct arg_item *item)
 130{
 131        free(item->conf.name);
 132        free(item->conf.key);
 133        free(item->conf.command);
 134        free(item->token);
 135        free(item->value);
 136        free(item);
 137}
 138
 139static char last_non_space_char(const char *s)
 140{
 141        int i;
 142        for (i = strlen(s) - 1; i >= 0; i--)
 143                if (!isspace(s[i]))
 144                        return s[i];
 145        return '\0';
 146}
 147
 148static void print_tok_val(FILE *outfile, const char *tok, const char *val)
 149{
 150        char c;
 151
 152        if (!tok) {
 153                fprintf(outfile, "%s\n", val);
 154                return;
 155        }
 156
 157        c = last_non_space_char(tok);
 158        if (!c)
 159                return;
 160        if (strchr(separators, c))
 161                fprintf(outfile, "%s%s\n", tok, val);
 162        else
 163                fprintf(outfile, "%s%c %s\n", tok, separators[0], val);
 164}
 165
 166static void print_all(FILE *outfile, struct list_head *head, int trim_empty)
 167{
 168        struct list_head *pos;
 169        struct trailer_item *item;
 170        list_for_each(pos, head) {
 171                item = list_entry(pos, struct trailer_item, list);
 172                if (!trim_empty || strlen(item->value) > 0)
 173                        print_tok_val(outfile, item->token, item->value);
 174        }
 175}
 176
 177static struct trailer_item *trailer_from_arg(struct arg_item *arg_tok)
 178{
 179        struct trailer_item *new = xcalloc(sizeof(*new), 1);
 180        new->token = arg_tok->token;
 181        new->value = arg_tok->value;
 182        arg_tok->token = arg_tok->value = NULL;
 183        free_arg_item(arg_tok);
 184        return new;
 185}
 186
 187static void add_arg_to_input_list(struct trailer_item *on_tok,
 188                                  struct arg_item *arg_tok)
 189{
 190        int aoe = after_or_end(arg_tok->conf.where);
 191        struct trailer_item *to_add = trailer_from_arg(arg_tok);
 192        if (aoe)
 193                list_add(&to_add->list, &on_tok->list);
 194        else
 195                list_add_tail(&to_add->list, &on_tok->list);
 196}
 197
 198static int check_if_different(struct trailer_item *in_tok,
 199                              struct arg_item *arg_tok,
 200                              int check_all,
 201                              struct list_head *head)
 202{
 203        enum action_where where = arg_tok->conf.where;
 204        struct list_head *next_head;
 205        do {
 206                if (same_trailer(in_tok, arg_tok))
 207                        return 0;
 208                /*
 209                 * if we want to add a trailer after another one,
 210                 * we have to check those before this one
 211                 */
 212                next_head = after_or_end(where) ? in_tok->list.prev
 213                                                : in_tok->list.next;
 214                if (next_head == head)
 215                        break;
 216                in_tok = list_entry(next_head, struct trailer_item, list);
 217        } while (check_all);
 218        return 1;
 219}
 220
 221static char *apply_command(const char *command, const char *arg)
 222{
 223        struct strbuf cmd = STRBUF_INIT;
 224        struct strbuf buf = STRBUF_INIT;
 225        struct child_process cp = CHILD_PROCESS_INIT;
 226        const char *argv[] = {NULL, NULL};
 227        char *result;
 228
 229        strbuf_addstr(&cmd, command);
 230        if (arg)
 231                strbuf_replace(&cmd, TRAILER_ARG_STRING, arg);
 232
 233        argv[0] = cmd.buf;
 234        cp.argv = argv;
 235        cp.env = local_repo_env;
 236        cp.no_stdin = 1;
 237        cp.use_shell = 1;
 238
 239        if (capture_command(&cp, &buf, 1024)) {
 240                error(_("running trailer command '%s' failed"), cmd.buf);
 241                strbuf_release(&buf);
 242                result = xstrdup("");
 243        } else {
 244                strbuf_trim(&buf);
 245                result = strbuf_detach(&buf, NULL);
 246        }
 247
 248        strbuf_release(&cmd);
 249        return result;
 250}
 251
 252static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg_tok)
 253{
 254        if (arg_tok->conf.command) {
 255                const char *arg;
 256                if (arg_tok->value && arg_tok->value[0]) {
 257                        arg = arg_tok->value;
 258                } else {
 259                        if (in_tok && in_tok->value)
 260                                arg = xstrdup(in_tok->value);
 261                        else
 262                                arg = xstrdup("");
 263                }
 264                arg_tok->value = apply_command(arg_tok->conf.command, arg);
 265                free((char *)arg);
 266        }
 267}
 268
 269static void apply_arg_if_exists(struct trailer_item *in_tok,
 270                                struct arg_item *arg_tok,
 271                                struct trailer_item *on_tok,
 272                                struct list_head *head)
 273{
 274        switch (arg_tok->conf.if_exists) {
 275        case EXISTS_DO_NOTHING:
 276                free_arg_item(arg_tok);
 277                break;
 278        case EXISTS_REPLACE:
 279                apply_item_command(in_tok, arg_tok);
 280                add_arg_to_input_list(on_tok, arg_tok);
 281                list_del(&in_tok->list);
 282                free_trailer_item(in_tok);
 283                break;
 284        case EXISTS_ADD:
 285                apply_item_command(in_tok, arg_tok);
 286                add_arg_to_input_list(on_tok, arg_tok);
 287                break;
 288        case EXISTS_ADD_IF_DIFFERENT:
 289                apply_item_command(in_tok, arg_tok);
 290                if (check_if_different(in_tok, arg_tok, 1, head))
 291                        add_arg_to_input_list(on_tok, arg_tok);
 292                else
 293                        free_arg_item(arg_tok);
 294                break;
 295        case EXISTS_ADD_IF_DIFFERENT_NEIGHBOR:
 296                apply_item_command(in_tok, arg_tok);
 297                if (check_if_different(on_tok, arg_tok, 0, head))
 298                        add_arg_to_input_list(on_tok, arg_tok);
 299                else
 300                        free_arg_item(arg_tok);
 301                break;
 302        }
 303}
 304
 305static void apply_arg_if_missing(struct list_head *head,
 306                                 struct arg_item *arg_tok)
 307{
 308        enum action_where where;
 309        struct trailer_item *to_add;
 310
 311        switch (arg_tok->conf.if_missing) {
 312        case MISSING_DO_NOTHING:
 313                free_arg_item(arg_tok);
 314                break;
 315        case MISSING_ADD:
 316                where = arg_tok->conf.where;
 317                apply_item_command(NULL, arg_tok);
 318                to_add = trailer_from_arg(arg_tok);
 319                if (after_or_end(where))
 320                        list_add_tail(&to_add->list, head);
 321                else
 322                        list_add(&to_add->list, head);
 323        }
 324}
 325
 326static int find_same_and_apply_arg(struct list_head *head,
 327                                   struct arg_item *arg_tok)
 328{
 329        struct list_head *pos;
 330        struct trailer_item *in_tok;
 331        struct trailer_item *on_tok;
 332
 333        enum action_where where = arg_tok->conf.where;
 334        int middle = (where == WHERE_AFTER) || (where == WHERE_BEFORE);
 335        int backwards = after_or_end(where);
 336        struct trailer_item *start_tok;
 337
 338        if (list_empty(head))
 339                return 0;
 340
 341        start_tok = list_entry(backwards ? head->prev : head->next,
 342                               struct trailer_item,
 343                               list);
 344
 345        list_for_each_dir(pos, head, backwards) {
 346                in_tok = list_entry(pos, struct trailer_item, list);
 347                if (!same_token(in_tok, arg_tok))
 348                        continue;
 349                on_tok = middle ? in_tok : start_tok;
 350                apply_arg_if_exists(in_tok, arg_tok, on_tok, head);
 351                return 1;
 352        }
 353        return 0;
 354}
 355
 356static void process_trailers_lists(struct list_head *head,
 357                                   struct list_head *arg_head)
 358{
 359        struct list_head *pos, *p;
 360        struct arg_item *arg_tok;
 361
 362        list_for_each_safe(pos, p, arg_head) {
 363                int applied = 0;
 364                arg_tok = list_entry(pos, struct arg_item, list);
 365
 366                list_del(pos);
 367
 368                applied = find_same_and_apply_arg(head, arg_tok);
 369
 370                if (!applied)
 371                        apply_arg_if_missing(head, arg_tok);
 372        }
 373}
 374
 375static int set_where(struct conf_info *item, const char *value)
 376{
 377        if (!strcasecmp("after", value))
 378                item->where = WHERE_AFTER;
 379        else if (!strcasecmp("before", value))
 380                item->where = WHERE_BEFORE;
 381        else if (!strcasecmp("end", value))
 382                item->where = WHERE_END;
 383        else if (!strcasecmp("start", value))
 384                item->where = WHERE_START;
 385        else
 386                return -1;
 387        return 0;
 388}
 389
 390static int set_if_exists(struct conf_info *item, const char *value)
 391{
 392        if (!strcasecmp("addIfDifferent", value))
 393                item->if_exists = EXISTS_ADD_IF_DIFFERENT;
 394        else if (!strcasecmp("addIfDifferentNeighbor", value))
 395                item->if_exists = EXISTS_ADD_IF_DIFFERENT_NEIGHBOR;
 396        else if (!strcasecmp("add", value))
 397                item->if_exists = EXISTS_ADD;
 398        else if (!strcasecmp("replace", value))
 399                item->if_exists = EXISTS_REPLACE;
 400        else if (!strcasecmp("doNothing", value))
 401                item->if_exists = EXISTS_DO_NOTHING;
 402        else
 403                return -1;
 404        return 0;
 405}
 406
 407static int set_if_missing(struct conf_info *item, const char *value)
 408{
 409        if (!strcasecmp("doNothing", value))
 410                item->if_missing = MISSING_DO_NOTHING;
 411        else if (!strcasecmp("add", value))
 412                item->if_missing = MISSING_ADD;
 413        else
 414                return -1;
 415        return 0;
 416}
 417
 418static void duplicate_conf(struct conf_info *dst, const struct conf_info *src)
 419{
 420        *dst = *src;
 421        dst->name = xstrdup_or_null(src->name);
 422        dst->key = xstrdup_or_null(src->key);
 423        dst->command = xstrdup_or_null(src->command);
 424}
 425
 426static struct arg_item *get_conf_item(const char *name)
 427{
 428        struct list_head *pos;
 429        struct arg_item *item;
 430
 431        /* Look up item with same name */
 432        list_for_each(pos, &conf_head) {
 433                item = list_entry(pos, struct arg_item, list);
 434                if (!strcasecmp(item->conf.name, name))
 435                        return item;
 436        }
 437
 438        /* Item does not already exists, create it */
 439        item = xcalloc(sizeof(*item), 1);
 440        duplicate_conf(&item->conf, &default_conf_info);
 441        item->conf.name = xstrdup(name);
 442
 443        list_add_tail(&item->list, &conf_head);
 444
 445        return item;
 446}
 447
 448enum trailer_info_type { TRAILER_KEY, TRAILER_COMMAND, TRAILER_WHERE,
 449                         TRAILER_IF_EXISTS, TRAILER_IF_MISSING };
 450
 451static struct {
 452        const char *name;
 453        enum trailer_info_type type;
 454} trailer_config_items[] = {
 455        { "key", TRAILER_KEY },
 456        { "command", TRAILER_COMMAND },
 457        { "where", TRAILER_WHERE },
 458        { "ifexists", TRAILER_IF_EXISTS },
 459        { "ifmissing", TRAILER_IF_MISSING }
 460};
 461
 462static int git_trailer_default_config(const char *conf_key, const char *value, void *cb)
 463{
 464        const char *trailer_item, *variable_name;
 465
 466        if (!skip_prefix(conf_key, "trailer.", &trailer_item))
 467                return 0;
 468
 469        variable_name = strrchr(trailer_item, '.');
 470        if (!variable_name) {
 471                if (!strcmp(trailer_item, "where")) {
 472                        if (set_where(&default_conf_info, value) < 0)
 473                                warning(_("unknown value '%s' for key '%s'"),
 474                                        value, conf_key);
 475                } else if (!strcmp(trailer_item, "ifexists")) {
 476                        if (set_if_exists(&default_conf_info, value) < 0)
 477                                warning(_("unknown value '%s' for key '%s'"),
 478                                        value, conf_key);
 479                } else if (!strcmp(trailer_item, "ifmissing")) {
 480                        if (set_if_missing(&default_conf_info, value) < 0)
 481                                warning(_("unknown value '%s' for key '%s'"),
 482                                        value, conf_key);
 483                } else if (!strcmp(trailer_item, "separators")) {
 484                        separators = xstrdup(value);
 485                }
 486        }
 487        return 0;
 488}
 489
 490static int git_trailer_config(const char *conf_key, const char *value, void *cb)
 491{
 492        const char *trailer_item, *variable_name;
 493        struct arg_item *item;
 494        struct conf_info *conf;
 495        char *name = NULL;
 496        enum trailer_info_type type;
 497        int i;
 498
 499        if (!skip_prefix(conf_key, "trailer.", &trailer_item))
 500                return 0;
 501
 502        variable_name = strrchr(trailer_item, '.');
 503        if (!variable_name)
 504                return 0;
 505
 506        variable_name++;
 507        for (i = 0; i < ARRAY_SIZE(trailer_config_items); i++) {
 508                if (strcmp(trailer_config_items[i].name, variable_name))
 509                        continue;
 510                name = xstrndup(trailer_item,  variable_name - trailer_item - 1);
 511                type = trailer_config_items[i].type;
 512                break;
 513        }
 514
 515        if (!name)
 516                return 0;
 517
 518        item = get_conf_item(name);
 519        conf = &item->conf;
 520        free(name);
 521
 522        switch (type) {
 523        case TRAILER_KEY:
 524                if (conf->key)
 525                        warning(_("more than one %s"), conf_key);
 526                conf->key = xstrdup(value);
 527                break;
 528        case TRAILER_COMMAND:
 529                if (conf->command)
 530                        warning(_("more than one %s"), conf_key);
 531                conf->command = xstrdup(value);
 532                break;
 533        case TRAILER_WHERE:
 534                if (set_where(conf, value))
 535                        warning(_("unknown value '%s' for key '%s'"), value, conf_key);
 536                break;
 537        case TRAILER_IF_EXISTS:
 538                if (set_if_exists(conf, value))
 539                        warning(_("unknown value '%s' for key '%s'"), value, conf_key);
 540                break;
 541        case TRAILER_IF_MISSING:
 542                if (set_if_missing(conf, value))
 543                        warning(_("unknown value '%s' for key '%s'"), value, conf_key);
 544                break;
 545        default:
 546                die("BUG: trailer.c: unhandled type %d", type);
 547        }
 548        return 0;
 549}
 550
 551static 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
 562static const char *token_from_item(struct arg_item *item, char *tok)
 563{
 564        if (item->conf.key)
 565                return item->conf.key;
 566        if (tok)
 567                return tok;
 568        return item->conf.name;
 569}
 570
 571static int token_matches_item(const char *tok, struct arg_item *item, int tok_len)
 572{
 573        if (!strncasecmp(tok, item->conf.name, tok_len))
 574                return 1;
 575        return item->conf.key ? !strncasecmp(tok, item->conf.key, tok_len) : 0;
 576}
 577
 578/*
 579 * If the given line is of the form
 580 * "<token><optional whitespace><separator>..." or "<separator>...", return the
 581 * location of the separator. Otherwise, return -1.  The optional whitespace
 582 * is allowed there primarily to allow things like "Bug #43" where <token> is
 583 * "Bug" and <separator> is "#".
 584 *
 585 * The separator-starts-line case (in which this function returns 0) is
 586 * distinguished from the non-well-formed-line case (in which this function
 587 * returns -1) because some callers of this function need such a distinction.
 588 */
 589static int find_separator(const char *line, const char *separators)
 590{
 591        int whitespace_found = 0;
 592        const char *c;
 593        for (c = line; *c; c++) {
 594                if (strchr(separators, *c))
 595                        return c - line;
 596                if (!whitespace_found && (isalnum(*c) || *c == '-'))
 597                        continue;
 598                if (c != line && (*c == ' ' || *c == '\t')) {
 599                        whitespace_found = 1;
 600                        continue;
 601                }
 602                break;
 603        }
 604        return -1;
 605}
 606
 607/*
 608 * Obtain the token, value, and conf from the given trailer.
 609 *
 610 * separator_pos must not be 0, since the token cannot be an empty string.
 611 *
 612 * If separator_pos is -1, interpret the whole trailer as a token.
 613 */
 614static void parse_trailer(struct strbuf *tok, struct strbuf *val,
 615                         const struct conf_info **conf, const char *trailer,
 616                         int separator_pos)
 617{
 618        struct arg_item *item;
 619        int tok_len;
 620        struct list_head *pos;
 621
 622        if (separator_pos != -1) {
 623                strbuf_add(tok, trailer, separator_pos);
 624                strbuf_trim(tok);
 625                strbuf_addstr(val, trailer + separator_pos + 1);
 626                strbuf_trim(val);
 627        } else {
 628                strbuf_addstr(tok, trailer);
 629                strbuf_trim(tok);
 630        }
 631
 632        /* Lookup if the token matches something in the config */
 633        tok_len = token_len_without_separator(tok->buf, tok->len);
 634        if (conf)
 635                *conf = &default_conf_info;
 636        list_for_each(pos, &conf_head) {
 637                item = list_entry(pos, struct arg_item, list);
 638                if (token_matches_item(tok->buf, item, tok_len)) {
 639                        char *tok_buf = strbuf_detach(tok, NULL);
 640                        if (conf)
 641                                *conf = &item->conf;
 642                        strbuf_addstr(tok, token_from_item(item, tok_buf));
 643                        free(tok_buf);
 644                        break;
 645                }
 646        }
 647}
 648
 649static struct trailer_item *add_trailer_item(struct list_head *head, char *tok,
 650                                             char *val)
 651{
 652        struct trailer_item *new = xcalloc(sizeof(*new), 1);
 653        new->token = tok;
 654        new->value = val;
 655        list_add_tail(&new->list, head);
 656        return new;
 657}
 658
 659static void add_arg_item(struct list_head *arg_head, char *tok, char *val,
 660                         const struct conf_info *conf)
 661{
 662        struct arg_item *new = xcalloc(sizeof(*new), 1);
 663        new->token = tok;
 664        new->value = val;
 665        duplicate_conf(&new->conf, conf);
 666        list_add_tail(&new->list, arg_head);
 667}
 668
 669static void process_command_line_args(struct list_head *arg_head,
 670                                      struct string_list *trailers)
 671{
 672        struct string_list_item *tr;
 673        struct arg_item *item;
 674        struct strbuf tok = STRBUF_INIT;
 675        struct strbuf val = STRBUF_INIT;
 676        const struct conf_info *conf;
 677        struct list_head *pos;
 678
 679        /*
 680         * In command-line arguments, '=' is accepted (in addition to the
 681         * separators that are defined).
 682         */
 683        char *cl_separators = xstrfmt("=%s", separators);
 684
 685        /* Add an arg item for each configured trailer with a command */
 686        list_for_each(pos, &conf_head) {
 687                item = list_entry(pos, struct arg_item, list);
 688                if (item->conf.command)
 689                        add_arg_item(arg_head,
 690                                     xstrdup(token_from_item(item, NULL)),
 691                                     xstrdup(""),
 692                                     &item->conf);
 693        }
 694
 695        /* Add an arg item for each trailer on the command line */
 696        for_each_string_list_item(tr, trailers) {
 697                int separator_pos = find_separator(tr->string, cl_separators);
 698                if (separator_pos == 0) {
 699                        struct strbuf sb = STRBUF_INIT;
 700                        strbuf_addstr(&sb, tr->string);
 701                        strbuf_trim(&sb);
 702                        error(_("empty trailer token in trailer '%.*s'"),
 703                              (int) sb.len, sb.buf);
 704                        strbuf_release(&sb);
 705                } else {
 706                        parse_trailer(&tok, &val, &conf, tr->string,
 707                                      separator_pos);
 708                        add_arg_item(arg_head,
 709                                     strbuf_detach(&tok, NULL),
 710                                     strbuf_detach(&val, NULL),
 711                                     conf);
 712                }
 713        }
 714
 715        free(cl_separators);
 716}
 717
 718static void read_input_file(struct strbuf *sb, const char *file)
 719{
 720        if (file) {
 721                if (strbuf_read_file(sb, file, 0) < 0)
 722                        die_errno(_("could not read input file '%s'"), file);
 723        } else {
 724                if (strbuf_read(sb, fileno(stdin), 0) < 0)
 725                        die_errno(_("could not read from stdin"));
 726        }
 727}
 728
 729static const char *next_line(const char *str)
 730{
 731        const char *nl = strchrnul(str, '\n');
 732        return nl + !!*nl;
 733}
 734
 735/*
 736 * Return the position of the start of the last line. If len is 0, return -1.
 737 */
 738static int last_line(const char *buf, size_t len)
 739{
 740        int i;
 741        if (len == 0)
 742                return -1;
 743        if (len == 1)
 744                return 0;
 745        /*
 746         * Skip the last character (in addition to the null terminator),
 747         * because if the last character is a newline, it is considered as part
 748         * of the last line anyway.
 749         */
 750        i = len - 2;
 751
 752        for (; i >= 0; i--) {
 753                if (buf[i] == '\n')
 754                        return i + 1;
 755        }
 756        return 0;
 757}
 758
 759/*
 760 * Return the position of the start of the patch or the length of str if there
 761 * is no patch in the message.
 762 */
 763static int find_patch_start(const char *str)
 764{
 765        const char *s;
 766
 767        for (s = str; *s; s = next_line(s)) {
 768                if (starts_with(s, "---"))
 769                        return s - str;
 770        }
 771
 772        return s - str;
 773}
 774
 775/*
 776 * Return the position of the first trailer line or len if there are no
 777 * trailers.
 778 */
 779static int find_trailer_start(const char *buf, size_t len)
 780{
 781        const char *s;
 782        int end_of_title, l, only_spaces = 1;
 783        int recognized_prefix = 0, trailer_lines = 0, non_trailer_lines = 0;
 784        /*
 785         * Number of possible continuation lines encountered. This will be
 786         * reset to 0 if we encounter a trailer (since those lines are to be
 787         * considered continuations of that trailer), and added to
 788         * non_trailer_lines if we encounter a non-trailer (since those lines
 789         * are to be considered non-trailers).
 790         */
 791        int possible_continuation_lines = 0;
 792
 793        /* The first paragraph is the title and cannot be trailers */
 794        for (s = buf; s < buf + len; s = next_line(s)) {
 795                if (s[0] == comment_line_char)
 796                        continue;
 797                if (is_blank_line(s))
 798                        break;
 799        }
 800        end_of_title = s - buf;
 801
 802        /*
 803         * Get the start of the trailers by looking starting from the end for a
 804         * blank line before a set of non-blank lines that (i) are all
 805         * trailers, or (ii) contains at least one Git-generated trailer and
 806         * consists of at least 25% trailers.
 807         */
 808        for (l = last_line(buf, len);
 809             l >= end_of_title;
 810             l = last_line(buf, l)) {
 811                const char *bol = buf + l;
 812                const char **p;
 813                int separator_pos;
 814
 815                if (bol[0] == comment_line_char) {
 816                        non_trailer_lines += possible_continuation_lines;
 817                        possible_continuation_lines = 0;
 818                        continue;
 819                }
 820                if (is_blank_line(bol)) {
 821                        if (only_spaces)
 822                                continue;
 823                        non_trailer_lines += possible_continuation_lines;
 824                        if (recognized_prefix &&
 825                            trailer_lines * 3 >= non_trailer_lines)
 826                                return next_line(bol) - buf;
 827                        else if (trailer_lines && !non_trailer_lines)
 828                                return next_line(bol) - buf;
 829                        return len;
 830                }
 831                only_spaces = 0;
 832
 833                for (p = git_generated_prefixes; *p; p++) {
 834                        if (starts_with(bol, *p)) {
 835                                trailer_lines++;
 836                                possible_continuation_lines = 0;
 837                                recognized_prefix = 1;
 838                                goto continue_outer_loop;
 839                        }
 840                }
 841
 842                separator_pos = find_separator(bol, separators);
 843                if (separator_pos >= 1 && !isspace(bol[0])) {
 844                        struct list_head *pos;
 845
 846                        trailer_lines++;
 847                        possible_continuation_lines = 0;
 848                        if (recognized_prefix)
 849                                continue;
 850                        list_for_each(pos, &conf_head) {
 851                                struct arg_item *item;
 852                                item = list_entry(pos, struct arg_item, list);
 853                                if (token_matches_item(bol, item,
 854                                                       separator_pos)) {
 855                                        recognized_prefix = 1;
 856                                        break;
 857                                }
 858                        }
 859                } else if (isspace(bol[0]))
 860                        possible_continuation_lines++;
 861                else {
 862                        non_trailer_lines++;
 863                        non_trailer_lines += possible_continuation_lines;
 864                        possible_continuation_lines = 0;
 865                }
 866continue_outer_loop:
 867                ;
 868        }
 869
 870        return len;
 871}
 872
 873/* Return the position of the end of the trailers. */
 874static int find_trailer_end(const char *buf, size_t len)
 875{
 876        return len - ignore_non_trailer(buf, len);
 877}
 878
 879static int ends_with_blank_line(const char *buf, size_t len)
 880{
 881        int ll = last_line(buf, len);
 882        if (ll < 0)
 883                return 0;
 884        return is_blank_line(buf + ll);
 885}
 886
 887static int process_input_file(FILE *outfile,
 888                              const char *str,
 889                              struct list_head *head)
 890{
 891        struct trailer_info info;
 892        struct strbuf tok = STRBUF_INIT;
 893        struct strbuf val = STRBUF_INIT;
 894        int i;
 895
 896        trailer_info_get(&info, str);
 897
 898        /* Print lines before the trailers as is */
 899        fwrite(str, 1, info.trailer_start - str, outfile);
 900
 901        if (!info.blank_line_before_trailer)
 902                fprintf(outfile, "\n");
 903
 904        for (i = 0; i < info.trailer_nr; i++) {
 905                int separator_pos;
 906                char *trailer = info.trailers[i];
 907                if (trailer[0] == comment_line_char)
 908                        continue;
 909                separator_pos = find_separator(trailer, separators);
 910                if (separator_pos >= 1) {
 911                        parse_trailer(&tok, &val, NULL, trailer,
 912                                      separator_pos);
 913                        add_trailer_item(head,
 914                                         strbuf_detach(&tok, NULL),
 915                                         strbuf_detach(&val, NULL));
 916                } else {
 917                        strbuf_addstr(&val, trailer);
 918                        strbuf_strip_suffix(&val, "\n");
 919                        add_trailer_item(head,
 920                                         NULL,
 921                                         strbuf_detach(&val, NULL));
 922                }
 923        }
 924
 925        trailer_info_release(&info);
 926
 927        return info.trailer_end - str;
 928}
 929
 930static void free_all(struct list_head *head)
 931{
 932        struct list_head *pos, *p;
 933        list_for_each_safe(pos, p, head) {
 934                list_del(pos);
 935                free_trailer_item(list_entry(pos, struct trailer_item, list));
 936        }
 937}
 938
 939static struct tempfile trailers_tempfile;
 940
 941static FILE *create_in_place_tempfile(const char *file)
 942{
 943        struct stat st;
 944        struct strbuf template = STRBUF_INIT;
 945        const char *tail;
 946        FILE *outfile;
 947
 948        if (stat(file, &st))
 949                die_errno(_("could not stat %s"), file);
 950        if (!S_ISREG(st.st_mode))
 951                die(_("file %s is not a regular file"), file);
 952        if (!(st.st_mode & S_IWUSR))
 953                die(_("file %s is not writable by user"), file);
 954
 955        /* Create temporary file in the same directory as the original */
 956        tail = strrchr(file, '/');
 957        if (tail != NULL)
 958                strbuf_add(&template, file, tail - file + 1);
 959        strbuf_addstr(&template, "git-interpret-trailers-XXXXXX");
 960
 961        xmks_tempfile_m(&trailers_tempfile, template.buf, st.st_mode);
 962        strbuf_release(&template);
 963        outfile = fdopen_tempfile(&trailers_tempfile, "w");
 964        if (!outfile)
 965                die_errno(_("could not open temporary file"));
 966
 967        return outfile;
 968}
 969
 970void process_trailers(const char *file, int in_place, int trim_empty, struct string_list *trailers)
 971{
 972        LIST_HEAD(head);
 973        LIST_HEAD(arg_head);
 974        struct strbuf sb = STRBUF_INIT;
 975        int trailer_end;
 976        FILE *outfile = stdout;
 977
 978        ensure_configured();
 979
 980        read_input_file(&sb, file);
 981
 982        if (in_place)
 983                outfile = create_in_place_tempfile(file);
 984
 985        /* Print the lines before the trailers */
 986        trailer_end = process_input_file(outfile, sb.buf, &head);
 987
 988        process_command_line_args(&arg_head, trailers);
 989
 990        process_trailers_lists(&head, &arg_head);
 991
 992        print_all(outfile, &head, trim_empty);
 993
 994        free_all(&head);
 995
 996        /* Print the lines after the trailers as is */
 997        fwrite(sb.buf + trailer_end, 1, sb.len - trailer_end, outfile);
 998
 999        if (in_place)
1000                if (rename_tempfile(&trailers_tempfile, file))
1001                        die_errno(_("could not rename temporary file to %s"), file);
1002
1003        strbuf_release(&sb);
1004}
1005
1006void 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
1049void 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}