diff options
author | Junio C Hamano <junkio@cox.net> | 2006-05-28 22:47:53 -0700 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2006-05-28 22:47:53 -0700 |
commit | 0a2586c807fadc4b13a741e693471765870f6bb4 (patch) | |
tree | 9c62558c76d02057e71f6152c8d73b9cb1cf536e /builtin-cat-file.c | |
parent | Merge branch 'jc/dirwalk-n-cache-tree' into jc/cache-tree (diff) | |
parent | Remove "tree->entries" tree-entry list from tree parser (diff) | |
download | tgif-0a2586c807fadc4b13a741e693471765870f6bb4.tar.xz |
Merge branch 'lt/tree' into jc/lt-tree-n-cache-tree
* lt/tree: (98 commits)
Remove "tree->entries" tree-entry list from tree parser
Switch "read_tree_recursive()" over to tree-walk functionality
Make "tree_entry" have a SHA1 instead of a union of object pointers
Add raw tree buffer info to "struct tree"
Don't use "sscanf()" for tree mode scanning
git-fetch: avoid using "case ... in (arm)"
mailinfo: skip bogus UNIX From line inside body
mailinfo: More carefully parse header lines in read_one_header_line()
Allow in body headers beyond the in body header prefix.
More accurately detect header lines in read_one_header_line
In handle_body only read a line if we don't already have one.
Refactor commit messge handling.
Move B and Q decoding into check header.
Make read_one_header_line return a flag not a length.
Fix memory leak in "git rev-list --objects"
gitview: Move the console error messages to message dialog
gitview: Add key binding for F5.
Let git-clone to pass --template=dir option to git-init-db.
Make cvsexportcommit create parent directories as needed.
Document current cvsexportcommit limitations.
...
Conflicts:
Makefile, builtin.h, git.c are trivially resolved.
builtin-read-tree.c needed adjustment for the tree
parser change.
Diffstat (limited to 'builtin-cat-file.c')
-rw-r--r-- | builtin-cat-file.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/builtin-cat-file.c b/builtin-cat-file.c new file mode 100644 index 0000000000..4d36817e5f --- /dev/null +++ b/builtin-cat-file.c @@ -0,0 +1,167 @@ +/* + * GIT - The information manager from hell + * + * Copyright (C) Linus Torvalds, 2005 + */ +#include "cache.h" +#include "exec_cmd.h" +#include "tag.h" +#include "tree.h" +#include "builtin.h" + +static void flush_buffer(const char *buf, unsigned long size) +{ + while (size > 0) { + long ret = xwrite(1, buf, size); + if (ret < 0) { + /* Ignore epipe */ + if (errno == EPIPE) + break; + die("git-cat-file: %s", strerror(errno)); + } else if (!ret) { + die("git-cat-file: disk full?"); + } + size -= ret; + buf += ret; + } +} + +static int pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size) +{ + /* the parser in tag.c is useless here. */ + const char *endp = buf + size; + const char *cp = buf; + + while (cp < endp) { + char c = *cp++; + if (c != '\n') + continue; + if (7 <= endp - cp && !memcmp("tagger ", cp, 7)) { + const char *tagger = cp; + + /* Found the tagger line. Copy out the contents + * of the buffer so far. + */ + flush_buffer(buf, cp - buf); + + /* + * Do something intelligent, like pretty-printing + * the date. + */ + while (cp < endp) { + if (*cp++ == '\n') { + /* tagger to cp is a line + * that has ident and time. + */ + const char *sp = tagger; + char *ep; + unsigned long date; + long tz; + while (sp < cp && *sp != '>') + sp++; + if (sp == cp) { + /* give up */ + flush_buffer(tagger, + cp - tagger); + break; + } + while (sp < cp && + !('0' <= *sp && *sp <= '9')) + sp++; + flush_buffer(tagger, sp - tagger); + date = strtoul(sp, &ep, 10); + tz = strtol(ep, NULL, 10); + sp = show_date(date, tz); + flush_buffer(sp, strlen(sp)); + xwrite(1, "\n", 1); + break; + } + } + break; + } + if (cp < endp && *cp == '\n') + /* end of header */ + break; + } + /* At this point, we have copied out the header up to the end of + * the tagger line and cp points at one past \n. It could be the + * next header line after the tagger line, or it could be another + * \n that marks the end of the headers. We need to copy out the + * remainder as is. + */ + if (cp < endp) + flush_buffer(cp, endp - cp); + return 0; +} + +int cmd_cat_file(int argc, const char **argv, char **envp) +{ + unsigned char sha1[20]; + char type[20]; + void *buf; + unsigned long size; + int opt; + + setup_git_directory(); + git_config(git_default_config); + if (argc != 3) + usage("git-cat-file [-t|-s|-e|-p|<type>] <sha1>"); + if (get_sha1(argv[2], sha1)) + die("Not a valid object name %s", argv[2]); + + opt = 0; + if ( argv[1][0] == '-' ) { + opt = argv[1][1]; + if ( !opt || argv[1][2] ) + opt = -1; /* Not a single character option */ + } + + buf = NULL; + switch (opt) { + case 't': + if (!sha1_object_info(sha1, type, NULL)) { + printf("%s\n", type); + return 0; + } + break; + + case 's': + if (!sha1_object_info(sha1, type, &size)) { + printf("%lu\n", size); + return 0; + } + break; + + case 'e': + return !has_sha1_file(sha1); + + case 'p': + if (sha1_object_info(sha1, type, NULL)) + die("Not a valid object name %s", argv[2]); + + /* custom pretty-print here */ + if (!strcmp(type, tree_type)) + return cmd_ls_tree(2, argv + 1, NULL); + + buf = read_sha1_file(sha1, type, &size); + if (!buf) + die("Cannot read object %s", argv[2]); + if (!strcmp(type, tag_type)) + return pprint_tag(sha1, buf, size); + + /* otherwise just spit out the data */ + break; + case 0: + buf = read_object_with_reference(sha1, argv[1], &size, NULL); + break; + + default: + die("git-cat-file: unknown option: %s\n", argv[1]); + } + + if (!buf) + die("git-cat-file %s: bad file", argv[2]); + + flush_buffer(buf, size); + return 0; +} |