07db863bbcec0427b3b73dcf355e94925f32253c
   1/*
   2 * GIT - The information manager from hell
   3 *
   4 * Copyright (C) Linus Torvalds, 2005
   5 */
   6#include "cache.h"
   7#include "blob.h"
   8#include "tree.h"
   9#include "quote.h"
  10
  11static int line_termination = '\n';
  12#define LS_RECURSIVE 1
  13#define LS_TREE_ONLY 2
  14#define LS_SHOW_TREES 4
  15static int ls_options = 0;
  16const char **pathspec;
  17
  18static const char ls_tree_usage[] =
  19        "git-ls-tree [-d] [-r] [-t] [-z] <tree-ish> [path...]";
  20
  21static int show_recursive(const char *base, int baselen, const char *pathname)
  22{
  23        const char **s;
  24
  25        if (ls_options & LS_RECURSIVE)
  26                return 1;
  27
  28        s = pathspec;
  29        if (!s)
  30                return 0;
  31
  32        for (;;) {
  33                const char *spec = *s++;
  34                int len, speclen;
  35
  36                if (!spec)
  37                        return 0;
  38                if (strncmp(base, spec, baselen))
  39                        continue;
  40                len = strlen(pathname);
  41                spec += baselen;
  42                speclen = strlen(spec);
  43                if (speclen <= len)
  44                        continue;
  45                if (memcmp(pathname, spec, len))
  46                        continue;
  47                return 1;
  48        }
  49}
  50
  51static int show_tree(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
  52{
  53        int retval = 0;
  54        const char *type = "blob";
  55
  56        if (S_ISDIR(mode)) {
  57                if (show_recursive(base, baselen, pathname)) {
  58                        retval = READ_TREE_RECURSIVE;
  59                        if (!(ls_options & LS_SHOW_TREES))
  60                                return retval;
  61                }
  62                type = "tree";
  63        }
  64        else if (ls_options & LS_TREE_ONLY)
  65                return 0;
  66
  67        printf("%06o %s %s\t", mode, type, sha1_to_hex(sha1));
  68        write_name_quoted(base, baselen, pathname, line_termination, stdout);
  69        putchar(line_termination);
  70        return retval;
  71}
  72
  73int main(int argc, const char **argv)
  74{
  75        const char *prefix;
  76        unsigned char sha1[20];
  77        char *buf;
  78        unsigned long size;
  79
  80        prefix = setup_git_directory();
  81        while (1 < argc && argv[1][0] == '-') {
  82                switch (argv[1][1]) {
  83                case 'z':
  84                        line_termination = 0;
  85                        break;
  86                case 'r':
  87                        ls_options |= LS_RECURSIVE;
  88                        break;
  89                case 'd':
  90                        ls_options |= LS_TREE_ONLY;
  91                        break;
  92                case 't':
  93                        ls_options |= LS_SHOW_TREES;
  94                        break;
  95                default:
  96                        usage(ls_tree_usage);
  97                }
  98                argc--; argv++;
  99        }
 100        /* -d -r should imply -t, but -d by itself should not have to. */
 101        if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
 102            ((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
 103                ls_options |= LS_SHOW_TREES;
 104
 105        if (argc < 2)
 106                usage(ls_tree_usage);
 107        if (get_sha1(argv[1], sha1) < 0)
 108                usage(ls_tree_usage);
 109
 110        pathspec = get_pathspec(prefix, argv + 2);
 111        buf = read_object_with_reference(sha1, "tree", &size, NULL);
 112        if (!buf)
 113                die("not a tree object");
 114        read_tree_recursive(buf, size, "", 0, 0, pathspec, show_tree);
 115
 116        return 0;
 117}