c096dc45ee7606c2b2947400f66c350f5801cb06
   1/*
   2 * rev-parse.c
   3 *
   4 * Copyright (C) Linus Torvalds, 2005
   5 */
   6#include "cache.h"
   7#include "commit.h"
   8#include "refs.h"
   9
  10static char *def = NULL;
  11static int no_revs = 0;
  12static int single_rev = 0;
  13static int revs_only = 0;
  14static int do_rev_argument = 1;
  15static int output_revs = 0;
  16
  17#define NORMAL 0
  18#define REVERSED 1
  19static int show_type = NORMAL;
  20
  21static int get_extended_sha1(char *name, unsigned char *sha1);
  22
  23/*
  24 * Some arguments are relevant "revision" arguments,
  25 * others are about output format or other details.
  26 * This sorts it all out.
  27 */
  28static int is_rev_argument(const char *arg)
  29{
  30        static const char *rev_args[] = {
  31                "--max-count=",
  32                "--max-age=",
  33                "--min-age=",
  34                "--merge-order",
  35                NULL
  36        };
  37        const char **p = rev_args;
  38
  39        for (;;) {
  40                const char *str = *p++;
  41                int len;
  42                if (!str)
  43                        return 0;
  44                len = strlen(str);
  45                if (!strncmp(arg, str, len))
  46                        return 1;
  47        }
  48}
  49
  50static void show_rev(int type, const unsigned char *sha1)
  51{
  52        if (no_revs)
  53                return;
  54        output_revs++;
  55        printf("%s%s\n", type == show_type ? "" : "^", sha1_to_hex(sha1));
  56}
  57
  58static void show_rev_arg(char *rev)
  59{
  60        if (no_revs)
  61                return;
  62        puts(rev);
  63}
  64
  65static void show_norev(char *norev)
  66{
  67        if (revs_only)
  68                return;
  69        puts(norev);
  70}
  71
  72static void show_arg(char *arg)
  73{
  74        if (do_rev_argument && is_rev_argument(arg))
  75                show_rev_arg(arg);
  76        else
  77                show_norev(arg);
  78}
  79
  80static int get_parent(char *name, unsigned char *result, int idx)
  81{
  82        unsigned char sha1[20];
  83        int ret = get_extended_sha1(name, sha1);
  84        struct commit *commit;
  85        struct commit_list *p;
  86
  87        if (ret)
  88                return ret;
  89        commit = lookup_commit_reference(sha1);
  90        if (!commit)
  91                return -1;
  92        if (parse_commit(commit))
  93                return -1;
  94        p = commit->parents;
  95        while (p) {
  96                if (!--idx) {
  97                        memcpy(result, p->item->object.sha1, 20);
  98                        return 0;
  99                }
 100                p = p->next;
 101        }
 102        return -1;
 103}
 104
 105/*
 106 * This is like "get_sha1()", except it allows "sha1 expressions",
 107 * notably "xyz^" for "parent of xyz"
 108 */
 109static int get_extended_sha1(char *name, unsigned char *sha1)
 110{
 111        int parent;
 112        int len = strlen(name);
 113
 114        parent = 1;
 115        if (len > 2 && name[len-1] >= '1' && name[len-1] <= '9') {
 116                parent = name[len-1] - '0';
 117                len--;
 118        }
 119        if (len > 1 && name[len-1] == '^') {
 120                int ret;
 121                name[len-1] = 0;
 122                ret = get_parent(name, sha1, parent);
 123                name[len-1] = '^';
 124                if (!ret)
 125                        return 0;
 126        }
 127        return get_sha1(name, sha1);
 128}
 129
 130static void show_default(void)
 131{
 132        char *s = def;
 133
 134        if (s) {
 135                unsigned char sha1[20];
 136
 137                def = NULL;
 138                if (!get_extended_sha1(s, sha1)) {
 139                        show_rev(NORMAL, sha1);
 140                        return;
 141                }
 142                show_arg(s);
 143        }
 144}
 145
 146static int show_reference(const char *refname, const unsigned char *sha1)
 147{
 148        show_rev(NORMAL, sha1);
 149        return 0;
 150}
 151
 152int main(int argc, char **argv)
 153{
 154        int i, as_is = 0;
 155        unsigned char sha1[20];
 156
 157        for (i = 1; i < argc; i++) {
 158                char *arg = argv[i];
 159                char *dotdot;
 160        
 161                if (as_is) {
 162                        show_norev(arg);
 163                        continue;
 164                }
 165                if (*arg == '-') {
 166                        if (!strcmp(arg, "--")) {
 167                                show_default();
 168                                if (revs_only)
 169                                        break;
 170                                as_is = 1;
 171                        }
 172                        if (!strcmp(arg, "--default")) {
 173                                def = argv[i+1];
 174                                i++;
 175                                continue;
 176                        }
 177                        if (!strcmp(arg, "--revs-only")) {
 178                                revs_only = 1;
 179                                continue;
 180                        }
 181                        if (!strcmp(arg, "--no-revs")) {
 182                                no_revs = 1;
 183                                continue;
 184                        }
 185                        if (!strcmp(arg, "--verify")) {
 186                                revs_only = 1;
 187                                do_rev_argument = 0;
 188                                single_rev = 1;
 189                                continue;
 190                        }
 191                        if (!strcmp(arg, "--not")) {
 192                                show_type ^= REVERSED;
 193                                continue;
 194                        }
 195                        if (!strcmp(arg, "--all")) {
 196                                for_each_ref(show_reference);
 197                                continue;
 198                        }
 199                        show_arg(arg);
 200                        continue;
 201                }
 202                dotdot = strstr(arg, "..");
 203                if (dotdot) {
 204                        unsigned char end[20];
 205                        char *n = dotdot+2;
 206                        *dotdot = 0;
 207                        if (!get_extended_sha1(arg, sha1)) {
 208                                if (!*n)
 209                                        n = "HEAD";
 210                                if (!get_extended_sha1(n, end)) {
 211                                        if (no_revs)
 212                                                continue;
 213                                        def = NULL;
 214                                        show_rev(NORMAL, end);
 215                                        show_rev(REVERSED, sha1);
 216                                        continue;
 217                                }
 218                        }
 219                        *dotdot = '.';
 220                }
 221                if (!get_extended_sha1(arg, sha1)) {
 222                        if (no_revs)
 223                                continue;
 224                        def = NULL;
 225                        show_rev(NORMAL, sha1);
 226                        continue;
 227                }
 228                if (*arg == '^' && !get_extended_sha1(arg+1, sha1)) {
 229                        if (no_revs)
 230                                continue;
 231                        def = NULL;
 232                        show_rev(REVERSED, sha1);
 233                        continue;
 234                }
 235                show_default();
 236                show_norev(arg);
 237        }
 238        show_default();
 239        if (single_rev && output_revs != 1) {
 240                fprintf(stderr, "Needed a single revision\n");
 241                exit(1);
 242        }
 243        return 0;
 244}