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