rev-parse.con commit Merge git://git.kernel.org/pub/scm/gitk/gitk (0825de8)
   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#include "quote.h"
  10
  11#define DO_REVS         1
  12#define DO_NOREV        2
  13#define DO_FLAGS        4
  14#define DO_NONFLAGS     8
  15static int filter = ~0;
  16
  17static char *def = NULL;
  18
  19#define NORMAL 0
  20#define REVERSED 1
  21static int show_type = NORMAL;
  22static int symbolic = 0;
  23static int abbrev = 0;
  24static int output_sq = 0;
  25
  26static int revs_count = 0;
  27
  28/*
  29 * Some arguments are relevant "revision" arguments,
  30 * others are about output format or other details.
  31 * This sorts it all out.
  32 */
  33static int is_rev_argument(const char *arg)
  34{
  35        static const char *rev_args[] = {
  36                "--all",
  37                "--bisect",
  38                "--dense",
  39                "--branches",
  40                "--header",
  41                "--max-age=",
  42                "--max-count=",
  43                "--min-age=",
  44                "--no-merges",
  45                "--objects",
  46                "--objects-edge",
  47                "--parents",
  48                "--pretty",
  49                "--remotes",
  50                "--sparse",
  51                "--tags",
  52                "--topo-order",
  53                "--date-order",
  54                "--unpacked",
  55                NULL
  56        };
  57        const char **p = rev_args;
  58
  59        /* accept -<digit>, like traditional "head" */
  60        if ((*arg == '-') && isdigit(arg[1]))
  61                return 1;
  62
  63        for (;;) {
  64                const char *str = *p++;
  65                int len;
  66                if (!str)
  67                        return 0;
  68                len = strlen(str);
  69                if (!strcmp(arg, str) ||
  70                    (str[len-1] == '=' && !strncmp(arg, str, len)))
  71                        return 1;
  72        }
  73}
  74
  75/* Output argument as a string, either SQ or normal */
  76static void show(const char *arg)
  77{
  78        if (output_sq) {
  79                int sq = '\'', ch;
  80
  81                putchar(sq);
  82                while ((ch = *arg++)) {
  83                        if (ch == sq)
  84                                fputs("'\\'", stdout);
  85                        putchar(ch);
  86                }
  87                putchar(sq);
  88                putchar(' ');
  89        }
  90        else
  91                puts(arg);
  92}
  93
  94/* Output a revision, only if filter allows it */
  95static void show_rev(int type, const unsigned char *sha1, const char *name)
  96{
  97        if (!(filter & DO_REVS))
  98                return;
  99        def = NULL;
 100        revs_count++;
 101
 102        if (type != show_type)
 103                putchar('^');
 104        if (symbolic && name)
 105                show(name);
 106        else if (abbrev)
 107                show(find_unique_abbrev(sha1, abbrev));
 108        else
 109                show(sha1_to_hex(sha1));
 110}
 111
 112/* Output a flag, only if filter allows it. */
 113static int show_flag(char *arg)
 114{
 115        if (!(filter & DO_FLAGS))
 116                return 0;
 117        if (filter & (is_rev_argument(arg) ? DO_REVS : DO_NOREV)) {
 118                show(arg);
 119                return 1;
 120        }
 121        return 0;
 122}
 123
 124static void show_default(void)
 125{
 126        char *s = def;
 127
 128        if (s) {
 129                unsigned char sha1[20];
 130
 131                def = NULL;
 132                if (!get_sha1(s, sha1)) {
 133                        show_rev(NORMAL, sha1, s);
 134                        return;
 135                }
 136        }
 137}
 138
 139static int show_reference(const char *refname, const unsigned char *sha1)
 140{
 141        show_rev(NORMAL, sha1, refname);
 142        return 0;
 143}
 144
 145static void show_datestring(const char *flag, const char *datestr)
 146{
 147        static char buffer[100];
 148
 149        /* date handling requires both flags and revs */
 150        if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))
 151                return;
 152        snprintf(buffer, sizeof(buffer), "%s%lu", flag, approxidate(datestr));
 153        show(buffer);
 154}
 155
 156static int show_file(const char *arg)
 157{
 158        show_default();
 159        if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
 160                show(arg);
 161                return 1;
 162        }
 163        return 0;
 164}
 165
 166int main(int argc, char **argv)
 167{
 168        int i, as_is = 0, verify = 0;
 169        unsigned char sha1[20];
 170        const char *prefix = setup_git_directory();
 171
 172        git_config(git_default_config);
 173
 174        for (i = 1; i < argc; i++) {
 175                char *arg = argv[i];
 176                char *dotdot;
 177
 178                if (as_is) {
 179                        if (show_file(arg) && as_is < 2)
 180                                verify_filename(prefix, arg);
 181                        continue;
 182                }
 183                if (!strcmp(arg,"-n")) {
 184                        if (++i >= argc)
 185                                die("-n requires an argument");
 186                        if ((filter & DO_FLAGS) && (filter & DO_REVS)) {
 187                                show(arg);
 188                                show(argv[i]);
 189                        }
 190                        continue;
 191                }
 192                if (!strncmp(arg,"-n",2)) {
 193                        if ((filter & DO_FLAGS) && (filter & DO_REVS))
 194                                show(arg);
 195                        continue;
 196                }
 197
 198                if (*arg == '-') {
 199                        if (!strcmp(arg, "--")) {
 200                                as_is = 2;
 201                                /* Pass on the "--" if we show anything but files.. */
 202                                if (filter & (DO_FLAGS | DO_REVS))
 203                                        show_file(arg);
 204                                continue;
 205                        }
 206                        if (!strcmp(arg, "--default")) {
 207                                def = argv[i+1];
 208                                i++;
 209                                continue;
 210                        }
 211                        if (!strcmp(arg, "--revs-only")) {
 212                                filter &= ~DO_NOREV;
 213                                continue;
 214                        }
 215                        if (!strcmp(arg, "--no-revs")) {
 216                                filter &= ~DO_REVS;
 217                                continue;
 218                        }
 219                        if (!strcmp(arg, "--flags")) {
 220                                filter &= ~DO_NONFLAGS;
 221                                continue;
 222                        }
 223                        if (!strcmp(arg, "--no-flags")) {
 224                                filter &= ~DO_FLAGS;
 225                                continue;
 226                        }
 227                        if (!strcmp(arg, "--verify")) {
 228                                filter &= ~(DO_FLAGS|DO_NOREV);
 229                                verify = 1;
 230                                continue;
 231                        }
 232                        if (!strcmp(arg, "--short") ||
 233                            !strncmp(arg, "--short=", 8)) {
 234                                filter &= ~(DO_FLAGS|DO_NOREV);
 235                                verify = 1;
 236                                abbrev = DEFAULT_ABBREV;
 237                                if (arg[7] == '=')
 238                                        abbrev = strtoul(arg + 8, NULL, 10);
 239                                if (abbrev < MINIMUM_ABBREV)
 240                                        abbrev = MINIMUM_ABBREV;
 241                                else if (40 <= abbrev)
 242                                        abbrev = 40;
 243                                continue;
 244                        }
 245                        if (!strcmp(arg, "--sq")) {
 246                                output_sq = 1;
 247                                continue;
 248                        }
 249                        if (!strcmp(arg, "--not")) {
 250                                show_type ^= REVERSED;
 251                                continue;
 252                        }
 253                        if (!strcmp(arg, "--symbolic")) {
 254                                symbolic = 1;
 255                                continue;
 256                        }
 257                        if (!strcmp(arg, "--all")) {
 258                                for_each_ref(show_reference);
 259                                continue;
 260                        }
 261                        if (!strcmp(arg, "--branches")) {
 262                                for_each_branch_ref(show_reference);
 263                                continue;
 264                        }
 265                        if (!strcmp(arg, "--tags")) {
 266                                for_each_tag_ref(show_reference);
 267                                continue;
 268                        }
 269                        if (!strcmp(arg, "--remotes")) {
 270                                for_each_remote_ref(show_reference);
 271                                continue;
 272                        }
 273                        if (!strcmp(arg, "--show-prefix")) {
 274                                if (prefix)
 275                                        puts(prefix);
 276                                continue;
 277                        }
 278                        if (!strcmp(arg, "--show-cdup")) {
 279                                const char *pfx = prefix;
 280                                while (pfx) {
 281                                        pfx = strchr(pfx, '/');
 282                                        if (pfx) {
 283                                                pfx++;
 284                                                printf("../");
 285                                        }
 286                                }
 287                                putchar('\n');
 288                                continue;
 289                        }
 290                        if (!strcmp(arg, "--git-dir")) {
 291                                const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
 292                                static char cwd[PATH_MAX];
 293                                if (gitdir) {
 294                                        puts(gitdir);
 295                                        continue;
 296                                }
 297                                if (!prefix) {
 298                                        puts(".git");
 299                                        continue;
 300                                }
 301                                if (!getcwd(cwd, PATH_MAX))
 302                                        die("unable to get current working directory");
 303                                printf("%s/.git\n", cwd);
 304                                continue;
 305                        }
 306                        if (!strncmp(arg, "--since=", 8)) {
 307                                show_datestring("--max-age=", arg+8);
 308                                continue;
 309                        }
 310                        if (!strncmp(arg, "--after=", 8)) {
 311                                show_datestring("--max-age=", arg+8);
 312                                continue;
 313                        }
 314                        if (!strncmp(arg, "--before=", 9)) {
 315                                show_datestring("--min-age=", arg+9);
 316                                continue;
 317                        }
 318                        if (!strncmp(arg, "--until=", 8)) {
 319                                show_datestring("--min-age=", arg+8);
 320                                continue;
 321                        }
 322                        if (show_flag(arg) && verify)
 323                                die("Needed a single revision");
 324                        continue;
 325                }
 326
 327                /* Not a flag argument */
 328                dotdot = strstr(arg, "..");
 329                if (dotdot) {
 330                        unsigned char end[20];
 331                        char *next = dotdot + 2;
 332                        char *this = arg;
 333                        *dotdot = 0;
 334                        if (!*next)
 335                                next = "HEAD";
 336                        if (dotdot == arg)
 337                                this = "HEAD";
 338                        if (!get_sha1(this, sha1) && !get_sha1(next, end)) {
 339                                show_rev(NORMAL, end, next);
 340                                show_rev(REVERSED, sha1, this);
 341                                continue;
 342                        }
 343                        *dotdot = '.';
 344                }
 345                if (!get_sha1(arg, sha1)) {
 346                        show_rev(NORMAL, sha1, arg);
 347                        continue;
 348                }
 349                if (*arg == '^' && !get_sha1(arg+1, sha1)) {
 350                        show_rev(REVERSED, sha1, arg+1);
 351                        continue;
 352                }
 353                as_is = 1;
 354                if (!show_file(arg))
 355                        continue;
 356                if (verify)
 357                        die("Needed a single revision");
 358                verify_filename(prefix, arg);
 359        }
 360        show_default();
 361        if (verify && revs_count != 1)
 362                die("Needed a single revision");
 363        return 0;
 364}