2  * GIT - The information manager from hell
 
   4  * Copyright (C) Linus Torvalds, 2005
 
  11 #include "parse-options.h"
 
  18 static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size)
 
  20         /* the parser in tag.c is useless here. */
 
  21         const char *endp = buf + size;
 
  28                 if (7 <= endp - cp && !memcmp("tagger ", cp, 7)) {
 
  29                         const char *tagger = cp;
 
  31                         /* Found the tagger line.  Copy out the contents
 
  32                          * of the buffer so far.
 
  34                         write_or_die(1, buf, cp - buf);
 
  37                          * Do something intelligent, like pretty-printing
 
  42                                         /* tagger to cp is a line
 
  43                                          * that has ident and time.
 
  45                                         const char *sp = tagger;
 
  49                                         while (sp < cp && *sp != '>')
 
  53                                                 write_or_die(1, tagger,
 
  58                                                !('0' <= *sp && *sp <= '9'))
 
  60                                         write_or_die(1, tagger, sp - tagger);
 
  61                                         date = strtoul(sp, &ep, 10);
 
  62                                         tz = strtol(ep, NULL, 10);
 
  63                                         sp = show_date(date, tz, 0);
 
  64                                         write_or_die(1, sp, strlen(sp));
 
  71                 if (cp < endp && *cp == '\n')
 
  75         /* At this point, we have copied out the header up to the end of
 
  76          * the tagger line and cp points at one past \n.  It could be the
 
  77          * next header line after the tagger line, or it could be another
 
  78          * \n that marks the end of the headers.  We need to copy out the
 
  82                 write_or_die(1, cp, endp - cp);
 
  85 static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
 
  87         unsigned char sha1[20];
 
  88         enum object_type type;
 
  91         struct object_context obj_context;
 
  93         if (get_sha1_with_context(obj_name, sha1, &obj_context))
 
  94                 die("Not a valid object name %s", obj_name);
 
  99                 type = sha1_object_info(sha1, NULL);
 
 101                         printf("%s\n", typename(type));
 
 107                 type = sha1_object_info(sha1, &size);
 
 109                         printf("%lu\n", size);
 
 115                 return !has_sha1_file(sha1);
 
 118                 type = sha1_object_info(sha1, NULL);
 
 120                         die("Not a valid object name %s", obj_name);
 
 122                 /* custom pretty-print here */
 
 123                 if (type == OBJ_TREE) {
 
 124                         const char *ls_args[3] = { NULL };
 
 125                         ls_args[0] =  "ls-tree";
 
 126                         ls_args[1] =  obj_name;
 
 127                         return cmd_ls_tree(2, ls_args, NULL);
 
 130                 buf = read_sha1_file(sha1, &type, &size);
 
 132                         die("Cannot read object %s", obj_name);
 
 133                 if (type == OBJ_TAG) {
 
 134                         pprint_tag(sha1, buf, size);
 
 138                 /* otherwise just spit out the data */
 
 142                 if (!obj_context.path[0])
 
 143                         die("git cat-file --textconv %s: <object> must be <sha1:path>",
 
 146                 if (!textconv_object(obj_context.path, obj_context.mode, sha1, &buf, &size))
 
 147                         die("git cat-file --textconv: unable to run textconv on %s",
 
 152                 buf = read_object_with_reference(sha1, exp_type, &size, NULL);
 
 156                 die("git cat-file: unknown option: %s", exp_type);
 
 160                 die("git cat-file %s: bad file", obj_name);
 
 162         write_or_die(1, buf, size);
 
 166 static int batch_one_object(const char *obj_name, int print_contents)
 
 168         unsigned char sha1[20];
 
 169         enum object_type type = 0;
 
 171         void *contents = contents;
 
 176         if (get_sha1(obj_name, sha1)) {
 
 177                 printf("%s missing\n", obj_name);
 
 182         if (print_contents == BATCH)
 
 183                 contents = read_sha1_file(sha1, &type, &size);
 
 185                 type = sha1_object_info(sha1, &size);
 
 188                 printf("%s missing\n", obj_name);
 
 190                 if (print_contents == BATCH)
 
 195         printf("%s %s %lu\n", sha1_to_hex(sha1), typename(type), size);
 
 198         if (print_contents == BATCH) {
 
 199                 write_or_die(1, contents, size);
 
 208 static int batch_objects(int print_contents)
 
 210         struct strbuf buf = STRBUF_INIT;
 
 212         while (strbuf_getline(&buf, stdin, '\n') != EOF) {
 
 213                 int error = batch_one_object(buf.buf, print_contents);
 
 221 static const char * const cat_file_usage[] = {
 
 222         "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>",
 
 223         "git cat-file (--batch|--batch-check) < <list_of_objects>",
 
 227 static int git_cat_file_config(const char *var, const char *value, void *cb)
 
 229         switch (userdiff_config(var, value)) {
 
 238         return git_default_config(var, value, cb);
 
 241 int cmd_cat_file(int argc, const char **argv, const char *prefix)
 
 243         int opt = 0, batch = 0;
 
 244         const char *exp_type = NULL, *obj_name = NULL;
 
 246         const struct option options[] = {
 
 247                 OPT_GROUP("<type> can be one of: blob, tree, commit, tag"),
 
 248                 OPT_SET_INT('t', NULL, &opt, "show object type", 't'),
 
 249                 OPT_SET_INT('s', NULL, &opt, "show object size", 's'),
 
 250                 OPT_SET_INT('e', NULL, &opt,
 
 251                             "exit with zero when there's no error", 'e'),
 
 252                 OPT_SET_INT('p', NULL, &opt, "pretty-print object's content", 'p'),
 
 253                 OPT_SET_INT(0, "textconv", &opt,
 
 254                             "for blob objects, run textconv on object's content", 'c'),
 
 255                 OPT_SET_INT(0, "batch", &batch,
 
 256                             "show info and content of objects fed from the standard input",
 
 258                 OPT_SET_INT(0, "batch-check", &batch,
 
 259                             "show info about objects fed from the standard input",
 
 264         git_config(git_cat_file_config, NULL);
 
 266         if (argc != 3 && argc != 2)
 
 267                 usage_with_options(cat_file_usage, options);
 
 269         argc = parse_options(argc, argv, prefix, options, cat_file_usage, 0);
 
 275                         usage_with_options(cat_file_usage, options);
 
 277         if (!opt && !batch) {
 
 282                         usage_with_options(cat_file_usage, options);
 
 284         if (batch && (opt || argc)) {
 
 285                 usage_with_options(cat_file_usage, options);
 
 289                 return batch_objects(batch);
 
 291         return cat_one_file(opt, exp_type, obj_name);