List all variables set in .git/config.
+ENVIRONMENT
+-----------
+
+GIT_CONFIG::
+ Take the configuration from the given file instead of .git/config.
+
+GIT_CONFIG_LOCAL::
+ Currently the same as $GIT_CONFIG; when Git will support global
+ configuration files, this will cause it to take the configuration
+ from the global configuration file in addition to the given file.
+
+
EXAMPLE
-------
# The ones that do not have to link with lcrypto, lz nor xdiff.
SIMPLE_PROGRAMS = \
- git-mailsplit$X \
- git-stripspace$X git-daemon$X
+ git-daemon$X
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS = \
git-checkout-index$X git-clone-pack$X \
git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
git-hash-object$X git-index-pack$X git-local-fetch$X \
- git-mailinfo$X git-merge-base$X \
+ git-merge-base$X \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
git-peek-remote$X git-prune-packed$X git-receive-pack$X \
git-send-pack$X git-shell$X \
git-show-index$X git-ssh-fetch$X \
git-ssh-upload$X git-unpack-file$X \
- git-unpack-objects$X git-update-index$X git-update-server-info$X \
- git-upload-pack$X git-verify-pack$X git-write-tree$X \
- git-update-ref$X git-symbolic-ref$X \
+ git-unpack-objects$X git-update-server-info$X \
+ git-upload-pack$X git-verify-pack$X \
+ git-symbolic-ref$X \
git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
git-describe$X git-merge-tree$X git-blame$X git-imap-send$X
-BUILT_INS = git-log$X git-whatchanged$X git-show$X \
- git-count-objects$X git-diff$X git-push$X \
- git-grep$X git-add$X git-rm$X git-rev-list$X \
- git-check-ref-format$X git-rev-parse$X \
+BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \
+ git-count-objects$X git-diff$X git-push$X git-mailsplit$X \
+ git-grep$X git-add$X git-rm$X git-rev-list$X git-stripspace$X \
+ git-check-ref-format$X git-rev-parse$X git-mailinfo$X \
git-init-db$X git-tar-tree$X git-upload-tar$X git-format-patch$X \
git-ls-files$X git-ls-tree$X git-get-tar-commit-id$X \
- git-read-tree$X git-commit-tree$X \
- git-apply$X git-show-branch$X git-diff-files$X \
+ git-read-tree$X git-commit-tree$X git-write-tree$X \
+ git-apply$X git-show-branch$X git-diff-files$X git-update-index$X \
git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X
# what 'all' will build and 'install' will install, in gitexecdir
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
- $(DIFF_OBJS)
+ alloc.o $(DIFF_OBJS)
BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-add.o builtin-rev-list.o builtin-check-ref-format.o \
builtin-rm.o builtin-init-db.o builtin-rev-parse.o \
- builtin-tar-tree.o builtin-upload-tar.o \
- builtin-ls-files.o builtin-ls-tree.o \
- builtin-read-tree.o builtin-commit-tree.o \
+ builtin-tar-tree.o builtin-upload-tar.o builtin-update-index.o \
+ builtin-ls-files.o builtin-ls-tree.o builtin-write-tree.o \
+ builtin-read-tree.o builtin-commit-tree.o builtin-mailinfo.o \
builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
- builtin-cat-file.o
+ builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
+ builtin-update-ref.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
else
ICONV_LINK =
endif
- LIB_4_ICONV = $(ICONV_LINK) -liconv
-else
- LIB_4_ICONV =
+ LIBS += $(ICONV_LINK) -liconv
endif
ifdef NEEDS_SOCKET
LIBS += -lsocket
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIB_FILE) $(SIMPLE_LIB)
-git-mailinfo$X: mailinfo.o $(LIB_FILE)
- $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
- $(LIB_FILE) $(SIMPLE_LIB) $(LIB_4_ICONV)
-
git-local-fetch$X: fetch.o
git-ssh-fetch$X: rsh.o fetch.o
git-ssh-upload$X: rsh.o
--- /dev/null
+/*
+ * alloc.c - specialized allocator for internal objects
+ *
+ * Copyright (C) 2006 Linus Torvalds
+ *
+ * The standard malloc/free wastes too much space for objects, partly because
+ * it maintains all the allocation infrastructure (which isn't needed, since
+ * we never free an object descriptor anyway), but even more because it ends
+ * up with maximal alignment because it doesn't know what the object alignment
+ * for the new allocation is.
+ */
+#include "cache.h"
+#include "object.h"
+#include "blob.h"
+#include "tree.h"
+#include "commit.h"
+#include "tag.h"
+
+#define BLOCKING 1024
+
+#define DEFINE_ALLOCATOR(name) \
+static unsigned int name##_allocs; \
+struct name *alloc_##name##_node(void) \
+{ \
+ static int nr; \
+ static struct name *block; \
+ \
+ if (!nr) { \
+ nr = BLOCKING; \
+ block = xcalloc(BLOCKING, sizeof(struct name)); \
+ } \
+ nr--; \
+ name##_allocs++; \
+ return block++; \
+}
+
+DEFINE_ALLOCATOR(blob)
+DEFINE_ALLOCATOR(tree)
+DEFINE_ALLOCATOR(commit)
+DEFINE_ALLOCATOR(tag)
+
+#define REPORT(name) \
+ fprintf(stderr, "%10s: %8u (%zu kB)\n", #name, name##_allocs, name##_allocs*sizeof(struct name) >> 10)
+
+void alloc_report(void)
+{
+ REPORT(blob);
+ REPORT(tree);
+ REPORT(commit);
+ REPORT(tag);
+}
if (DEBUG)
printf("map: i1: %d %d %p i2: %d %d %p\n",
i1, map[i1],
- i1 != -1 ? blame_lines[map[i1]] : NULL,
+ (void *) (i1 != -1 ? blame_lines[map[i1]] : NULL),
i2, map2[i2],
- i2 != -1 ? blame_lines[map2[i2]] : NULL);
+ (void *) (i2 != -1 ? blame_lines[map2[i2]] : NULL));
if (map2[i2] != -1 &&
blame_lines[map[i1]] &&
!blame_lines[map2[i2]])
{
struct object *obj = lookup_object(sha1);
if (!obj) {
- struct blob *ret = xcalloc(1, sizeof(struct blob));
+ struct blob *ret = alloc_blob_node();
created_object(sha1, &ret->object);
ret->object.type = TYPE_BLOB;
return ret;
* rev.max_count is reasonable (0 <= n <= 3),
* there is no other revision filtering parameters.
*/
- if (rev.pending_objects ||
+ if (rev.pending.nr ||
rev.min_age != -1 || rev.max_age != -1)
usage(diff_files_usage);
/*
* Make sure there is one revision (i.e. pending object),
* and there is no revision filtering parameters.
*/
- if (!rev.pending_objects || rev.pending_objects->next ||
+ if (rev.pending.nr != 1 ||
rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1)
usage(diff_cache_usage);
return run_diff_index(&rev, cached);
char line[1000];
struct object *tree1, *tree2;
static struct rev_info *opt = &log_tree_opt;
- struct object_list *list;
int read_stdin = 0;
git_config(git_diff_config);
}
/*
- * NOTE! "setup_revisions()" will have inserted the revisions
- * it parsed in reverse order. So if you do
- *
- * git-diff-tree a b
- *
- * the commit list will be "b" -> "a" -> NULL, so we reverse
- * the order of the objects if the first one is not marked
- * UNINTERESTING.
+ * NOTE! We expect "a ^b" to be equal to "a..b", so we
+ * reverse the order of the objects if the second one
+ * is marked UNINTERESTING.
*/
- nr_sha1 = 0;
- list = opt->pending_objects;
- if (list) {
- nr_sha1++;
- tree1 = list->item;
- list = list->next;
- if (list) {
- nr_sha1++;
- tree2 = tree1;
- tree1 = list->item;
- if (list->next)
- usage(diff_tree_usage);
- /* Switch them around if the second one was uninteresting.. */
- if (tree2->flags & UNINTERESTING) {
- struct object *tmp = tree2;
- tree2 = tree1;
- tree1 = tmp;
- }
- }
- }
-
+ nr_sha1 = opt->pending.nr;
switch (nr_sha1) {
case 0:
if (!read_stdin)
usage(diff_tree_usage);
break;
case 1:
+ tree1 = opt->pending.objects[0].item;
diff_tree_commit_sha1(tree1->sha1);
break;
case 2:
+ tree1 = opt->pending.objects[0].item;
+ tree2 = opt->pending.objects[1].item;
+ if (tree2->flags & UNINTERESTING) {
+ struct object *tmp = tree2;
+ tree2 = tree1;
+ tree1 = tmp;
+ }
diff_tree_sha1(tree1->sha1,
tree2->sha1,
"", &opt->diffopt);
* specified rev.max_count is reasonable (0 <= n <= 3), and
* there is no other revision filtering parameter.
*/
- if (revs->pending_objects ||
+ if (revs->pending.nr ||
revs->min_age != -1 ||
revs->max_age != -1 ||
3 < revs->max_count)
* Make sure there is one revision (i.e. pending object),
* and there is no revision filtering parameters.
*/
- if (!revs->pending_objects || revs->pending_objects->next ||
+ if (revs->pending.nr != 1 ||
revs->max_count != -1 || revs->min_age != -1 ||
revs->max_age != -1)
usage(builtin_diff_usage);
static int builtin_diff_tree(struct rev_info *revs,
int argc, const char **argv,
- struct object_list *ent)
+ struct object_array_entry *ent)
{
const unsigned char *(sha1[2]);
- int swap = 1;
+ int swap = 0;
while (1 < argc) {
const char *arg = argv[1];
if (!strcmp(arg, "--raw"))
}
/* We saw two trees, ent[0] and ent[1].
- * unless ent[0] is unintesting, they are swapped
+ * if ent[1] is unintesting, they are swapped
*/
- if (ent[0].item->flags & UNINTERESTING)
- swap = 0;
+ if (ent[1].item->flags & UNINTERESTING)
+ swap = 1;
sha1[swap] = ent[0].item->sha1;
sha1[1-swap] = ent[1].item->sha1;
diff_tree_sha1(sha1[0], sha1[1], "", &revs->diffopt);
static int builtin_diff_combined(struct rev_info *revs,
int argc, const char **argv,
- struct object_list *ent,
+ struct object_array_entry *ent,
int ents)
{
const unsigned char (*parent)[20];
obj = parse_object(sha1);
if (!obj)
return;
- add_object(obj, &revs->pending_objects, NULL, "HEAD");
+ add_pending_object(revs, obj, "HEAD");
}
int cmd_diff(int argc, const char **argv, char **envp)
{
+ int i;
struct rev_info rev;
- struct object_list *list, ent[100];
+ struct object_array_entry ent[100];
int ents = 0, blobs = 0, paths = 0;
const char *path = NULL;
struct blobinfo blob[2];
/* Do we have --cached and not have a pending object, then
* default to HEAD by hand. Eek.
*/
- if (!rev.pending_objects) {
+ if (!rev.pending.nr) {
int i;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
}
}
- for (list = rev.pending_objects; list; list = list->next) {
+ for (i = 0; i < rev.pending.nr; i++) {
+ struct object_array_entry *list = rev.pending.objects+i;
struct object *obj = list->item;
const char *name = list->name;
int flags = (obj->flags & UNINTERESTING);
int cached = 0;
int seen_dashdash = 0;
struct grep_opt opt;
- struct object_list *list, **tail, *object_list = NULL;
+ struct object_array list = { 0, 0, NULL };
const char *prefix = setup_git_directory();
const char **paths = NULL;
int i;
* that continues up to the -- (if exists), and then paths.
*/
- tail = &object_list;
while (1 < argc) {
const char *arg = argv[1];
argc--; argv++;
/* Is it a rev? */
if (!get_sha1(arg, sha1)) {
struct object *object = parse_object(sha1);
- struct object_list *elem;
if (!object)
die("bad object %s", arg);
- elem = object_list_insert(object, tail);
- elem->name = arg;
- tail = &elem->next;
+ add_object_array(object, arg, &list);
continue;
}
if (!strcmp(arg, "--")) {
paths[1] = NULL;
}
- if (!object_list)
+ if (!list.nr)
return !grep_cache(&opt, paths, cached);
if (cached)
die("both --cached and trees are given.");
- for (list = object_list; list; list = list->next) {
+ for (i = 0; i < list.nr; i++) {
struct object *real_obj;
- real_obj = deref_tag(list->item, NULL, 0);
- if (grep_object(&opt, paths, real_obj, list->name))
+ real_obj = deref_tag(list.objects[i].item, NULL, 0);
+ if (grep_object(&opt, paths, real_obj, list.objects[i].name))
hit = 1;
}
return !hit;
output_directory);
}
- if (rev.pending_objects && rev.pending_objects->next == NULL) {
- rev.pending_objects->item->flags |= UNINTERESTING;
+ if (rev.pending.nr == 1) {
+ rev.pending.objects[0].item->flags |= UNINTERESTING;
add_head(&rev);
}
--- /dev/null
+/*
+ * Another stupid program, this one parsing the headers of an
+ * email to figure out authorship and subject
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifndef NO_ICONV
+#include <iconv.h>
+#endif
+#include "git-compat-util.h"
+#include "cache.h"
+#include "builtin.h"
+
+static FILE *cmitmsg, *patchfile, *fin, *fout;
+
+static int keep_subject = 0;
+static const char *metainfo_charset = NULL;
+static char line[1000];
+static char date[1000];
+static char name[1000];
+static char email[1000];
+static char subject[1000];
+
+static enum {
+ TE_DONTCARE, TE_QP, TE_BASE64,
+} transfer_encoding;
+static char charset[256];
+
+static char multipart_boundary[1000];
+static int multipart_boundary_len;
+static int patch_lines = 0;
+
+static char *sanity_check(char *name, char *email)
+{
+ int len = strlen(name);
+ if (len < 3 || len > 60)
+ return email;
+ if (strchr(name, '@') || strchr(name, '<') || strchr(name, '>'))
+ return email;
+ return name;
+}
+
+static int bogus_from(char *line)
+{
+ /* John Doe <johndoe> */
+ char *bra, *ket, *dst, *cp;
+
+ /* This is fallback, so do not bother if we already have an
+ * e-mail address.
+ */
+ if (*email)
+ return 0;
+
+ bra = strchr(line, '<');
+ if (!bra)
+ return 0;
+ ket = strchr(bra, '>');
+ if (!ket)
+ return 0;
+
+ for (dst = email, cp = bra+1; cp < ket; )
+ *dst++ = *cp++;
+ *dst = 0;
+ for (cp = line; isspace(*cp); cp++)
+ ;
+ for (bra--; isspace(*bra); bra--)
+ *bra = 0;
+ cp = sanity_check(cp, email);
+ strcpy(name, cp);
+ return 1;
+}
+
+static int handle_from(char *in_line)
+{
+ char line[1000];
+ char *at;
+ char *dst;
+
+ strcpy(line, in_line);
+ at = strchr(line, '@');
+ if (!at)
+ return bogus_from(line);
+
+ /*
+ * If we already have one email, don't take any confusing lines
+ */
+ if (*email && strchr(at+1, '@'))
+ return 0;
+
+ /* Pick up the string around '@', possibly delimited with <>
+ * pair; that is the email part. White them out while copying.
+ */
+ while (at > line) {
+ char c = at[-1];
+ if (isspace(c))
+ break;
+ if (c == '<') {
+ at[-1] = ' ';
+ break;
+ }
+ at--;
+ }
+ dst = email;
+ for (;;) {
+ unsigned char c = *at;
+ if (!c || c == '>' || isspace(c)) {
+ if (c == '>')
+ *at = ' ';
+ break;
+ }
+ *at++ = ' ';
+ *dst++ = c;
+ }
+ *dst++ = 0;
+
+ /* The remainder is name. It could be "John Doe <john.doe@xz>"
+ * or "john.doe@xz (John Doe)", but we have whited out the
+ * email part, so trim from both ends, possibly removing
+ * the () pair at the end.
+ */
+ at = line + strlen(line);
+ while (at > line) {
+ unsigned char c = *--at;
+ if (!isspace(c)) {
+ at[(c == ')') ? 0 : 1] = 0;
+ break;
+ }
+ }
+
+ at = line;
+ for (;;) {
+ unsigned char c = *at;
+ if (!c || !isspace(c)) {
+ if (c == '(')
+ at++;
+ break;
+ }
+ at++;
+ }
+ at = sanity_check(at, email);
+ strcpy(name, at);
+ return 1;
+}
+
+static int handle_date(char *line)
+{
+ strcpy(date, line);
+ return 0;
+}
+
+static int handle_subject(char *line)
+{
+ strcpy(subject, line);
+ return 0;
+}
+
+/* NOTE NOTE NOTE. We do not claim we do full MIME. We just attempt
+ * to have enough heuristics to grok MIME encoded patches often found
+ * on our mailing lists. For example, we do not even treat header lines
+ * case insensitively.
+ */
+
+static int slurp_attr(const char *line, const char *name, char *attr)
+{
+ char *ends, *ap = strcasestr(line, name);
+ size_t sz;
+
+ if (!ap) {
+ *attr = 0;
+ return 0;
+ }
+ ap += strlen(name);
+ if (*ap == '"') {
+ ap++;
+ ends = "\"";
+ }
+ else
+ ends = "; \t";
+ sz = strcspn(ap, ends);
+ memcpy(attr, ap, sz);
+ attr[sz] = 0;
+ return 1;
+}
+
+static int handle_subcontent_type(char *line)
+{
+ /* We do not want to mess with boundary. Note that we do not
+ * handle nested multipart.
+ */
+ if (strcasestr(line, "boundary=")) {
+ fprintf(stderr, "Not handling nested multipart message.\n");
+ exit(1);
+ }
+ slurp_attr(line, "charset=", charset);
+ if (*charset) {
+ int i, c;
+ for (i = 0; (c = charset[i]) != 0; i++)
+ charset[i] = tolower(c);
+ }
+ return 0;
+}
+
+static int handle_content_type(char *line)
+{
+ *multipart_boundary = 0;
+ if (slurp_attr(line, "boundary=", multipart_boundary + 2)) {
+ memcpy(multipart_boundary, "--", 2);
+ multipart_boundary_len = strlen(multipart_boundary);
+ }
+ slurp_attr(line, "charset=", charset);
+ return 0;
+}
+
+static int handle_content_transfer_encoding(char *line)
+{
+ if (strcasestr(line, "base64"))
+ transfer_encoding = TE_BASE64;
+ else if (strcasestr(line, "quoted-printable"))
+ transfer_encoding = TE_QP;
+ else
+ transfer_encoding = TE_DONTCARE;
+ return 0;
+}
+
+static int is_multipart_boundary(const char *line)
+{
+ return (!memcmp(line, multipart_boundary, multipart_boundary_len));
+}
+
+static int eatspace(char *line)
+{
+ int len = strlen(line);
+ while (len > 0 && isspace(line[len-1]))
+ line[--len] = 0;
+ return len;
+}
+
+#define SEEN_FROM 01
+#define SEEN_DATE 02
+#define SEEN_SUBJECT 04
+#define SEEN_BOGUS_UNIX_FROM 010
+#define SEEN_PREFIX 020
+
+/* First lines of body can have From:, Date:, and Subject: or empty */
+static void handle_inbody_header(int *seen, char *line)
+{
+ if (*seen & SEEN_PREFIX)
+ return;
+ if (isspace(*line)) {
+ char *cp;
+ for (cp = line + 1; *cp; cp++) {
+ if (!isspace(*cp))
+ break;
+ }
+ if (!*cp)
+ return;
+ }
+ if (!memcmp(">From", line, 5) && isspace(line[5])) {
+ if (!(*seen & SEEN_BOGUS_UNIX_FROM)) {
+ *seen |= SEEN_BOGUS_UNIX_FROM;
+ return;
+ }
+ }
+ if (!memcmp("From:", line, 5) && isspace(line[5])) {
+ if (!(*seen & SEEN_FROM) && handle_from(line+6)) {
+ *seen |= SEEN_FROM;
+ return;
+ }
+ }
+ if (!memcmp("Date:", line, 5) && isspace(line[5])) {
+ if (!(*seen & SEEN_DATE)) {
+ handle_date(line+6);
+ *seen |= SEEN_DATE;
+ return;
+ }
+ }
+ if (!memcmp("Subject:", line, 8) && isspace(line[8])) {
+ if (!(*seen & SEEN_SUBJECT)) {
+ handle_subject(line+9);
+ *seen |= SEEN_SUBJECT;
+ return;
+ }
+ }
+ if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) {
+ if (!(*seen & SEEN_SUBJECT)) {
+ handle_subject(line);
+ *seen |= SEEN_SUBJECT;
+ return;
+ }
+ }
+ *seen |= SEEN_PREFIX;
+}
+
+static char *cleanup_subject(char *subject)
+{
+ if (keep_subject)
+ return subject;
+ for (;;) {
+ char *p;
+ int len, remove;
+ switch (*subject) {
+ case 'r': case 'R':
+ if (!memcmp("e:", subject+1, 2)) {
+ subject +=3;
+ continue;
+ }
+ break;
+ case ' ': case '\t': case ':':
+ subject++;
+ continue;
+
+ case '[':
+ p = strchr(subject, ']');
+ if (!p) {
+ subject++;
+ continue;
+ }
+ len = strlen(p);
+ remove = p - subject;
+ if (remove <= len *2) {
+ subject = p+1;
+ continue;
+ }
+ break;
+ }
+ eatspace(subject);
+ return subject;
+ }
+}
+
+static void cleanup_space(char *buf)
+{
+ unsigned char c;
+ while ((c = *buf) != 0) {
+ buf++;
+ if (isspace(c)) {
+ buf[-1] = ' ';
+ c = *buf;
+ while (isspace(c)) {
+ int len = strlen(buf);
+ memmove(buf, buf+1, len);
+ c = *buf;
+ }
+ }
+ }
+}
+
+static void decode_header_bq(char *it);
+typedef int (*header_fn_t)(char *);
+struct header_def {
+ const char *name;
+ header_fn_t func;
+ int namelen;
+};
+
+static void check_header(char *line, struct header_def *header)
+{
+ int i;
+
+ if (header[0].namelen <= 0) {
+ for (i = 0; header[i].name; i++)
+ header[i].namelen = strlen(header[i].name);
+ }
+ for (i = 0; header[i].name; i++) {
+ int len = header[i].namelen;
+ if (!strncasecmp(line, header[i].name, len) &&
+ line[len] == ':' && isspace(line[len + 1])) {
+ /* Unwrap inline B and Q encoding, and optionally
+ * normalize the meta information to utf8.
+ */
+ decode_header_bq(line + len + 2);
+ header[i].func(line + len + 2);
+ break;
+ }
+ }
+}
+
+static void check_subheader_line(char *line)
+{
+ static struct header_def header[] = {
+ { "Content-Type", handle_subcontent_type },
+ { "Content-Transfer-Encoding",
+ handle_content_transfer_encoding },
+ { NULL },
+ };
+ check_header(line, header);
+}
+static void check_header_line(char *line)
+{
+ static struct header_def header[] = {
+ { "From", handle_from },
+ { "Date", handle_date },
+ { "Subject", handle_subject },
+ { "Content-Type", handle_content_type },
+ { "Content-Transfer-Encoding",
+ handle_content_transfer_encoding },
+ { NULL },
+ };
+ check_header(line, header);
+}
+
+static int is_rfc2822_header(char *line)
+{
+ /*
+ * The section that defines the loosest possible
+ * field name is "3.6.8 Optional fields".
+ *
+ * optional-field = field-name ":" unstructured CRLF
+ * field-name = 1*ftext
+ * ftext = %d33-57 / %59-126
+ */
+ int ch;
+ char *cp = line;
+ while ((ch = *cp++)) {
+ if (ch == ':')
+ return cp != line;
+ if ((33 <= ch && ch <= 57) ||
+ (59 <= ch && ch <= 126))
+ continue;
+ break;
+ }
+ return 0;
+}
+
+static int read_one_header_line(char *line, int sz, FILE *in)
+{
+ int ofs = 0;
+ while (ofs < sz) {
+ int peek, len;
+ if (fgets(line + ofs, sz - ofs, in) == NULL)
+ break;
+ len = eatspace(line + ofs);
+ if ((len == 0) || !is_rfc2822_header(line)) {
+ /* Re-add the newline */
+ line[ofs + len] = '\n';
+ line[ofs + len + 1] = '\0';
+ break;
+ }
+ ofs += len;
+ /* Yuck, 2822 header "folding" */
+ peek = fgetc(in); ungetc(peek, in);
+ if (peek != ' ' && peek != '\t')
+ break;
+ }
+ /* Count mbox From headers as headers */
+ if (!ofs && !memcmp(line, "From ", 5))
+ ofs = 1;
+ return ofs;
+}
+
+static unsigned hexval(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return ~0;
+}
+
+static int decode_q_segment(char *in, char *ot, char *ep, int rfc2047)
+{
+ int c;
+ while ((c = *in++) != 0 && (in <= ep)) {
+ if (c == '=') {
+ int d = *in++;
+ if (d == '\n' || !d)
+ break; /* drop trailing newline */
+ *ot++ = ((hexval(d) << 4) | hexval(*in++));
+ continue;
+ }
+ if (rfc2047 && c == '_') /* rfc2047 4.2 (2) */
+ c = 0x20;
+ *ot++ = c;
+ }
+ *ot = 0;
+ return 0;
+}
+
+static int decode_b_segment(char *in, char *ot, char *ep)
+{
+ /* Decode in..ep, possibly in-place to ot */
+ int c, pos = 0, acc = 0;
+
+ while ((c = *in++) != 0 && (in <= ep)) {
+ if (c == '+')
+ c = 62;
+ else if (c == '/')
+ c = 63;
+ else if ('A' <= c && c <= 'Z')
+ c -= 'A';
+ else if ('a' <= c && c <= 'z')
+ c -= 'a' - 26;
+ else if ('0' <= c && c <= '9')
+ c -= '0' - 52;
+ else if (c == '=') {
+ /* padding is almost like (c == 0), except we do
+ * not output NUL resulting only from it;
+ * for now we just trust the data.
+ */
+ c = 0;
+ }
+ else
+ continue; /* garbage */
+ switch (pos++) {
+ case 0:
+ acc = (c << 2);
+ break;
+ case 1:
+ *ot++ = (acc | (c >> 4));
+ acc = (c & 15) << 4;
+ break;
+ case 2:
+ *ot++ = (acc | (c >> 2));
+ acc = (c & 3) << 6;
+ break;
+ case 3:
+ *ot++ = (acc | c);
+ acc = pos = 0;
+ break;
+ }
+ }
+ *ot = 0;
+ return 0;
+}
+
+static void convert_to_utf8(char *line, char *charset)
+{
+#ifndef NO_ICONV
+ char *in, *out;
+ size_t insize, outsize, nrc;
+ char outbuf[4096]; /* cheat */
+ static char latin_one[] = "latin1";
+ char *input_charset = *charset ? charset : latin_one;
+ iconv_t conv = iconv_open(metainfo_charset, input_charset);
+
+ if (conv == (iconv_t) -1) {
+ static int warned_latin1_once = 0;
+ if (input_charset != latin_one) {
+ fprintf(stderr, "cannot convert from %s to %s\n",
+ input_charset, metainfo_charset);
+ *charset = 0;
+ }
+ else if (!warned_latin1_once) {
+ warned_latin1_once = 1;
+ fprintf(stderr, "tried to convert from %s to %s, "
+ "but your iconv does not work with it.\n",
+ input_charset, metainfo_charset);
+ }
+ return;
+ }
+ in = line;
+ insize = strlen(in);
+ out = outbuf;
+ outsize = sizeof(outbuf);
+ nrc = iconv(conv, &in, &insize, &out, &outsize);
+ iconv_close(conv);
+ if (nrc == (size_t) -1)
+ return;
+ *out = 0;
+ strcpy(line, outbuf);
+#endif
+}
+
+static void decode_header_bq(char *it)
+{
+ char *in, *out, *ep, *cp, *sp;
+ char outbuf[1000];
+
+ in = it;
+ out = outbuf;
+ while ((ep = strstr(in, "=?")) != NULL) {
+ int sz, encoding;
+ char charset_q[256], piecebuf[256];
+ if (in != ep) {
+ sz = ep - in;
+ memcpy(out, in, sz);
+ out += sz;
+ in += sz;
+ }
+ /* E.g.
+ * ep : "=?iso-2022-jp?B?GyR...?= foo"
+ * ep : "=?ISO-8859-1?Q?Foo=FCbar?= baz"
+ */
+ ep += 2;
+ cp = strchr(ep, '?');
+ if (!cp)
+ return; /* no munging */
+ for (sp = ep; sp < cp; sp++)
+ charset_q[sp - ep] = tolower(*sp);
+ charset_q[cp - ep] = 0;
+ encoding = cp[1];
+ if (!encoding || cp[2] != '?')
+ return; /* no munging */
+ ep = strstr(cp + 3, "?=");
+ if (!ep)
+ return; /* no munging */
+ switch (tolower(encoding)) {
+ default:
+ return; /* no munging */
+ case 'b':
+ sz = decode_b_segment(cp + 3, piecebuf, ep);
+ break;
+ case 'q':
+ sz = decode_q_segment(cp + 3, piecebuf, ep, 1);
+ break;
+ }
+ if (sz < 0)
+ return;
+ if (metainfo_charset)
+ convert_to_utf8(piecebuf, charset_q);
+ strcpy(out, piecebuf);
+ out += strlen(out);
+ in = ep + 2;
+ }
+ strcpy(out, in);
+ strcpy(it, outbuf);
+}
+
+static void decode_transfer_encoding(char *line)
+{
+ char *ep;
+
+ switch (transfer_encoding) {
+ case TE_QP:
+ ep = line + strlen(line);
+ decode_q_segment(line, line, ep, 0);
+ break;
+ case TE_BASE64:
+ ep = line + strlen(line);
+ decode_b_segment(line, line, ep);
+ break;
+ case TE_DONTCARE:
+ break;
+ }
+}
+
+static void handle_info(void)
+{
+ char *sub;
+
+ sub = cleanup_subject(subject);
+ cleanup_space(name);
+ cleanup_space(date);
+ cleanup_space(email);
+ cleanup_space(sub);
+
+ fprintf(fout, "Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n",
+ name, email, sub, date);
+}
+
+/* We are inside message body and have read line[] already.
+ * Spit out the commit log.
+ */
+static int handle_commit_msg(int *seen)
+{
+ if (!cmitmsg)
+ return 0;
+ do {
+ if (!memcmp("diff -", line, 6) ||
+ !memcmp("---", line, 3) ||
+ !memcmp("Index: ", line, 7))
+ break;
+ if ((multipart_boundary[0] && is_multipart_boundary(line))) {
+ /* We come here when the first part had only
+ * the commit message without any patch. We
+ * pretend we have not seen this line yet, and
+ * go back to the loop.
+ */
+ return 1;
+ }
+
+ /* Unwrap transfer encoding and optionally
+ * normalize the log message to UTF-8.
+ */
+ decode_transfer_encoding(line);
+ if (metainfo_charset)
+ convert_to_utf8(line, charset);
+
+ handle_inbody_header(seen, line);
+ if (!(*seen & SEEN_PREFIX))
+ continue;
+
+ fputs(line, cmitmsg);
+ } while (fgets(line, sizeof(line), fin) != NULL);
+ fclose(cmitmsg);
+ cmitmsg = NULL;
+ return 0;
+}
+
+/* We have done the commit message and have the first
+ * line of the patch in line[].
+ */
+static void handle_patch(void)
+{
+ do {
+ if (multipart_boundary[0] && is_multipart_boundary(line))
+ break;
+ /* Only unwrap transfer encoding but otherwise do not
+ * do anything. We do *NOT* want UTF-8 conversion
+ * here; we are dealing with the user payload.
+ */
+ decode_transfer_encoding(line);
+ fputs(line, patchfile);
+ patch_lines++;
+ } while (fgets(line, sizeof(line), fin) != NULL);
+}
+
+/* multipart boundary and transfer encoding are set up for us, and we
+ * are at the end of the sub header. do equivalent of handle_body up
+ * to the next boundary without closing patchfile --- we will expect
+ * that the first part to contain commit message and a patch, and
+ * handle other parts as pure patches.
+ */
+static int handle_multipart_one_part(int *seen)
+{
+ int n = 0;
+
+ while (fgets(line, sizeof(line), fin) != NULL) {
+ again:
+ n++;
+ if (is_multipart_boundary(line))
+ break;
+ if (handle_commit_msg(seen))
+ goto again;
+ handle_patch();
+ break;
+ }
+ if (n == 0)
+ return -1;
+ return 0;
+}
+
+static void handle_multipart_body(void)
+{
+ int seen = 0;
+ int part_num = 0;
+
+ /* Skip up to the first boundary */
+ while (fgets(line, sizeof(line), fin) != NULL)
+ if (is_multipart_boundary(line)) {
+ part_num = 1;
+ break;
+ }
+ if (!part_num)
+ return;
+ /* We are on boundary line. Start slurping the subhead. */
+ while (1) {
+ int hdr = read_one_header_line(line, sizeof(line), fin);
+ if (!hdr) {
+ if (handle_multipart_one_part(&seen) < 0)
+ return;
+ /* Reset per part headers */
+ transfer_encoding = TE_DONTCARE;
+ charset[0] = 0;
+ }
+ else
+ check_subheader_line(line);
+ }
+ fclose(patchfile);
+ if (!patch_lines) {
+ fprintf(stderr, "No patch found\n");
+ exit(1);
+ }
+}
+
+/* Non multipart message */
+static void handle_body(void)
+{
+ int seen = 0;
+
+ handle_commit_msg(&seen);
+ handle_patch();
+ fclose(patchfile);
+ if (!patch_lines) {
+ fprintf(stderr, "No patch found\n");
+ exit(1);
+ }
+}
+
+int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
+ const char *msg, const char *patch)
+{
+ keep_subject = ks;
+ metainfo_charset = encoding;
+ fin = in;
+ fout = out;
+
+ cmitmsg = fopen(msg, "w");
+ if (!cmitmsg) {
+ perror(msg);
+ return -1;
+ }
+ patchfile = fopen(patch, "w");
+ if (!patchfile) {
+ perror(patch);
+ fclose(cmitmsg);
+ return -1;
+ }
+ while (1) {
+ int hdr = read_one_header_line(line, sizeof(line), fin);
+ if (!hdr) {
+ if (multipart_boundary[0])
+ handle_multipart_body();
+ else
+ handle_body();
+ handle_info();
+ break;
+ }
+ check_header_line(line);
+ }
+
+ return 0;
+}
+
+static const char mailinfo_usage[] =
+ "git-mailinfo [-k] [-u | --encoding=<encoding>] msg patch <mail >info";
+
+int cmd_mailinfo(int argc, const char **argv, char **envp)
+{
+ /* NEEDSWORK: might want to do the optional .git/ directory
+ * discovery
+ */
+ git_config(git_default_config);
+
+ while (1 < argc && argv[1][0] == '-') {
+ if (!strcmp(argv[1], "-k"))
+ keep_subject = 1;
+ else if (!strcmp(argv[1], "-u"))
+ metainfo_charset = git_commit_encoding;
+ else if (!strncmp(argv[1], "--encoding=", 11))
+ metainfo_charset = argv[1] + 11;
+ else
+ usage(mailinfo_usage);
+ argc--; argv++;
+ }
+
+ if (argc != 3)
+ usage(mailinfo_usage);
+
+ return !!mailinfo(stdin, stdout, keep_subject, metainfo_charset, argv[1], argv[2]);
+}
--- /dev/null
+/*
+ * Totally braindamaged mbox splitter program.
+ *
+ * It just splits a mbox into a list of files: "0001" "0002" ..
+ * so you can process them further from there.
+ */
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+#include "cache.h"
+#include "builtin.h"
+
+static const char git_mailsplit_usage[] =
+"git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>...";
+
+static int is_from_line(const char *line, int len)
+{
+ const char *colon;
+
+ if (len < 20 || memcmp("From ", line, 5))
+ return 0;
+
+ colon = line + len - 2;
+ line += 5;
+ for (;;) {
+ if (colon < line)
+ return 0;
+ if (*--colon == ':')
+ break;
+ }
+
+ if (!isdigit(colon[-4]) ||
+ !isdigit(colon[-2]) ||
+ !isdigit(colon[-1]) ||
+ !isdigit(colon[ 1]) ||
+ !isdigit(colon[ 2]))
+ return 0;
+
+ /* year */
+ if (strtol(colon+3, NULL, 10) <= 90)
+ return 0;
+
+ /* Ok, close enough */
+ return 1;
+}
+
+/* Could be as small as 64, enough to hold a Unix "From " line. */
+static char buf[4096];
+
+/* Called with the first line (potentially partial)
+ * already in buf[] -- normally that should begin with
+ * the Unix "From " line. Write it into the specified
+ * file.
+ */
+static int split_one(FILE *mbox, const char *name, int allow_bare)
+{
+ FILE *output = NULL;
+ int len = strlen(buf);
+ int fd;
+ int status = 0;
+ int is_bare = !is_from_line(buf, len);
+
+ if (is_bare && !allow_bare)
+ goto corrupt;
+
+ fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ if (fd < 0)
+ die("cannot open output file %s", name);
+ output = fdopen(fd, "w");
+
+ /* Copy it out, while searching for a line that begins with
+ * "From " and having something that looks like a date format.
+ */
+ for (;;) {
+ int is_partial = (buf[len-1] != '\n');
+
+ if (fputs(buf, output) == EOF)
+ die("cannot write output");
+
+ if (fgets(buf, sizeof(buf), mbox) == NULL) {
+ if (feof(mbox)) {
+ status = 1;
+ break;
+ }
+ die("cannot read mbox");
+ }
+ len = strlen(buf);
+ if (!is_partial && !is_bare && is_from_line(buf, len))
+ break; /* done with one message */
+ }
+ fclose(output);
+ return status;
+
+ corrupt:
+ if (output)
+ fclose(output);
+ unlink(name);
+ fprintf(stderr, "corrupt mailbox\n");
+ exit(1);
+}
+
+int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip)
+{
+ char *name = xmalloc(strlen(dir) + 2 + 3 * sizeof(skip));
+ int ret = -1;
+
+ while (*mbox) {
+ const char *file = *mbox++;
+ FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
+ int file_done = 0;
+
+ if ( !f ) {
+ error("cannot open mbox %s", file);
+ goto out;
+ }
+
+ if (fgets(buf, sizeof(buf), f) == NULL) {
+ if (f == stdin)
+ break; /* empty stdin is OK */
+ error("cannot read mbox %s", file);
+ goto out;
+ }
+
+ while (!file_done) {
+ sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+ file_done = split_one(f, name, allow_bare);
+ }
+
+ if (f != stdin)
+ fclose(f);
+ }
+ ret = skip;
+out:
+ free(name);
+ return ret;
+}
+int cmd_mailsplit(int argc, const char **argv, char **envp)
+{
+ int nr = 0, nr_prec = 4, ret;
+ int allow_bare = 0;
+ const char *dir = NULL;
+ const char **argp;
+ static const char *stdin_only[] = { "-", NULL };
+
+ for (argp = argv+1; *argp; argp++) {
+ const char *arg = *argp;
+
+ if (arg[0] != '-')
+ break;
+ /* do flags here */
+ if ( arg[1] == 'd' ) {
+ nr_prec = strtol(arg+2, NULL, 10);
+ if (nr_prec < 3 || 10 <= nr_prec)
+ usage(git_mailsplit_usage);
+ continue;
+ } else if ( arg[1] == 'f' ) {
+ nr = strtol(arg+2, NULL, 10);
+ } else if ( arg[1] == 'b' && !arg[2] ) {
+ allow_bare = 1;
+ } else if ( arg[1] == 'o' && arg[2] ) {
+ dir = arg+2;
+ } else if ( arg[1] == '-' && !arg[2] ) {
+ argp++; /* -- marks end of options */
+ break;
+ } else {
+ die("unknown option: %s", arg);
+ }
+ }
+
+ if ( !dir ) {
+ /* Backwards compatibility: if no -o specified, accept
+ <mbox> <dir> or just <dir> */
+ switch (argc - (argp-argv)) {
+ case 1:
+ dir = argp[0];
+ argp = stdin_only;
+ break;
+ case 2:
+ stdin_only[0] = argp[0];
+ dir = argp[1];
+ argp = stdin_only;
+ break;
+ default:
+ usage(git_mailsplit_usage);
+ }
+ } else {
+ /* New usage: if no more argument, parse stdin */
+ if ( !*argp )
+ argp = stdin_only;
+ }
+
+ ret = split_mbox(argp, dir, allow_bare, nr_prec, nr);
+ if (ret != -1)
+ printf("%d\n", ret);
+
+ return ret == -1;
+}
static struct object_list *trees = NULL;
-static struct cache_entry df_conflict_entry = {
-};
+static struct cache_entry df_conflict_entry;
struct tree_entry_list {
struct tree_entry_list *next;
}
}
-static struct object_list **process_blob(struct blob *blob,
- struct object_list **p,
- struct name_path *path,
- const char *name)
+static void process_blob(struct blob *blob,
+ struct object_array *p,
+ struct name_path *path,
+ const char *name)
{
struct object *obj = &blob->object;
if (!revs.blob_objects)
- return p;
+ return;
if (obj->flags & (UNINTERESTING | SEEN))
- return p;
+ return;
obj->flags |= SEEN;
name = strdup(name);
- return add_object(obj, p, path, name);
+ add_object(obj, p, path, name);
}
-static struct object_list **process_tree(struct tree *tree,
- struct object_list **p,
- struct name_path *path,
- const char *name)
+static void process_tree(struct tree *tree,
+ struct object_array *p,
+ struct name_path *path,
+ const char *name)
{
struct object *obj = &tree->object;
struct tree_desc desc;
struct name_path me;
if (!revs.tree_objects)
- return p;
+ return;
if (obj->flags & (UNINTERESTING | SEEN))
- return p;
+ return;
if (parse_tree(tree) < 0)
die("bad tree object %s", sha1_to_hex(obj->sha1));
obj->flags |= SEEN;
name = strdup(name);
- p = add_object(obj, p, path, name);
+ add_object(obj, p, path, name);
me.up = path;
me.elem = name;
me.elem_len = strlen(name);
while (tree_entry(&desc, &entry)) {
if (S_ISDIR(entry.mode))
- p = process_tree(lookup_tree(entry.sha1), p, &me, entry.path);
+ process_tree(lookup_tree(entry.sha1), p, &me, entry.path);
else
- p = process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
+ process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
}
free(tree->buffer);
tree->buffer = NULL;
- return p;
}
static void show_commit_list(struct rev_info *revs)
{
+ int i;
struct commit *commit;
- struct object_list *objects = NULL, **p = &objects, *pending;
+ struct object_array objects = { 0, 0, NULL };
while ((commit = get_revision(revs)) != NULL) {
- p = process_tree(commit->tree, p, NULL, "");
+ process_tree(commit->tree, &objects, NULL, "");
show_commit(commit);
}
- for (pending = revs->pending_objects; pending; pending = pending->next) {
+ for (i = 0; i < revs->pending.nr; i++) {
+ struct object_array_entry *pending = revs->pending.objects + i;
struct object *obj = pending->item;
const char *name = pending->name;
if (obj->flags & (UNINTERESTING | SEEN))
continue;
if (obj->type == TYPE_TAG) {
obj->flags |= SEEN;
- p = add_object(obj, p, NULL, name);
+ add_object_array(obj, name, &objects);
continue;
}
if (obj->type == TYPE_TREE) {
- p = process_tree((struct tree *)obj, p, NULL, name);
+ process_tree((struct tree *)obj, &objects, NULL, name);
continue;
}
if (obj->type == TYPE_BLOB) {
- p = process_blob((struct blob *)obj, p, NULL, name);
+ process_blob((struct blob *)obj, &objects, NULL, name);
continue;
}
die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
}
- while (objects) {
+ for (i = 0; i < objects.nr; i++) {
+ struct object_array_entry *p = objects.objects + i;
+
/* An object with name "foo\n0000000..." can be used to
* confuse downstream git-pack-objects very badly.
*/
- const char *ep = strchr(objects->name, '\n');
+ const char *ep = strchr(p->name, '\n');
if (ep) {
- printf("%s %.*s\n", sha1_to_hex(objects->item->sha1),
- (int) (ep - objects->name),
- objects->name);
+ printf("%s %.*s\n", sha1_to_hex(p->item->sha1),
+ (int) (ep - p->name),
+ p->name);
}
else
- printf("%s %s\n", sha1_to_hex(objects->item->sha1), objects->name);
- objects = objects->next;
+ printf("%s %s\n", sha1_to_hex(p->item->sha1), p->name);
}
}
if ((!list &&
(!(revs.tag_objects||revs.tree_objects||revs.blob_objects) &&
- !revs.pending_objects)) ||
+ !revs.pending.nr)) ||
revs.diff)
usage(rev_list_usage);
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "builtin.h"
+
+/*
+ * Remove empty lines from the beginning and end.
+ *
+ * Turn multiple consecutive empty lines into just one
+ * empty line. Return true if it is an incomplete line.
+ */
+static int cleanup(char *line)
+{
+ int len = strlen(line);
+
+ if (len && line[len-1] == '\n') {
+ if (len == 1)
+ return 0;
+ do {
+ unsigned char c = line[len-2];
+ if (!isspace(c))
+ break;
+ line[len-2] = '\n';
+ len--;
+ line[len] = 0;
+ } while (len > 1);
+ return 0;
+ }
+ return 1;
+}
+
+void stripspace(FILE *in, FILE *out)
+{
+ int empties = -1;
+ int incomplete = 0;
+ char line[1024];
+
+ while (fgets(line, sizeof(line), in)) {
+ incomplete = cleanup(line);
+
+ /* Not just an empty line? */
+ if (line[0] != '\n') {
+ if (empties > 0)
+ fputc('\n', out);
+ empties = 0;
+ fputs(line, out);
+ continue;
+ }
+ if (empties < 0)
+ continue;
+ empties++;
+ }
+ if (incomplete)
+ fputc('\n', out);
+}
+
+int cmd_stripspace(int argc, const char **argv, char **envp)
+{
+ stripspace(stdin, stdout);
+ return 0;
+}
--- /dev/null
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#include "cache.h"
+#include "strbuf.h"
+#include "quote.h"
+#include "cache-tree.h"
+#include "tree-walk.h"
+#include "builtin.h"
+
+/*
+ * Default to not allowing changes to the list of files. The
+ * tool doesn't actually care, but this makes it harder to add
+ * files to the revision control by mistake by doing something
+ * like "git-update-index *" and suddenly having all the object
+ * files be revision controlled.
+ */
+static int allow_add;
+static int allow_remove;
+static int allow_replace;
+static int info_only;
+static int force_remove;
+static int verbose;
+static int mark_valid_only = 0;
+#define MARK_VALID 1
+#define UNMARK_VALID 2
+
+static void report(const char *fmt, ...)
+{
+ va_list vp;
+
+ if (!verbose)
+ return;
+
+ va_start(vp, fmt);
+ vprintf(fmt, vp);
+ putchar('\n');
+ va_end(vp);
+}
+
+static int mark_valid(const char *path)
+{
+ int namelen = strlen(path);
+ int pos = cache_name_pos(path, namelen);
+ if (0 <= pos) {
+ switch (mark_valid_only) {
+ case MARK_VALID:
+ active_cache[pos]->ce_flags |= htons(CE_VALID);
+ break;
+ case UNMARK_VALID:
+ active_cache[pos]->ce_flags &= ~htons(CE_VALID);
+ break;
+ }
+ cache_tree_invalidate_path(active_cache_tree, path);
+ active_cache_changed = 1;
+ return 0;
+ }
+ return -1;
+}
+
+static int add_file_to_cache(const char *path)
+{
+ int size, namelen, option, status;
+ struct cache_entry *ce;
+ struct stat st;
+
+ status = lstat(path, &st);
+
+ /* We probably want to do this in remove_file_from_cache() and
+ * add_cache_entry() instead...
+ */
+ cache_tree_invalidate_path(active_cache_tree, path);
+
+ if (status < 0 || S_ISDIR(st.st_mode)) {
+ /* When we used to have "path" and now we want to add
+ * "path/file", we need a way to remove "path" before
+ * being able to add "path/file". However,
+ * "git-update-index --remove path" would not work.
+ * --force-remove can be used but this is more user
+ * friendly, especially since we can do the opposite
+ * case just fine without --force-remove.
+ */
+ if (status == 0 || (errno == ENOENT || errno == ENOTDIR)) {
+ if (allow_remove) {
+ if (remove_file_from_cache(path))
+ return error("%s: cannot remove from the index",
+ path);
+ else
+ return 0;
+ } else if (status < 0) {
+ return error("%s: does not exist and --remove not passed",
+ path);
+ }
+ }
+ if (0 == status)
+ return error("%s: is a directory - add files inside instead",
+ path);
+ else
+ return error("lstat(\"%s\"): %s", path,
+ strerror(errno));
+ }
+
+ namelen = strlen(path);
+ size = cache_entry_size(namelen);
+ ce = xcalloc(1, size);
+ memcpy(ce->name, path, namelen);
+ ce->ce_flags = htons(namelen);
+ fill_stat_cache_info(ce, &st);
+
+ ce->ce_mode = create_ce_mode(st.st_mode);
+ if (!trust_executable_bit) {
+ /* If there is an existing entry, pick the mode bits
+ * from it.
+ */
+ int pos = cache_name_pos(path, namelen);
+ if (0 <= pos)
+ ce->ce_mode = active_cache[pos]->ce_mode;
+ }
+
+ if (index_path(ce->sha1, path, &st, !info_only))
+ return -1;
+ option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
+ option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
+ if (add_cache_entry(ce, option))
+ return error("%s: cannot add to the index - missing --add option?",
+ path);
+ return 0;
+}
+
+static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
+ const char *path, int stage)
+{
+ int size, len, option;
+ struct cache_entry *ce;
+
+ if (!verify_path(path))
+ return -1;
+
+ len = strlen(path);
+ size = cache_entry_size(len);
+ ce = xcalloc(1, size);
+
+ memcpy(ce->sha1, sha1, 20);
+ memcpy(ce->name, path, len);
+ ce->ce_flags = create_ce_flags(len, stage);
+ ce->ce_mode = create_ce_mode(mode);
+ if (assume_unchanged)
+ ce->ce_flags |= htons(CE_VALID);
+ option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
+ option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
+ if (add_cache_entry(ce, option))
+ return error("%s: cannot add to the index - missing --add option?",
+ path);
+ report("add '%s'", path);
+ cache_tree_invalidate_path(active_cache_tree, path);
+ return 0;
+}
+
+static void chmod_path(int flip, const char *path)
+{
+ int pos;
+ struct cache_entry *ce;
+ unsigned int mode;
+
+ pos = cache_name_pos(path, strlen(path));
+ if (pos < 0)
+ goto fail;
+ ce = active_cache[pos];
+ mode = ntohl(ce->ce_mode);
+ if (!S_ISREG(mode))
+ goto fail;
+ switch (flip) {
+ case '+':
+ ce->ce_mode |= htonl(0111); break;
+ case '-':
+ ce->ce_mode &= htonl(~0111); break;
+ default:
+ goto fail;
+ }
+ cache_tree_invalidate_path(active_cache_tree, path);
+ active_cache_changed = 1;
+ report("chmod %cx '%s'", flip, path);
+ return;
+ fail:
+ die("git-update-index: cannot chmod %cx '%s'", flip, path);
+}
+
+static void update_one(const char *path, const char *prefix, int prefix_length)
+{
+ const char *p = prefix_path(prefix, prefix_length, path);
+ if (!verify_path(p)) {
+ fprintf(stderr, "Ignoring path %s\n", path);
+ goto free_return;
+ }
+ if (mark_valid_only) {
+ if (mark_valid(p))
+ die("Unable to mark file %s", path);
+ goto free_return;
+ }
+ cache_tree_invalidate_path(active_cache_tree, path);
+
+ if (force_remove) {
+ if (remove_file_from_cache(p))
+ die("git-update-index: unable to remove %s", path);
+ report("remove '%s'", path);
+ goto free_return;
+ }
+ if (add_file_to_cache(p))
+ die("Unable to process file %s", path);
+ report("add '%s'", path);
+ free_return:
+ if (p < path || p > path + strlen(path))
+ free((char*)p);
+}
+
+static void read_index_info(int line_termination)
+{
+ struct strbuf buf;
+ strbuf_init(&buf);
+ while (1) {
+ char *ptr, *tab;
+ char *path_name;
+ unsigned char sha1[20];
+ unsigned int mode;
+ int stage;
+
+ /* This reads lines formatted in one of three formats:
+ *
+ * (1) mode SP sha1 TAB path
+ * The first format is what "git-apply --index-info"
+ * reports, and used to reconstruct a partial tree
+ * that is used for phony merge base tree when falling
+ * back on 3-way merge.
+ *
+ * (2) mode SP type SP sha1 TAB path
+ * The second format is to stuff git-ls-tree output
+ * into the index file.
+ *
+ * (3) mode SP sha1 SP stage TAB path
+ * This format is to put higher order stages into the
+ * index file and matches git-ls-files --stage output.
+ */
+ read_line(&buf, stdin, line_termination);
+ if (buf.eof)
+ break;
+
+ mode = strtoul(buf.buf, &ptr, 8);
+ if (ptr == buf.buf || *ptr != ' ')
+ goto bad_line;
+
+ tab = strchr(ptr, '\t');
+ if (!tab || tab - ptr < 41)
+ goto bad_line;
+
+ if (tab[-2] == ' ' && '0' <= tab[-1] && tab[-1] <= '3') {
+ stage = tab[-1] - '0';
+ ptr = tab + 1; /* point at the head of path */
+ tab = tab - 2; /* point at tail of sha1 */
+ }
+ else {
+ stage = 0;
+ ptr = tab + 1; /* point at the head of path */
+ }
+
+ if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ')
+ goto bad_line;
+
+ if (line_termination && ptr[0] == '"')
+ path_name = unquote_c_style(ptr, NULL);
+ else
+ path_name = ptr;
+
+ if (!verify_path(path_name)) {
+ fprintf(stderr, "Ignoring path %s\n", path_name);
+ if (path_name != ptr)
+ free(path_name);
+ continue;
+ }
+ cache_tree_invalidate_path(active_cache_tree, path_name);
+
+ if (!mode) {
+ /* mode == 0 means there is no such path -- remove */
+ if (remove_file_from_cache(path_name))
+ die("git-update-index: unable to remove %s",
+ ptr);
+ }
+ else {
+ /* mode ' ' sha1 '\t' name
+ * ptr[-1] points at tab,
+ * ptr[-41] is at the beginning of sha1
+ */
+ ptr[-42] = ptr[-1] = 0;
+ if (add_cacheinfo(mode, sha1, path_name, stage))
+ die("git-update-index: unable to update %s",
+ path_name);
+ }
+ if (path_name != ptr)
+ free(path_name);
+ continue;
+
+ bad_line:
+ die("malformed index info %s", buf.buf);
+ }
+}
+
+static const char update_index_usage[] =
+"git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again] [--ignore-missing] [-z] [--verbose] [--] <file>...";
+
+static unsigned char head_sha1[20];
+static unsigned char merge_head_sha1[20];
+
+static struct cache_entry *read_one_ent(const char *which,
+ unsigned char *ent, const char *path,
+ int namelen, int stage)
+{
+ unsigned mode;
+ unsigned char sha1[20];
+ int size;
+ struct cache_entry *ce;
+
+ if (get_tree_entry(ent, path, sha1, &mode)) {
+ if (which)
+ error("%s: not in %s branch.", path, which);
+ return NULL;
+ }
+ if (mode == S_IFDIR) {
+ if (which)
+ error("%s: not a blob in %s branch.", path, which);
+ return NULL;
+ }
+ size = cache_entry_size(namelen);
+ ce = xcalloc(1, size);
+
+ memcpy(ce->sha1, sha1, 20);
+ memcpy(ce->name, path, namelen);
+ ce->ce_flags = create_ce_flags(namelen, stage);
+ ce->ce_mode = create_ce_mode(mode);
+ return ce;
+}
+
+static int unresolve_one(const char *path)
+{
+ int namelen = strlen(path);
+ int pos;
+ int ret = 0;
+ struct cache_entry *ce_2 = NULL, *ce_3 = NULL;
+
+ /* See if there is such entry in the index. */
+ pos = cache_name_pos(path, namelen);
+ if (pos < 0) {
+ /* If there isn't, either it is unmerged, or
+ * resolved as "removed" by mistake. We do not
+ * want to do anything in the former case.
+ */
+ pos = -pos-1;
+ if (pos < active_nr) {
+ struct cache_entry *ce = active_cache[pos];
+ if (ce_namelen(ce) == namelen &&
+ !memcmp(ce->name, path, namelen)) {
+ fprintf(stderr,
+ "%s: skipping still unmerged path.\n",
+ path);
+ goto free_return;
+ }
+ }
+ }
+
+ /* Grab blobs from given path from HEAD and MERGE_HEAD,
+ * stuff HEAD version in stage #2,
+ * stuff MERGE_HEAD version in stage #3.
+ */
+ ce_2 = read_one_ent("our", head_sha1, path, namelen, 2);
+ ce_3 = read_one_ent("their", merge_head_sha1, path, namelen, 3);
+
+ if (!ce_2 || !ce_3) {
+ ret = -1;
+ goto free_return;
+ }
+ if (!memcmp(ce_2->sha1, ce_3->sha1, 20) &&
+ ce_2->ce_mode == ce_3->ce_mode) {
+ fprintf(stderr, "%s: identical in both, skipping.\n",
+ path);
+ goto free_return;
+ }
+
+ cache_tree_invalidate_path(active_cache_tree, path);
+ remove_file_from_cache(path);
+ if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) {
+ error("%s: cannot add our version to the index.", path);
+ ret = -1;
+ goto free_return;
+ }
+ if (!add_cache_entry(ce_3, ADD_CACHE_OK_TO_ADD))
+ return 0;
+ error("%s: cannot add their version to the index.", path);
+ ret = -1;
+ free_return:
+ free(ce_2);
+ free(ce_3);
+ return ret;
+}
+
+static void read_head_pointers(void)
+{
+ if (read_ref(git_path("HEAD"), head_sha1))
+ die("No HEAD -- no initial commit yet?\n");
+ if (read_ref(git_path("MERGE_HEAD"), merge_head_sha1)) {
+ fprintf(stderr, "Not in the middle of a merge.\n");
+ exit(0);
+ }
+}
+
+static int do_unresolve(int ac, const char **av,
+ const char *prefix, int prefix_length)
+{
+ int i;
+ int err = 0;
+
+ /* Read HEAD and MERGE_HEAD; if MERGE_HEAD does not exist, we
+ * are not doing a merge, so exit with success status.
+ */
+ read_head_pointers();
+
+ for (i = 1; i < ac; i++) {
+ const char *arg = av[i];
+ const char *p = prefix_path(prefix, prefix_length, arg);
+ err |= unresolve_one(p);
+ if (p < arg || p > arg + strlen(arg))
+ free((char*)p);
+ }
+ return err;
+}
+
+static int do_reupdate(int ac, const char **av,
+ const char *prefix, int prefix_length)
+{
+ /* Read HEAD and run update-index on paths that are
+ * merged and already different between index and HEAD.
+ */
+ int pos;
+ int has_head = 1;
+ const char **pathspec = get_pathspec(prefix, av + 1);
+
+ if (read_ref(git_path("HEAD"), head_sha1))
+ /* If there is no HEAD, that means it is an initial
+ * commit. Update everything in the index.
+ */
+ has_head = 0;
+ redo:
+ for (pos = 0; pos < active_nr; pos++) {
+ struct cache_entry *ce = active_cache[pos];
+ struct cache_entry *old = NULL;
+ int save_nr;
+
+ if (ce_stage(ce) || !ce_path_match(ce, pathspec))
+ continue;
+ if (has_head)
+ old = read_one_ent(NULL, head_sha1,
+ ce->name, ce_namelen(ce), 0);
+ if (old && ce->ce_mode == old->ce_mode &&
+ !memcmp(ce->sha1, old->sha1, 20)) {
+ free(old);
+ continue; /* unchanged */
+ }
+ /* Be careful. The working tree may not have the
+ * path anymore, in which case, under 'allow_remove',
+ * or worse yet 'allow_replace', active_nr may decrease.
+ */
+ save_nr = active_nr;
+ update_one(ce->name + prefix_length, prefix, prefix_length);
+ if (save_nr != active_nr)
+ goto redo;
+ }
+ return 0;
+}
+
+int cmd_update_index(int argc, const char **argv, char **envp)
+{
+ int i, newfd, entries, has_errors = 0, line_termination = '\n';
+ int allow_options = 1;
+ int read_from_stdin = 0;
+ const char *prefix = setup_git_directory();
+ int prefix_length = prefix ? strlen(prefix) : 0;
+ char set_executable_bit = 0;
+ unsigned int refresh_flags = 0;
+ struct lock_file *lock_file;
+
+ git_config(git_default_config);
+
+ /* We can't free this memory, it becomes part of a linked list parsed atexit() */
+ lock_file = xcalloc(1, sizeof(struct lock_file));
+
+ newfd = hold_lock_file_for_update(lock_file, get_index_file());
+ if (newfd < 0)
+ die("unable to create new cachefile");
+
+ entries = read_cache();
+ if (entries < 0)
+ die("cache corrupted");
+
+ for (i = 1 ; i < argc; i++) {
+ const char *path = argv[i];
+
+ if (allow_options && *path == '-') {
+ if (!strcmp(path, "--")) {
+ allow_options = 0;
+ continue;
+ }
+ if (!strcmp(path, "-q")) {
+ refresh_flags |= REFRESH_QUIET;
+ continue;
+ }
+ if (!strcmp(path, "--add")) {
+ allow_add = 1;
+ continue;
+ }
+ if (!strcmp(path, "--replace")) {
+ allow_replace = 1;
+ continue;
+ }
+ if (!strcmp(path, "--remove")) {
+ allow_remove = 1;
+ continue;
+ }
+ if (!strcmp(path, "--unmerged")) {
+ refresh_flags |= REFRESH_UNMERGED;
+ continue;
+ }
+ if (!strcmp(path, "--refresh")) {
+ has_errors |= refresh_cache(refresh_flags);
+ continue;
+ }
+ if (!strcmp(path, "--really-refresh")) {
+ has_errors |= refresh_cache(REFRESH_REALLY | refresh_flags);
+ continue;
+ }
+ if (!strcmp(path, "--cacheinfo")) {
+ unsigned char sha1[20];
+ unsigned int mode;
+
+ if (i+3 >= argc)
+ die("git-update-index: --cacheinfo <mode> <sha1> <path>");
+
+ if ((sscanf(argv[i+1], "%o", &mode) != 1) ||
+ get_sha1_hex(argv[i+2], sha1) ||
+ add_cacheinfo(mode, sha1, argv[i+3], 0))
+ die("git-update-index: --cacheinfo"
+ " cannot add %s", argv[i+3]);
+ i += 3;
+ continue;
+ }
+ if (!strcmp(path, "--chmod=-x") ||
+ !strcmp(path, "--chmod=+x")) {
+ if (argc <= i+1)
+ die("git-update-index: %s <path>", path);
+ set_executable_bit = path[8];
+ continue;
+ }
+ if (!strcmp(path, "--assume-unchanged")) {
+ mark_valid_only = MARK_VALID;
+ continue;
+ }
+ if (!strcmp(path, "--no-assume-unchanged")) {
+ mark_valid_only = UNMARK_VALID;
+ continue;
+ }
+ if (!strcmp(path, "--info-only")) {
+ info_only = 1;
+ continue;
+ }
+ if (!strcmp(path, "--force-remove")) {
+ force_remove = 1;
+ continue;
+ }
+ if (!strcmp(path, "-z")) {
+ line_termination = 0;
+ continue;
+ }
+ if (!strcmp(path, "--stdin")) {
+ if (i != argc - 1)
+ die("--stdin must be at the end");
+ read_from_stdin = 1;
+ break;
+ }
+ if (!strcmp(path, "--index-info")) {
+ if (i != argc - 1)
+ die("--index-info must be at the end");
+ allow_add = allow_replace = allow_remove = 1;
+ read_index_info(line_termination);
+ break;
+ }
+ if (!strcmp(path, "--unresolve")) {
+ has_errors = do_unresolve(argc - i, argv + i,
+ prefix, prefix_length);
+ if (has_errors)
+ active_cache_changed = 0;
+ goto finish;
+ }
+ if (!strcmp(path, "--again")) {
+ has_errors = do_reupdate(argc - i, argv + i,
+ prefix, prefix_length);
+ if (has_errors)
+ active_cache_changed = 0;
+ goto finish;
+ }
+ if (!strcmp(path, "--ignore-missing")) {
+ refresh_flags |= REFRESH_IGNORE_MISSING;
+ continue;
+ }
+ if (!strcmp(path, "--verbose")) {
+ verbose = 1;
+ continue;
+ }
+ if (!strcmp(path, "-h") || !strcmp(path, "--help"))
+ usage(update_index_usage);
+ die("unknown option %s", path);
+ }
+ update_one(path, prefix, prefix_length);
+ if (set_executable_bit)
+ chmod_path(set_executable_bit, path);
+ }
+ if (read_from_stdin) {
+ struct strbuf buf;
+ strbuf_init(&buf);
+ while (1) {
+ char *path_name;
+ const char *p;
+ read_line(&buf, stdin, line_termination);
+ if (buf.eof)
+ break;
+ if (line_termination && buf.buf[0] == '"')
+ path_name = unquote_c_style(buf.buf, NULL);
+ else
+ path_name = buf.buf;
+ p = prefix_path(prefix, prefix_length, path_name);
+ update_one(p, NULL, 0);
+ if (set_executable_bit)
+ chmod_path(set_executable_bit, p);
+ if (p < path_name || p > path_name + strlen(path_name))
+ free((char*) p);
+ if (path_name != buf.buf)
+ free(path_name);
+ }
+ }
+
+ finish:
+ if (active_cache_changed) {
+ if (write_cache(newfd, active_cache, active_nr) ||
+ commit_lock_file(lock_file))
+ die("Unable to write new index file");
+ }
+
+ rollback_lock_file(lock_file);
+
+ return has_errors ? 1 : 0;
+}
--- /dev/null
+#include "cache.h"
+#include "refs.h"
+#include "builtin.h"
+
+static const char git_update_ref_usage[] =
+"git-update-ref <refname> <value> [<oldval>] [-m <reason>]";
+
+int cmd_update_ref(int argc, const char **argv, char **envp)
+{
+ const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL;
+ struct ref_lock *lock;
+ unsigned char sha1[20], oldsha1[20];
+ int i;
+
+ setup_git_directory();
+ git_config(git_default_config);
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp("-m", argv[i])) {
+ if (i+1 >= argc)
+ usage(git_update_ref_usage);
+ msg = argv[++i];
+ if (!*msg)
+ die("Refusing to perform update with empty message.");
+ if (strchr(msg, '\n'))
+ die("Refusing to perform update with \\n in message.");
+ continue;
+ }
+ if (!refname) {
+ refname = argv[i];
+ continue;
+ }
+ if (!value) {
+ value = argv[i];
+ continue;
+ }
+ if (!oldval) {
+ oldval = argv[i];
+ continue;
+ }
+ }
+ if (!refname || !value)
+ usage(git_update_ref_usage);
+
+ if (get_sha1(value, sha1))
+ die("%s: not a valid SHA1", value);
+ memset(oldsha1, 0, 20);
+ if (oldval && get_sha1(oldval, oldsha1))
+ die("%s: not a valid old SHA1", oldval);
+
+ lock = lock_any_ref_for_update(refname, oldval ? oldsha1 : NULL, 0);
+ if (!lock)
+ return 1;
+ if (write_ref_sha1(lock, sha1, msg) < 0)
+ return 1;
+
+ /* write_ref_sha1 always unlocks the ref, no need to do it explicitly */
+ return 0;
+}
--- /dev/null
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#include "builtin.h"
+#include "cache.h"
+#include "tree.h"
+#include "cache-tree.h"
+
+static const char write_tree_usage[] =
+"git-write-tree [--missing-ok] [--prefix=<prefix>/]";
+
+int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
+{
+ int entries, was_valid, newfd;
+
+ /* We can't free this memory, it becomes part of a linked list parsed atexit() */
+ struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+
+ newfd = hold_lock_file_for_update(lock_file, get_index_file());
+
+ entries = read_cache();
+ if (entries < 0)
+ die("git-write-tree: error reading cache");
+
+ if (!active_cache_tree)
+ active_cache_tree = cache_tree();
+
+ was_valid = cache_tree_fully_valid(active_cache_tree);
+
+ if (!was_valid) {
+ if (cache_tree_update(active_cache_tree,
+ active_cache, active_nr,
+ missing_ok, 0) < 0)
+ die("git-write-tree: error building trees");
+ if (0 <= newfd) {
+ if (!write_cache(newfd, active_cache, active_nr))
+ commit_lock_file(lock_file);
+ }
+ /* Not being able to write is fine -- we are only interested
+ * in updating the cache-tree part, and if the next caller
+ * ends up using the old index with unupdated cache-tree part
+ * it misses the work we did here, but that is just a
+ * performance penalty and not a big deal.
+ */
+ }
+
+ if (prefix) {
+ struct cache_tree *subtree =
+ cache_tree_find(active_cache_tree, prefix);
+ memcpy(sha1, subtree->sha1, 20);
+ }
+ else
+ memcpy(sha1, active_cache_tree->sha1, 20);
+
+ rollback_lock_file(lock_file);
+
+ return 0;
+}
+
+int cmd_write_tree(int argc, const char **argv, char **envp)
+{
+ int missing_ok = 0, ret;
+ const char *prefix = NULL;
+ unsigned char sha1[20];
+
+ setup_git_directory();
+
+ while (1 < argc) {
+ const char *arg = argv[1];
+ if (!strcmp(arg, "--missing-ok"))
+ missing_ok = 1;
+ else if (!strncmp(arg, "--prefix=", 9))
+ prefix = arg + 9;
+ else
+ die(write_tree_usage);
+ argc--; argv++;
+ }
+
+ if (argc > 2)
+ die("too many options");
+
+ ret = write_tree(sha1, missing_ok, prefix);
+ printf("%s\n", sha1_to_hex(sha1));
+
+ return ret;
+}
#ifndef BUILTIN_H
#define BUILTIN_H
+#include <stdio.h>
+
#ifndef PATH_MAX
# define PATH_MAX 4096
#endif
extern int cmd_diff_tree(int argc, const char **argv, char **envp);
extern int cmd_cat_file(int argc, const char **argv, char **envp);
extern int cmd_rev_parse(int argc, const char **argv, char **envp);
+extern int cmd_update_index(int argc, const char **argv, char **envp);
+extern int cmd_update_ref(int argc, const char **argv, char **envp);
+
+extern int cmd_write_tree(int argc, const char **argv, char **envp);
+extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
+
+extern int cmd_mailsplit(int argc, const char **argv, char **envp);
+extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
+
+extern int cmd_mailinfo(int argc, const char **argv, char **envp);
+extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch);
+extern int cmd_stripspace(int argc, const char **argv, char **envp);
+extern void stripspace(FILE *in, FILE *out);
#endif
int decode_85(char *dst, char *line, int linelen);
void encode_85(char *buf, unsigned char *data, int bytes);
+/* alloc.c */
+struct blob;
+struct tree;
+struct commit;
+struct tag;
+extern struct blob *alloc_blob_node(void);
+extern struct tree *alloc_tree_node(void);
+extern struct commit *alloc_commit_node(void);
+extern struct tag *alloc_tag_node(void);
+extern void alloc_report(void);
+
#endif /* CACHE_H */
{
struct object *obj = lookup_object(sha1);
if (!obj) {
- struct commit *ret = xcalloc(1, sizeof(struct commit));
+ struct commit *ret = alloc_commit_node();
created_object(sha1, &ret->object);
ret->object.type = TYPE_COMMIT;
return ret;
memcpy(bp, q_utf8, sizeof(q_utf8)-1);
bp += sizeof(q_utf8)-1;
for (i = 0; i < len; i++) {
- unsigned ch = line[i];
+ unsigned ch = line[i] & 0xFF;
if (is_rfc2047_special(ch)) {
sprintf(bp, "=%02X", ch);
bp += 3;
* to say this is not a 7-bit ASCII.
*/
if (fmt == CMIT_FMT_EMAIL && !after_subject) {
- int i;
- for (i = 0; !plain_non_ascii && msg[i] && i < len; i++)
- if (msg[i] & 0x80)
+ int i, ch, in_body;
+
+ for (in_body = i = 0; (ch = msg[i]) && i < len; i++) {
+ if (!in_body) {
+ /* author could be non 7-bit ASCII but
+ * the log may so; skip over the
+ * header part first.
+ */
+ if (ch == '\n' &&
+ i + 1 < len && msg[i+1] == '\n')
+ in_body = 1;
+ }
+ else if (ch & 0x80) {
plain_non_ascii = 1;
+ break;
+ }
+ }
}
for (;;) {
int git_config(config_fn_t fn)
{
- return git_config_from_file(fn, git_path("config"));
+ int ret = 0;
+ char *repo_config = NULL;
+ const char *home = NULL, *filename;
+
+ /* $GIT_CONFIG makes git read _only_ the given config file,
+ * $GIT_CONFIG_LOCAL will make it process it in addition to the
+ * global config file, the same way it would the per-repository
+ * config file otherwise. */
+ filename = getenv("GIT_CONFIG");
+ if (!filename) {
+ home = getenv("HOME");
+ filename = getenv("GIT_CONFIG_LOCAL");
+ if (!filename)
+ filename = repo_config = strdup(git_path("config"));
+ }
+
+ if (home) {
+ char *user_config = strdup(mkpath("%s/.gitconfig", home));
+ if (!access(user_config, R_OK))
+ ret = git_config_from_file(fn, user_config);
+ free(user_config);
+ }
+
+ ret += git_config_from_file(fn, filename);
+ if (repo_config)
+ free(repo_config);
+ return ret;
}
/*
int i, dot;
int fd = -1, in_fd;
int ret;
- char* config_filename = strdup(git_path("config"));
- char* lock_file = strdup(git_path("config.lock"));
+ char* config_filename;
+ char* lock_file;
const char* last_dot = strrchr(key, '.');
+ config_filename = getenv("GIT_CONFIG");
+ if (!config_filename) {
+ config_filename = getenv("GIT_CONFIG_LOCAL");
+ if (!config_filename)
+ config_filename = git_path("config");
+ }
+ config_filename = strdup(config_filename);
+ lock_file = strdup(mkpath("%s.lock", config_filename));
+
/*
* Since "key" actually contains the section name and the real
* key name separated by a dot, we have to know where the dot is.
* As a side effect, we make sure to transform only a valid
* existing config file.
*/
- if (git_config(store_aux)) {
+ if (git_config_from_file(store_aux, config_filename)) {
fprintf(stderr, "invalid config file\n");
free(store.key);
if (store.value_regex != NULL) {
enum protocol protocol = PROTO_LOCAL;
int free_path = 0;
+ /* Without this we cannot rely on waitpid() to tell
+ * what happened to our children.
+ */
+ signal(SIGCHLD, SIG_DFL);
+
host = strstr(url, "://");
if(host) {
*host = '\0';
int inetd_mode = 0;
int i;
+ /* Without this we cannot rely on waitpid() to tell
+ * what happened to our children.
+ */
+ signal(SIGCHLD, SIG_DFL);
+
for (i = 1; i < argc; i++) {
char *arg = argv[i];
#include <string.h>
#include "delta.h"
+#include "git-compat-util.h"
/* maximum hash entry list for the same hash bucket */
#define HASH_LIMIT 64
const void *src_buf;
unsigned long src_size;
unsigned int hash_mask;
- struct index_entry *hash[0];
+ struct index_entry *hash[FLEX_ARRAY];
};
struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)
continue;
if (ce_stage(ce)) {
- struct {
- struct combine_diff_path p;
- struct combine_diff_parent filler[5];
- } combine;
+ struct combine_diff_path *dpath;
int num_compare_stages = 0;
+ size_t path_len;
- combine.p.next = NULL;
- combine.p.len = ce_namelen(ce);
- combine.p.path = xmalloc(combine.p.len + 1);
- memcpy(combine.p.path, ce->name, combine.p.len);
- combine.p.path[combine.p.len] = 0;
- combine.p.mode = 0;
- memset(combine.p.sha1, 0, 20);
- memset(&combine.p.parent[0], 0,
- sizeof(combine.filler));
+ path_len = ce_namelen(ce);
+
+ dpath = xmalloc (combine_diff_path_size (5, path_len));
+ dpath->path = (char *) &(dpath->parent[5]);
+
+ dpath->next = NULL;
+ dpath->len = path_len;
+ memcpy(dpath->path, ce->name, path_len);
+ dpath->path[path_len] = '\0';
+ dpath->mode = 0;
+ memset(dpath->sha1, 0, 20);
+ memset(&(dpath->parent[0]), 0,
+ sizeof(struct combine_diff_parent)*5);
while (i < entries) {
struct cache_entry *nce = active_cache[i];
if (2 <= stage) {
int mode = ntohl(nce->ce_mode);
num_compare_stages++;
- memcpy(combine.p.parent[stage-2].sha1,
+ memcpy(dpath->parent[stage-2].sha1,
nce->sha1, 20);
- combine.p.parent[stage-2].mode =
+ dpath->parent[stage-2].mode =
canon_mode(mode);
- combine.p.parent[stage-2].status =
+ dpath->parent[stage-2].status =
DIFF_STATUS_MODIFIED;
}
i--;
if (revs->combine_merges && num_compare_stages == 2) {
- show_combined_diff(&combine.p, 2,
+ show_combined_diff(dpath, 2,
revs->dense_combined_merges,
revs);
- free(combine.p.path);
+ free(dpath);
continue;
}
- free(combine.p.path);
+ free(dpath);
+ dpath = NULL;
/*
* Show the diff for the 'ce' if we found the one
}
mark_merge_entries();
- ent = revs->pending_objects->item;
- tree_name = revs->pending_objects->name;
+ ent = revs->pending.objects[0].item;
+ tree_name = revs->pending.objects[0].name;
tree = parse_tree_indirect(ent->sha1);
if (!tree)
return error("bad tree object %s", tree_name);
return git_default_config(var, value);
}
+enum color_diff {
+ DIFF_PLAIN = 0,
+ DIFF_METAINFO = 1,
+ DIFF_FILE_OLD = 2,
+ DIFF_FILE_NEW = 3,
+};
+
+static const char *diff_colors[] = {
+ "\033[0;0m",
+ "\033[1;35m",
+ "\033[1;31m",
+ "\033[1;34m",
+};
+
static char *quote_one(const char *str)
{
int needlen;
}
struct emit_callback {
+ struct xdiff_emit_state xm;
+ int nparents, color_diff;
const char **label_path;
};
-static int fn_out(void *priv, mmbuffer_t *mb, int nbuf)
+static inline void color_diff(int diff_use_color, enum color_diff ix)
+{
+ if (diff_use_color)
+ fputs(diff_colors[ix], stdout);
+}
+
+static void fn_out_consume(void *priv, char *line, unsigned long len)
{
int i;
struct emit_callback *ecbdata = priv;
if (ecbdata->label_path[0]) {
+ color_diff(ecbdata->color_diff, DIFF_METAINFO);
printf("--- %s\n", ecbdata->label_path[0]);
+ color_diff(ecbdata->color_diff, DIFF_METAINFO);
printf("+++ %s\n", ecbdata->label_path[1]);
ecbdata->label_path[0] = ecbdata->label_path[1] = NULL;
}
- for (i = 0; i < nbuf; i++)
- if (!fwrite(mb[i].ptr, mb[i].size, 1, stdout))
- return -1;
- return 0;
+
+ /* This is not really necessary for now because
+ * this codepath only deals with two-way diffs.
+ */
+ for (i = 0; i < len && line[i] == '@'; i++)
+ ;
+ if (2 <= i && i < len && line[i] == ' ') {
+ ecbdata->nparents = i - 1;
+ color_diff(ecbdata->color_diff, DIFF_METAINFO);
+ }
+ else if (len < ecbdata->nparents)
+ color_diff(ecbdata->color_diff, DIFF_PLAIN);
+ else {
+ int nparents = ecbdata->nparents;
+ int color = DIFF_PLAIN;
+ for (i = 0; i < nparents && len; i++) {
+ if (line[i] == '-')
+ color = DIFF_FILE_OLD;
+ else if (line[i] == '+')
+ color = DIFF_FILE_NEW;
+ }
+ color_diff(ecbdata->color_diff, color);
+ }
+ fwrite(line, len, 1, stdout);
+ color_diff(ecbdata->color_diff, DIFF_PLAIN);
}
static char *pprint_rename(const char *a, const char *b)
b_two = quote_two("b/", name_b);
lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
+ color_diff(o->color_diff, DIFF_METAINFO);
printf("diff --git %s %s\n", a_one, b_two);
if (lbl[0][0] == '/') {
/* /dev/null */
+ color_diff(o->color_diff, DIFF_METAINFO);
printf("new file mode %06o\n", two->mode);
- if (xfrm_msg && xfrm_msg[0])
+ if (xfrm_msg && xfrm_msg[0]) {
+ color_diff(o->color_diff, DIFF_METAINFO);
puts(xfrm_msg);
+ }
}
else if (lbl[1][0] == '/') {
printf("deleted file mode %06o\n", one->mode);
- if (xfrm_msg && xfrm_msg[0])
+ if (xfrm_msg && xfrm_msg[0]) {
+ color_diff(o->color_diff, DIFF_METAINFO);
puts(xfrm_msg);
+ }
}
else {
if (one->mode != two->mode) {
+ color_diff(o->color_diff, DIFF_METAINFO);
printf("old mode %06o\n", one->mode);
+ color_diff(o->color_diff, DIFF_METAINFO);
printf("new mode %06o\n", two->mode);
}
- if (xfrm_msg && xfrm_msg[0])
+ if (xfrm_msg && xfrm_msg[0]) {
+ color_diff(o->color_diff, DIFF_METAINFO);
puts(xfrm_msg);
+ }
/*
* we do not run diff between different kind
* of objects.
if ((one->mode ^ two->mode) & S_IFMT)
goto free_ab_and_return;
if (complete_rewrite) {
+ color_diff(o->color_diff, DIFF_PLAIN);
emit_rewrite_diff(name_a, name_b, one, two);
goto free_ab_and_return;
}
xdemitcb_t ecb;
struct emit_callback ecbdata;
+ memset(&ecbdata, 0, sizeof(ecbdata));
ecbdata.label_path = lbl;
+ ecbdata.color_diff = o->color_diff;
xpp.flags = XDF_NEED_MINIMAL;
xecfg.ctxlen = o->context;
xecfg.flags = XDL_EMIT_FUNCNAMES;
xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10);
else if (!strncmp(diffopts, "-u", 2))
xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10);
- ecb.outf = fn_out;
+ ecb.outf = xdiff_outf;
ecb.priv = &ecbdata;
+ ecbdata.xm.consume = fn_out_consume;
xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
}
else if (40 < options->abbrev)
options->abbrev = 40;
}
+ else if (!strcmp(arg, "--color"))
+ options->color_diff = 1;
else
return 0;
return 1;
full_index:1,
silent_on_remove:1,
find_copies_harder:1,
- summary:1;
+ summary:1,
+ color_diff:1;
int context;
int break_opt;
int detect_rename;
{ "diff-stages", cmd_diff_stages },
{ "diff-tree", cmd_diff_tree },
{ "cat-file", cmd_cat_file },
- { "rev-parse", cmd_rev_parse }
+ { "rev-parse", cmd_rev_parse },
+ { "write-tree", cmd_write_tree },
+ { "mailsplit", cmd_mailsplit },
+ { "mailinfo", cmd_mailinfo },
+ { "stripspace", cmd_stripspace },
+ { "update-index", cmd_update_index },
+ { "update-ref", cmd_update_ref }
};
int i;
static inline int needs_quote(int ch)
{
- switch (ch) {
- case '/': case '-': case '.':
- case 'A'...'Z': case 'a'...'z': case '0'...'9':
+ if (((ch >= 'A') && (ch <= 'Z'))
+ || ((ch >= 'a') && (ch <= 'z'))
+ || ((ch >= '0') && (ch <= '9'))
+ || (ch == '/')
+ || (ch == '-')
+ || (ch == '.'))
return 0;
- default:
- return 1;
- }
+ return 1;
}
static inline int hex(int v)
static inline int needs_quote(int ch)
{
- switch (ch) {
- case '/': case '-': case '.':
- case 'A'...'Z': case 'a'...'z': case '0'...'9':
+ if (((ch >= 'A') && (ch <= 'Z'))
+ || ((ch >= 'a') && (ch <= 'z'))
+ || ((ch >= '0') && (ch <= '9'))
+ || (ch == '/')
+ || (ch == '-')
+ || (ch == '.'))
return 0;
- default:
- return 1;
- }
+ return 1;
}
static inline int hex(int v)
obj->flags |= REMOTE;
if (!object_list_contains(objects, obj))
- add_object(obj, &objects, NULL, "");
+ object_list_insert(obj, &objects);
}
static void handle_lockprop_ctx(struct xml_ctx *ctx, int tag_closed)
return lock_flags;
}
+struct object_list **add_one_object(struct object *obj, struct object_list **p)
+{
+ struct object_list *entry = xmalloc(sizeof(struct object_list));
+ entry->item = obj;
+ entry->next = *p;
+ *p = entry;
+ return &entry->next;
+}
+
static struct object_list **process_blob(struct blob *blob,
struct object_list **p,
struct name_path *path,
return p;
obj->flags |= SEEN;
- name = strdup(name);
- return add_object(obj, p, path, name);
+ return add_one_object(obj, p);
}
static struct object_list **process_tree(struct tree *tree,
obj->flags |= SEEN;
name = strdup(name);
- p = add_object(obj, p, NULL, name);
+ p = add_one_object(obj, p);
me.up = path;
me.elem = name;
me.elem_len = strlen(name);
static int get_delta(struct rev_info *revs, struct remote_lock *lock)
{
+ int i;
struct commit *commit;
- struct object_list **p = &objects, *pending;
+ struct object_list **p = &objects;
int count = 0;
while ((commit = get_revision(revs)) != NULL) {
count += add_send_request(&commit->object, lock);
}
- for (pending = revs->pending_objects; pending; pending = pending->next) {
- struct object *obj = pending->item;
- const char *name = pending->name;
+ for (i = 0; i < revs->pending.nr; i++) {
+ struct object_array_entry *entry = revs->pending.objects + i;
+ struct object *obj = entry->item;
+ const char *name = entry->name;
if (obj->flags & (UNINTERESTING | SEEN))
continue;
if (obj->type == TYPE_TAG) {
obj->flags |= SEEN;
- p = add_object(obj, p, NULL, name);
+ p = add_one_object(obj, p);
continue;
}
if (obj->type == TYPE_TREE) {
char *data;
int len;
unsigned char flags;
- unsigned char crlf:1;
+ unsigned int crlf:1;
} msg_data_t;
#define DRV_OK 0
+++ /dev/null
-/*
- * Another stupid program, this one parsing the headers of an
- * email to figure out authorship and subject
- */
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#ifndef NO_ICONV
-#include <iconv.h>
-#endif
-#include "git-compat-util.h"
-#include "cache.h"
-
-static FILE *cmitmsg, *patchfile;
-
-static int keep_subject = 0;
-static char *metainfo_charset = NULL;
-static char line[1000];
-static char date[1000];
-static char name[1000];
-static char email[1000];
-static char subject[1000];
-
-static enum {
- TE_DONTCARE, TE_QP, TE_BASE64,
-} transfer_encoding;
-static char charset[256];
-
-static char multipart_boundary[1000];
-static int multipart_boundary_len;
-static int patch_lines = 0;
-
-static char *sanity_check(char *name, char *email)
-{
- int len = strlen(name);
- if (len < 3 || len > 60)
- return email;
- if (strchr(name, '@') || strchr(name, '<') || strchr(name, '>'))
- return email;
- return name;
-}
-
-static int bogus_from(char *line)
-{
- /* John Doe <johndoe> */
- char *bra, *ket, *dst, *cp;
-
- /* This is fallback, so do not bother if we already have an
- * e-mail address.
- */
- if (*email)
- return 0;
-
- bra = strchr(line, '<');
- if (!bra)
- return 0;
- ket = strchr(bra, '>');
- if (!ket)
- return 0;
-
- for (dst = email, cp = bra+1; cp < ket; )
- *dst++ = *cp++;
- *dst = 0;
- for (cp = line; isspace(*cp); cp++)
- ;
- for (bra--; isspace(*bra); bra--)
- *bra = 0;
- cp = sanity_check(cp, email);
- strcpy(name, cp);
- return 1;
-}
-
-static int handle_from(char *in_line)
-{
- char line[1000];
- char *at;
- char *dst;
-
- strcpy(line, in_line);
- at = strchr(line, '@');
- if (!at)
- return bogus_from(line);
-
- /*
- * If we already have one email, don't take any confusing lines
- */
- if (*email && strchr(at+1, '@'))
- return 0;
-
- /* Pick up the string around '@', possibly delimited with <>
- * pair; that is the email part. White them out while copying.
- */
- while (at > line) {
- char c = at[-1];
- if (isspace(c))
- break;
- if (c == '<') {
- at[-1] = ' ';
- break;
- }
- at--;
- }
- dst = email;
- for (;;) {
- unsigned char c = *at;
- if (!c || c == '>' || isspace(c)) {
- if (c == '>')
- *at = ' ';
- break;
- }
- *at++ = ' ';
- *dst++ = c;
- }
- *dst++ = 0;
-
- /* The remainder is name. It could be "John Doe <john.doe@xz>"
- * or "john.doe@xz (John Doe)", but we have whited out the
- * email part, so trim from both ends, possibly removing
- * the () pair at the end.
- */
- at = line + strlen(line);
- while (at > line) {
- unsigned char c = *--at;
- if (!isspace(c)) {
- at[(c == ')') ? 0 : 1] = 0;
- break;
- }
- }
-
- at = line;
- for (;;) {
- unsigned char c = *at;
- if (!c || !isspace(c)) {
- if (c == '(')
- at++;
- break;
- }
- at++;
- }
- at = sanity_check(at, email);
- strcpy(name, at);
- return 1;
-}
-
-static int handle_date(char *line)
-{
- strcpy(date, line);
- return 0;
-}
-
-static int handle_subject(char *line)
-{
- strcpy(subject, line);
- return 0;
-}
-
-/* NOTE NOTE NOTE. We do not claim we do full MIME. We just attempt
- * to have enough heuristics to grok MIME encoded patches often found
- * on our mailing lists. For example, we do not even treat header lines
- * case insensitively.
- */
-
-static int slurp_attr(const char *line, const char *name, char *attr)
-{
- char *ends, *ap = strcasestr(line, name);
- size_t sz;
-
- if (!ap) {
- *attr = 0;
- return 0;
- }
- ap += strlen(name);
- if (*ap == '"') {
- ap++;
- ends = "\"";
- }
- else
- ends = "; \t";
- sz = strcspn(ap, ends);
- memcpy(attr, ap, sz);
- attr[sz] = 0;
- return 1;
-}
-
-static int handle_subcontent_type(char *line)
-{
- /* We do not want to mess with boundary. Note that we do not
- * handle nested multipart.
- */
- if (strcasestr(line, "boundary=")) {
- fprintf(stderr, "Not handling nested multipart message.\n");
- exit(1);
- }
- slurp_attr(line, "charset=", charset);
- if (*charset) {
- int i, c;
- for (i = 0; (c = charset[i]) != 0; i++)
- charset[i] = tolower(c);
- }
- return 0;
-}
-
-static int handle_content_type(char *line)
-{
- *multipart_boundary = 0;
- if (slurp_attr(line, "boundary=", multipart_boundary + 2)) {
- memcpy(multipart_boundary, "--", 2);
- multipart_boundary_len = strlen(multipart_boundary);
- }
- slurp_attr(line, "charset=", charset);
- return 0;
-}
-
-static int handle_content_transfer_encoding(char *line)
-{
- if (strcasestr(line, "base64"))
- transfer_encoding = TE_BASE64;
- else if (strcasestr(line, "quoted-printable"))
- transfer_encoding = TE_QP;
- else
- transfer_encoding = TE_DONTCARE;
- return 0;
-}
-
-static int is_multipart_boundary(const char *line)
-{
- return (!memcmp(line, multipart_boundary, multipart_boundary_len));
-}
-
-static int eatspace(char *line)
-{
- int len = strlen(line);
- while (len > 0 && isspace(line[len-1]))
- line[--len] = 0;
- return len;
-}
-
-#define SEEN_FROM 01
-#define SEEN_DATE 02
-#define SEEN_SUBJECT 04
-#define SEEN_BOGUS_UNIX_FROM 010
-#define SEEN_PREFIX 020
-
-/* First lines of body can have From:, Date:, and Subject: or empty */
-static void handle_inbody_header(int *seen, char *line)
-{
- if (*seen & SEEN_PREFIX)
- return;
- if (isspace(*line)) {
- char *cp;
- for (cp = line + 1; *cp; cp++) {
- if (!isspace(*cp))
- break;
- }
- if (!*cp)
- return;
- }
- if (!memcmp(">From", line, 5) && isspace(line[5])) {
- if (!(*seen & SEEN_BOGUS_UNIX_FROM)) {
- *seen |= SEEN_BOGUS_UNIX_FROM;
- return;
- }
- }
- if (!memcmp("From:", line, 5) && isspace(line[5])) {
- if (!(*seen & SEEN_FROM) && handle_from(line+6)) {
- *seen |= SEEN_FROM;
- return;
- }
- }
- if (!memcmp("Date:", line, 5) && isspace(line[5])) {
- if (!(*seen & SEEN_DATE)) {
- handle_date(line+6);
- *seen |= SEEN_DATE;
- return;
- }
- }
- if (!memcmp("Subject:", line, 8) && isspace(line[8])) {
- if (!(*seen & SEEN_SUBJECT)) {
- handle_subject(line+9);
- *seen |= SEEN_SUBJECT;
- return;
- }
- }
- if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) {
- if (!(*seen & SEEN_SUBJECT)) {
- handle_subject(line);
- *seen |= SEEN_SUBJECT;
- return;
- }
- }
- *seen |= SEEN_PREFIX;
-}
-
-static char *cleanup_subject(char *subject)
-{
- if (keep_subject)
- return subject;
- for (;;) {
- char *p;
- int len, remove;
- switch (*subject) {
- case 'r': case 'R':
- if (!memcmp("e:", subject+1, 2)) {
- subject +=3;
- continue;
- }
- break;
- case ' ': case '\t': case ':':
- subject++;
- continue;
-
- case '[':
- p = strchr(subject, ']');
- if (!p) {
- subject++;
- continue;
- }
- len = strlen(p);
- remove = p - subject;
- if (remove <= len *2) {
- subject = p+1;
- continue;
- }
- break;
- }
- eatspace(subject);
- return subject;
- }
-}
-
-static void cleanup_space(char *buf)
-{
- unsigned char c;
- while ((c = *buf) != 0) {
- buf++;
- if (isspace(c)) {
- buf[-1] = ' ';
- c = *buf;
- while (isspace(c)) {
- int len = strlen(buf);
- memmove(buf, buf+1, len);
- c = *buf;
- }
- }
- }
-}
-
-static void decode_header_bq(char *it);
-typedef int (*header_fn_t)(char *);
-struct header_def {
- const char *name;
- header_fn_t func;
- int namelen;
-};
-
-static void check_header(char *line, struct header_def *header)
-{
- int i;
-
- if (header[0].namelen <= 0) {
- for (i = 0; header[i].name; i++)
- header[i].namelen = strlen(header[i].name);
- }
- for (i = 0; header[i].name; i++) {
- int len = header[i].namelen;
- if (!strncasecmp(line, header[i].name, len) &&
- line[len] == ':' && isspace(line[len + 1])) {
- /* Unwrap inline B and Q encoding, and optionally
- * normalize the meta information to utf8.
- */
- decode_header_bq(line + len + 2);
- header[i].func(line + len + 2);
- break;
- }
- }
-}
-
-static void check_subheader_line(char *line)
-{
- static struct header_def header[] = {
- { "Content-Type", handle_subcontent_type },
- { "Content-Transfer-Encoding",
- handle_content_transfer_encoding },
- { NULL },
- };
- check_header(line, header);
-}
-static void check_header_line(char *line)
-{
- static struct header_def header[] = {
- { "From", handle_from },
- { "Date", handle_date },
- { "Subject", handle_subject },
- { "Content-Type", handle_content_type },
- { "Content-Transfer-Encoding",
- handle_content_transfer_encoding },
- { NULL },
- };
- check_header(line, header);
-}
-
-static int is_rfc2822_header(char *line)
-{
- /*
- * The section that defines the loosest possible
- * field name is "3.6.8 Optional fields".
- *
- * optional-field = field-name ":" unstructured CRLF
- * field-name = 1*ftext
- * ftext = %d33-57 / %59-126
- */
- int ch;
- char *cp = line;
- while ((ch = *cp++)) {
- if (ch == ':')
- return cp != line;
- if ((33 <= ch && ch <= 57) ||
- (59 <= ch && ch <= 126))
- continue;
- break;
- }
- return 0;
-}
-
-static int read_one_header_line(char *line, int sz, FILE *in)
-{
- int ofs = 0;
- while (ofs < sz) {
- int peek, len;
- if (fgets(line + ofs, sz - ofs, in) == NULL)
- break;
- len = eatspace(line + ofs);
- if ((len == 0) || !is_rfc2822_header(line)) {
- /* Re-add the newline */
- line[ofs + len] = '\n';
- line[ofs + len + 1] = '\0';
- break;
- }
- ofs += len;
- /* Yuck, 2822 header "folding" */
- peek = fgetc(in); ungetc(peek, in);
- if (peek != ' ' && peek != '\t')
- break;
- }
- /* Count mbox From headers as headers */
- if (!ofs && !memcmp(line, "From ", 5))
- ofs = 1;
- return ofs;
-}
-
-static unsigned hexval(int c)
-{
- if (c >= '0' && c <= '9')
- return c - '0';
- if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
- return ~0;
-}
-
-static int decode_q_segment(char *in, char *ot, char *ep, int rfc2047)
-{
- int c;
- while ((c = *in++) != 0 && (in <= ep)) {
- if (c == '=') {
- int d = *in++;
- if (d == '\n' || !d)
- break; /* drop trailing newline */
- *ot++ = ((hexval(d) << 4) | hexval(*in++));
- continue;
- }
- if (rfc2047 && c == '_') /* rfc2047 4.2 (2) */
- c = 0x20;
- *ot++ = c;
- }
- *ot = 0;
- return 0;
-}
-
-static int decode_b_segment(char *in, char *ot, char *ep)
-{
- /* Decode in..ep, possibly in-place to ot */
- int c, pos = 0, acc = 0;
-
- while ((c = *in++) != 0 && (in <= ep)) {
- if (c == '+')
- c = 62;
- else if (c == '/')
- c = 63;
- else if ('A' <= c && c <= 'Z')
- c -= 'A';
- else if ('a' <= c && c <= 'z')
- c -= 'a' - 26;
- else if ('0' <= c && c <= '9')
- c -= '0' - 52;
- else if (c == '=') {
- /* padding is almost like (c == 0), except we do
- * not output NUL resulting only from it;
- * for now we just trust the data.
- */
- c = 0;
- }
- else
- continue; /* garbage */
- switch (pos++) {
- case 0:
- acc = (c << 2);
- break;
- case 1:
- *ot++ = (acc | (c >> 4));
- acc = (c & 15) << 4;
- break;
- case 2:
- *ot++ = (acc | (c >> 2));
- acc = (c & 3) << 6;
- break;
- case 3:
- *ot++ = (acc | c);
- acc = pos = 0;
- break;
- }
- }
- *ot = 0;
- return 0;
-}
-
-static void convert_to_utf8(char *line, char *charset)
-{
-#ifndef NO_ICONV
- char *in, *out;
- size_t insize, outsize, nrc;
- char outbuf[4096]; /* cheat */
- static char latin_one[] = "latin1";
- char *input_charset = *charset ? charset : latin_one;
- iconv_t conv = iconv_open(metainfo_charset, input_charset);
-
- if (conv == (iconv_t) -1) {
- static int warned_latin1_once = 0;
- if (input_charset != latin_one) {
- fprintf(stderr, "cannot convert from %s to %s\n",
- input_charset, metainfo_charset);
- *charset = 0;
- }
- else if (!warned_latin1_once) {
- warned_latin1_once = 1;
- fprintf(stderr, "tried to convert from %s to %s, "
- "but your iconv does not work with it.\n",
- input_charset, metainfo_charset);
- }
- return;
- }
- in = line;
- insize = strlen(in);
- out = outbuf;
- outsize = sizeof(outbuf);
- nrc = iconv(conv, &in, &insize, &out, &outsize);
- iconv_close(conv);
- if (nrc == (size_t) -1)
- return;
- *out = 0;
- strcpy(line, outbuf);
-#endif
-}
-
-static void decode_header_bq(char *it)
-{
- char *in, *out, *ep, *cp, *sp;
- char outbuf[1000];
-
- in = it;
- out = outbuf;
- while ((ep = strstr(in, "=?")) != NULL) {
- int sz, encoding;
- char charset_q[256], piecebuf[256];
- if (in != ep) {
- sz = ep - in;
- memcpy(out, in, sz);
- out += sz;
- in += sz;
- }
- /* E.g.
- * ep : "=?iso-2022-jp?B?GyR...?= foo"
- * ep : "=?ISO-8859-1?Q?Foo=FCbar?= baz"
- */
- ep += 2;
- cp = strchr(ep, '?');
- if (!cp)
- return; /* no munging */
- for (sp = ep; sp < cp; sp++)
- charset_q[sp - ep] = tolower(*sp);
- charset_q[cp - ep] = 0;
- encoding = cp[1];
- if (!encoding || cp[2] != '?')
- return; /* no munging */
- ep = strstr(cp + 3, "?=");
- if (!ep)
- return; /* no munging */
- switch (tolower(encoding)) {
- default:
- return; /* no munging */
- case 'b':
- sz = decode_b_segment(cp + 3, piecebuf, ep);
- break;
- case 'q':
- sz = decode_q_segment(cp + 3, piecebuf, ep, 1);
- break;
- }
- if (sz < 0)
- return;
- if (metainfo_charset)
- convert_to_utf8(piecebuf, charset_q);
- strcpy(out, piecebuf);
- out += strlen(out);
- in = ep + 2;
- }
- strcpy(out, in);
- strcpy(it, outbuf);
-}
-
-static void decode_transfer_encoding(char *line)
-{
- char *ep;
-
- switch (transfer_encoding) {
- case TE_QP:
- ep = line + strlen(line);
- decode_q_segment(line, line, ep, 0);
- break;
- case TE_BASE64:
- ep = line + strlen(line);
- decode_b_segment(line, line, ep);
- break;
- case TE_DONTCARE:
- break;
- }
-}
-
-static void handle_info(void)
-{
- char *sub;
-
- sub = cleanup_subject(subject);
- cleanup_space(name);
- cleanup_space(date);
- cleanup_space(email);
- cleanup_space(sub);
-
- printf("Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n",
- name, email, sub, date);
-}
-
-/* We are inside message body and have read line[] already.
- * Spit out the commit log.
- */
-static int handle_commit_msg(int *seen)
-{
- if (!cmitmsg)
- return 0;
- do {
- if (!memcmp("diff -", line, 6) ||
- !memcmp("---", line, 3) ||
- !memcmp("Index: ", line, 7))
- break;
- if ((multipart_boundary[0] && is_multipart_boundary(line))) {
- /* We come here when the first part had only
- * the commit message without any patch. We
- * pretend we have not seen this line yet, and
- * go back to the loop.
- */
- return 1;
- }
-
- /* Unwrap transfer encoding and optionally
- * normalize the log message to UTF-8.
- */
- decode_transfer_encoding(line);
- if (metainfo_charset)
- convert_to_utf8(line, charset);
-
- handle_inbody_header(seen, line);
- if (!(*seen & SEEN_PREFIX))
- continue;
-
- fputs(line, cmitmsg);
- } while (fgets(line, sizeof(line), stdin) != NULL);
- fclose(cmitmsg);
- cmitmsg = NULL;
- return 0;
-}
-
-/* We have done the commit message and have the first
- * line of the patch in line[].
- */
-static void handle_patch(void)
-{
- do {
- if (multipart_boundary[0] && is_multipart_boundary(line))
- break;
- /* Only unwrap transfer encoding but otherwise do not
- * do anything. We do *NOT* want UTF-8 conversion
- * here; we are dealing with the user payload.
- */
- decode_transfer_encoding(line);
- fputs(line, patchfile);
- patch_lines++;
- } while (fgets(line, sizeof(line), stdin) != NULL);
-}
-
-/* multipart boundary and transfer encoding are set up for us, and we
- * are at the end of the sub header. do equivalent of handle_body up
- * to the next boundary without closing patchfile --- we will expect
- * that the first part to contain commit message and a patch, and
- * handle other parts as pure patches.
- */
-static int handle_multipart_one_part(int *seen)
-{
- int n = 0;
-
- while (fgets(line, sizeof(line), stdin) != NULL) {
- again:
- n++;
- if (is_multipart_boundary(line))
- break;
- if (handle_commit_msg(seen))
- goto again;
- handle_patch();
- break;
- }
- if (n == 0)
- return -1;
- return 0;
-}
-
-static void handle_multipart_body(void)
-{
- int seen = 0;
- int part_num = 0;
-
- /* Skip up to the first boundary */
- while (fgets(line, sizeof(line), stdin) != NULL)
- if (is_multipart_boundary(line)) {
- part_num = 1;
- break;
- }
- if (!part_num)
- return;
- /* We are on boundary line. Start slurping the subhead. */
- while (1) {
- int hdr = read_one_header_line(line, sizeof(line), stdin);
- if (!hdr) {
- if (handle_multipart_one_part(&seen) < 0)
- return;
- /* Reset per part headers */
- transfer_encoding = TE_DONTCARE;
- charset[0] = 0;
- }
- else
- check_subheader_line(line);
- }
- fclose(patchfile);
- if (!patch_lines) {
- fprintf(stderr, "No patch found\n");
- exit(1);
- }
-}
-
-/* Non multipart message */
-static void handle_body(void)
-{
- int seen = 0;
-
- handle_commit_msg(&seen);
- handle_patch();
- fclose(patchfile);
- if (!patch_lines) {
- fprintf(stderr, "No patch found\n");
- exit(1);
- }
-}
-
-static const char mailinfo_usage[] =
- "git-mailinfo [-k] [-u | --encoding=<encoding>] msg patch <mail >info";
-
-int main(int argc, char **argv)
-{
- /* NEEDSWORK: might want to do the optional .git/ directory
- * discovery
- */
- git_config(git_default_config);
-
- while (1 < argc && argv[1][0] == '-') {
- if (!strcmp(argv[1], "-k"))
- keep_subject = 1;
- else if (!strcmp(argv[1], "-u"))
- metainfo_charset = git_commit_encoding;
- else if (!strncmp(argv[1], "--encoding=", 11))
- metainfo_charset = argv[1] + 11;
- else
- usage(mailinfo_usage);
- argc--; argv++;
- }
-
- if (argc != 3)
- usage(mailinfo_usage);
- cmitmsg = fopen(argv[1], "w");
- if (!cmitmsg) {
- perror(argv[1]);
- exit(1);
- }
- patchfile = fopen(argv[2], "w");
- if (!patchfile) {
- perror(argv[2]);
- exit(1);
- }
- while (1) {
- int hdr = read_one_header_line(line, sizeof(line), stdin);
- if (!hdr) {
- if (multipart_boundary[0])
- handle_multipart_body();
- else
- handle_body();
- handle_info();
- break;
- }
- check_header_line(line);
- }
- return 0;
-}
+++ /dev/null
-/*
- * Totally braindamaged mbox splitter program.
- *
- * It just splits a mbox into a list of files: "0001" "0002" ..
- * so you can process them further from there.
- */
-#include <unistd.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <stdio.h>
-#include "cache.h"
-
-static const char git_mailsplit_usage[] =
-"git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>...";
-
-static int is_from_line(const char *line, int len)
-{
- const char *colon;
-
- if (len < 20 || memcmp("From ", line, 5))
- return 0;
-
- colon = line + len - 2;
- line += 5;
- for (;;) {
- if (colon < line)
- return 0;
- if (*--colon == ':')
- break;
- }
-
- if (!isdigit(colon[-4]) ||
- !isdigit(colon[-2]) ||
- !isdigit(colon[-1]) ||
- !isdigit(colon[ 1]) ||
- !isdigit(colon[ 2]))
- return 0;
-
- /* year */
- if (strtol(colon+3, NULL, 10) <= 90)
- return 0;
-
- /* Ok, close enough */
- return 1;
-}
-
-/* Could be as small as 64, enough to hold a Unix "From " line. */
-static char buf[4096];
-
-/* Called with the first line (potentially partial)
- * already in buf[] -- normally that should begin with
- * the Unix "From " line. Write it into the specified
- * file.
- */
-static int split_one(FILE *mbox, const char *name, int allow_bare)
-{
- FILE *output = NULL;
- int len = strlen(buf);
- int fd;
- int status = 0;
- int is_bare = !is_from_line(buf, len);
-
- if (is_bare && !allow_bare)
- goto corrupt;
-
- fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0666);
- if (fd < 0)
- die("cannot open output file %s", name);
- output = fdopen(fd, "w");
-
- /* Copy it out, while searching for a line that begins with
- * "From " and having something that looks like a date format.
- */
- for (;;) {
- int is_partial = (buf[len-1] != '\n');
-
- if (fputs(buf, output) == EOF)
- die("cannot write output");
-
- if (fgets(buf, sizeof(buf), mbox) == NULL) {
- if (feof(mbox)) {
- status = 1;
- break;
- }
- die("cannot read mbox");
- }
- len = strlen(buf);
- if (!is_partial && !is_bare && is_from_line(buf, len))
- break; /* done with one message */
- }
- fclose(output);
- return status;
-
- corrupt:
- if (output)
- fclose(output);
- unlink(name);
- fprintf(stderr, "corrupt mailbox\n");
- exit(1);
-}
-
-int main(int argc, const char **argv)
-{
- int nr = 0, nr_prec = 4;
- int allow_bare = 0;
- const char *dir = NULL;
- const char **argp;
- static const char *stdin_only[] = { "-", NULL };
- char *name;
-
- for (argp = argv+1; *argp; argp++) {
- const char *arg = *argp;
-
- if (arg[0] != '-')
- break;
- /* do flags here */
- if ( arg[1] == 'd' ) {
- nr_prec = strtol(arg+2, NULL, 10);
- if (nr_prec < 3 || 10 <= nr_prec)
- usage(git_mailsplit_usage);
- continue;
- } else if ( arg[1] == 'f' ) {
- nr = strtol(arg+2, NULL, 10);
- } else if ( arg[1] == 'b' && !arg[2] ) {
- allow_bare = 1;
- } else if ( arg[1] == 'o' && arg[2] ) {
- dir = arg+2;
- } else if ( arg[1] == '-' && !arg[2] ) {
- argp++; /* -- marks end of options */
- break;
- } else {
- die("unknown option: %s", arg);
- }
- }
-
- if ( !dir ) {
- /* Backwards compatibility: if no -o specified, accept
- <mbox> <dir> or just <dir> */
- switch (argc - (argp-argv)) {
- case 1:
- dir = argp[0];
- argp = stdin_only;
- break;
- case 2:
- stdin_only[0] = argp[0];
- dir = argp[1];
- argp = stdin_only;
- break;
- default:
- usage(git_mailsplit_usage);
- }
- } else {
- /* New usage: if no more argument, parse stdin */
- if ( !*argp )
- argp = stdin_only;
- }
-
- name = xmalloc(strlen(dir) + 2 + 3 * sizeof(nr));
-
- while (*argp) {
- const char *file = *argp++;
- FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
- int file_done = 0;
-
- if ( !f )
- die ("cannot open mbox %s", file);
-
- if (fgets(buf, sizeof(buf), f) == NULL) {
- if (f == stdin)
- break; /* empty stdin is OK */
- die("cannot read mbox %s", file);
- }
-
- while (!file_done) {
- sprintf(name, "%s/%0*d", dir, nr_prec, ++nr);
- file_done = split_one(f, name, allow_bare);
- }
-
- if (f != stdin)
- fclose(f);
- }
-
- printf("%d\n", nr);
- return 0;
-}
{
int i, force_file = 0;
+ /* Without this we cannot rely on waitpid() to tell
+ * what happened to our children.
+ */
+ signal(SIGCHLD, SIG_DFL);
+
if (argc < 3)
usage("git-merge-index [-o] [-q] <merge-program> (-a | <filename>*)");
return buffer;
}
-
+
int main(int argc, char **argv)
{
- struct object_list *revs = NULL;
- struct object_list **walker = &revs;
+ struct object_array revs = { 0, 0, NULL };
int as_is = 0, all = 0, transform_stdin = 0;
setup_git_directory();
if (cutoff > commit->date)
cutoff = commit->date;
- object_list_append((struct object *)commit, walker);
- (*walker)->name = *argv;
- walker = &((*walker)->next);
+ add_object_array((struct object *)commit, *argv, &revs);
}
for_each_ref(name_ref);
if (objs[i])
printf("%s %s\n", sha1_to_hex(objs[i]->sha1),
get_rev_name(objs[i]));
- } else
- for ( ; revs; revs = revs->next)
- printf("%s %s\n", revs->name, get_rev_name(revs->item));
+ } else {
+ int i;
+ for (i = 0; i < revs.nr; i++)
+ printf("%s %s\n",
+ revs.objects[i].name,
+ get_rev_name(revs.objects[i].item));
+ }
return 0;
}
}
return 0;
}
+
+void add_object_array(struct object *obj, const char *name, struct object_array *array)
+{
+ unsigned nr = array->nr;
+ unsigned alloc = array->alloc;
+ struct object_array_entry *objects = array->objects;
+
+ if (nr >= alloc) {
+ alloc = (alloc + 32) * 2;
+ objects = xrealloc(objects, alloc * sizeof(*objects));
+ array->alloc = alloc;
+ array->objects = objects;
+ }
+ objects[nr].item = obj;
+ objects[nr].name = name;
+ array->nr = ++nr;
+}
struct object_list {
struct object *item;
struct object_list *next;
- const char *name;
};
struct object_refs {
struct object *ref[FLEX_ARRAY]; /* more */
};
+struct object_array {
+ unsigned int nr;
+ unsigned int alloc;
+ struct object_array_entry {
+ struct object *item;
+ const char *name;
+ } *objects;
+};
+
#define TYPE_BITS 3
#define FLAG_BITS 27
int object_list_contains(struct object_list *list, struct object *obj);
+/* Object array handling .. */
+void add_object_array(struct object *obj, const char *name, struct object_array *array);
+
#endif /* OBJECT_H */
close(fd[0]);
close(fd[1]);
- setenv("LESS", "-S", 0);
+ setenv("LESS", "-RS", 0);
run_pager(pager);
die("unable to execute pager '%s'", pager);
exit(255);
case '\\': case '"':
break; /* verbatim */
- case '0'...'7':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
/* octal */
ac = ((ch - '0') << 6);
if ((ch = *sp++) < '0' || '7' < ch)
static int get_value(const char* key_, const char* regex_)
{
+ int ret = -1;
char *tl;
+ char *global = NULL, *repo_config = NULL;
+ const char *local;
+
+ local = getenv("GIT_CONFIG");
+ if (!local) {
+ const char *home = getenv("HOME");
+ local = getenv("GIT_CONFIG_LOCAL");
+ if (!local)
+ local = repo_config = strdup(git_path("config"));
+ if (home)
+ global = strdup(mkpath("%s/.gitconfig", home));
+ }
key = strdup(key_);
for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
key_regexp = (regex_t*)malloc(sizeof(regex_t));
if (regcomp(key_regexp, key, REG_EXTENDED)) {
fprintf(stderr, "Invalid key pattern: %s\n", key_);
- return -1;
+ goto free_strings;
}
}
regexp = (regex_t*)malloc(sizeof(regex_t));
if (regcomp(regexp, regex_, REG_EXTENDED)) {
fprintf(stderr, "Invalid pattern: %s\n", regex_);
- return -1;
+ goto free_strings;
}
}
- git_config(show_config);
+ if (do_all && global)
+ git_config_from_file(show_config, global);
+ git_config_from_file(show_config, local);
+ if (!do_all && !seen && global)
+ git_config_from_file(show_config, global);
+
free(key);
if (regexp) {
regfree(regexp);
}
if (do_all)
- return !seen;
-
- return (seen == 1) ? 0 : 1;
+ ret = !seen;
+ else
+ ret = (seen == 1) ? 0 : 1;
+
+free_strings:
+ if (repo_config)
+ free(repo_config);
+ if (global)
+ free(global);
+ return ret;
}
int main(int argc, const char **argv)
return n;
}
-struct object_list **add_object(struct object *obj,
- struct object_list **p,
- struct name_path *path,
- const char *name)
+void add_object(struct object *obj,
+ struct object_array *p,
+ struct name_path *path,
+ const char *name)
{
- struct object_list *entry = xmalloc(sizeof(*entry));
- entry->item = obj;
- entry->next = *p;
- entry->name = path_name(path, name);
- *p = entry;
- return &entry->next;
+ add_object_array(obj, path_name(path, name), p);
}
static void mark_blob_uninteresting(struct blob *blob)
}
}
-static void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
+void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
{
- add_object(obj, &revs->pending_objects, NULL, name);
+ add_object_array(obj, name, &revs->pending);
}
static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
object = get_reference(revs, arg, sha1, flags ^ local_flags);
add_pending_object(revs, object, arg);
}
- if (def && !revs->pending_objects) {
+ if (def && !revs->pending.nr) {
unsigned char sha1[20];
struct object *object;
if (get_sha1(def, sha1))
void prepare_revision_walk(struct rev_info *revs)
{
- struct object_list *list;
+ int nr = revs->pending.nr;
+ struct object_array_entry *list = revs->pending.objects;
- list = revs->pending_objects;
- revs->pending_objects = NULL;
- while (list) {
+ revs->pending.nr = 0;
+ revs->pending.alloc = 0;
+ revs->pending.objects = NULL;
+ while (--nr >= 0) {
struct commit *commit = handle_commit(revs, list->item, list->name);
if (commit) {
if (!(commit->object.flags & SEEN)) {
insert_by_date(commit, &revs->commits);
}
}
- list = list->next;
+ list++;
}
if (revs->no_walk)
struct rev_info {
/* Starting list */
struct commit_list *commits;
- struct object_list *pending_objects;
+ struct object_array pending;
/* Basic information */
const char *prefix;
const char *elem;
};
-extern struct object_list **add_object(struct object *obj,
- struct object_list **p,
- struct name_path *path,
- const char *name);
+extern void add_object(struct object *obj,
+ struct object_array *p,
+ struct name_path *path,
+ const char *name);
+
+extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name);
#endif
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-
-/*
- * Remove empty lines from the beginning and end.
- *
- * Turn multiple consecutive empty lines into just one
- * empty line. Return true if it is an incomplete line.
- */
-static int cleanup(char *line)
-{
- int len = strlen(line);
-
- if (len && line[len-1] == '\n') {
- if (len == 1)
- return 0;
- do {
- unsigned char c = line[len-2];
- if (!isspace(c))
- break;
- line[len-2] = '\n';
- len--;
- line[len] = 0;
- } while (len > 1);
- return 0;
- }
- return 1;
-}
-
-int main(int argc, char **argv)
-{
- int empties = -1;
- int incomplete = 0;
- char line[1024];
-
- while (fgets(line, sizeof(line), stdin)) {
- incomplete = cleanup(line);
-
- /* Not just an empty line? */
- if (line[0] != '\n') {
- if (empties > 0)
- putchar('\n');
- empties = 0;
- fputs(line, stdout);
- continue;
- }
- if (empties < 0)
- continue;
- empties++;
- }
- if (incomplete)
- putchar('\n');
- return 0;
-}
all: $(T) clean
$(T):
- @echo "*** $@ ***"; '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
+ @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
clean:
rm -fr trash
test_expect_success \
'some edit' \
- 'perl -pi -e "s/^1A.*\n$//; s/^3A/99/" file &&
+ 'perl -p -i.orig -e "s/^1A.*\n$//; s/^3A/99/" file &&
GIT_AUTHOR_NAME="D" git commit -a -m "edit"'
test_expect_success \
test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect'
+cat > other-config << EOF
+[ein]
+ bahn = strasse
+EOF
+
+cat > expect << EOF
+ein.bahn=strasse
+EOF
+
+GIT_CONFIG=other-config git-repo-config -l > output
+
+test_expect_success 'alternative GIT_CONFIG' 'cmp output expect'
+
+GIT_CONFIG=other-config git-repo-config anwohner.park ausweis
+
+cat > expect << EOF
+[ein]
+ bahn = strasse
+[anwohner]
+ park = ausweis
+EOF
+
+test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect'
+
test_done
{
struct object *obj = lookup_object(sha1);
if (!obj) {
- struct tag *ret = xcalloc(1, sizeof(struct tag));
+ struct tag *ret = alloc_tag_node();
created_object(sha1, &ret->object);
ret->object.type = TYPE_TAG;
return ret;
{
struct object *obj = lookup_object(sha1);
if (!obj) {
- struct tree *ret = xcalloc(1, sizeof(struct tree));
+ struct tree *ret = alloc_tree_node();
created_object(sha1, &ret->object);
ret->object.type = TYPE_TREE;
return ret;
+++ /dev/null
-/*
- * GIT - The information manager from hell
- *
- * Copyright (C) Linus Torvalds, 2005
- */
-#include "cache.h"
-#include "strbuf.h"
-#include "quote.h"
-#include "cache-tree.h"
-#include "tree-walk.h"
-
-/*
- * Default to not allowing changes to the list of files. The
- * tool doesn't actually care, but this makes it harder to add
- * files to the revision control by mistake by doing something
- * like "git-update-index *" and suddenly having all the object
- * files be revision controlled.
- */
-static int allow_add;
-static int allow_remove;
-static int allow_replace;
-static int info_only;
-static int force_remove;
-static int verbose;
-static int mark_valid_only = 0;
-#define MARK_VALID 1
-#define UNMARK_VALID 2
-
-static void report(const char *fmt, ...)
-{
- va_list vp;
-
- if (!verbose)
- return;
-
- va_start(vp, fmt);
- vprintf(fmt, vp);
- putchar('\n');
- va_end(vp);
-}
-
-static int mark_valid(const char *path)
-{
- int namelen = strlen(path);
- int pos = cache_name_pos(path, namelen);
- if (0 <= pos) {
- switch (mark_valid_only) {
- case MARK_VALID:
- active_cache[pos]->ce_flags |= htons(CE_VALID);
- break;
- case UNMARK_VALID:
- active_cache[pos]->ce_flags &= ~htons(CE_VALID);
- break;
- }
- cache_tree_invalidate_path(active_cache_tree, path);
- active_cache_changed = 1;
- return 0;
- }
- return -1;
-}
-
-static int add_file_to_cache(const char *path)
-{
- int size, namelen, option, status;
- struct cache_entry *ce;
- struct stat st;
-
- status = lstat(path, &st);
-
- /* We probably want to do this in remove_file_from_cache() and
- * add_cache_entry() instead...
- */
- cache_tree_invalidate_path(active_cache_tree, path);
-
- if (status < 0 || S_ISDIR(st.st_mode)) {
- /* When we used to have "path" and now we want to add
- * "path/file", we need a way to remove "path" before
- * being able to add "path/file". However,
- * "git-update-index --remove path" would not work.
- * --force-remove can be used but this is more user
- * friendly, especially since we can do the opposite
- * case just fine without --force-remove.
- */
- if (status == 0 || (errno == ENOENT || errno == ENOTDIR)) {
- if (allow_remove) {
- if (remove_file_from_cache(path))
- return error("%s: cannot remove from the index",
- path);
- else
- return 0;
- } else if (status < 0) {
- return error("%s: does not exist and --remove not passed",
- path);
- }
- }
- if (0 == status)
- return error("%s: is a directory - add files inside instead",
- path);
- else
- return error("lstat(\"%s\"): %s", path,
- strerror(errno));
- }
-
- namelen = strlen(path);
- size = cache_entry_size(namelen);
- ce = xcalloc(1, size);
- memcpy(ce->name, path, namelen);
- ce->ce_flags = htons(namelen);
- fill_stat_cache_info(ce, &st);
-
- ce->ce_mode = create_ce_mode(st.st_mode);
- if (!trust_executable_bit) {
- /* If there is an existing entry, pick the mode bits
- * from it.
- */
- int pos = cache_name_pos(path, namelen);
- if (0 <= pos)
- ce->ce_mode = active_cache[pos]->ce_mode;
- }
-
- if (index_path(ce->sha1, path, &st, !info_only))
- return -1;
- option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
- option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
- if (add_cache_entry(ce, option))
- return error("%s: cannot add to the index - missing --add option?",
- path);
- return 0;
-}
-
-static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
- const char *path, int stage)
-{
- int size, len, option;
- struct cache_entry *ce;
-
- if (!verify_path(path))
- return -1;
-
- len = strlen(path);
- size = cache_entry_size(len);
- ce = xcalloc(1, size);
-
- memcpy(ce->sha1, sha1, 20);
- memcpy(ce->name, path, len);
- ce->ce_flags = create_ce_flags(len, stage);
- ce->ce_mode = create_ce_mode(mode);
- if (assume_unchanged)
- ce->ce_flags |= htons(CE_VALID);
- option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
- option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
- if (add_cache_entry(ce, option))
- return error("%s: cannot add to the index - missing --add option?",
- path);
- report("add '%s'", path);
- cache_tree_invalidate_path(active_cache_tree, path);
- return 0;
-}
-
-static void chmod_path(int flip, const char *path)
-{
- int pos;
- struct cache_entry *ce;
- unsigned int mode;
-
- pos = cache_name_pos(path, strlen(path));
- if (pos < 0)
- goto fail;
- ce = active_cache[pos];
- mode = ntohl(ce->ce_mode);
- if (!S_ISREG(mode))
- goto fail;
- switch (flip) {
- case '+':
- ce->ce_mode |= htonl(0111); break;
- case '-':
- ce->ce_mode &= htonl(~0111); break;
- default:
- goto fail;
- }
- cache_tree_invalidate_path(active_cache_tree, path);
- active_cache_changed = 1;
- report("chmod %cx '%s'", flip, path);
- return;
- fail:
- die("git-update-index: cannot chmod %cx '%s'", flip, path);
-}
-
-static struct lock_file lock_file;
-
-static void update_one(const char *path, const char *prefix, int prefix_length)
-{
- const char *p = prefix_path(prefix, prefix_length, path);
- if (!verify_path(p)) {
- fprintf(stderr, "Ignoring path %s\n", path);
- goto free_return;
- }
- if (mark_valid_only) {
- if (mark_valid(p))
- die("Unable to mark file %s", path);
- goto free_return;
- }
- cache_tree_invalidate_path(active_cache_tree, path);
-
- if (force_remove) {
- if (remove_file_from_cache(p))
- die("git-update-index: unable to remove %s", path);
- report("remove '%s'", path);
- goto free_return;
- }
- if (add_file_to_cache(p))
- die("Unable to process file %s", path);
- report("add '%s'", path);
- free_return:
- if (p < path || p > path + strlen(path))
- free((char*)p);
-}
-
-static void read_index_info(int line_termination)
-{
- struct strbuf buf;
- strbuf_init(&buf);
- while (1) {
- char *ptr, *tab;
- char *path_name;
- unsigned char sha1[20];
- unsigned int mode;
- int stage;
-
- /* This reads lines formatted in one of three formats:
- *
- * (1) mode SP sha1 TAB path
- * The first format is what "git-apply --index-info"
- * reports, and used to reconstruct a partial tree
- * that is used for phony merge base tree when falling
- * back on 3-way merge.
- *
- * (2) mode SP type SP sha1 TAB path
- * The second format is to stuff git-ls-tree output
- * into the index file.
- *
- * (3) mode SP sha1 SP stage TAB path
- * This format is to put higher order stages into the
- * index file and matches git-ls-files --stage output.
- */
- read_line(&buf, stdin, line_termination);
- if (buf.eof)
- break;
-
- mode = strtoul(buf.buf, &ptr, 8);
- if (ptr == buf.buf || *ptr != ' ')
- goto bad_line;
-
- tab = strchr(ptr, '\t');
- if (!tab || tab - ptr < 41)
- goto bad_line;
-
- if (tab[-2] == ' ' && '0' <= tab[-1] && tab[-1] <= '3') {
- stage = tab[-1] - '0';
- ptr = tab + 1; /* point at the head of path */
- tab = tab - 2; /* point at tail of sha1 */
- }
- else {
- stage = 0;
- ptr = tab + 1; /* point at the head of path */
- }
-
- if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ')
- goto bad_line;
-
- if (line_termination && ptr[0] == '"')
- path_name = unquote_c_style(ptr, NULL);
- else
- path_name = ptr;
-
- if (!verify_path(path_name)) {
- fprintf(stderr, "Ignoring path %s\n", path_name);
- if (path_name != ptr)
- free(path_name);
- continue;
- }
- cache_tree_invalidate_path(active_cache_tree, path_name);
-
- if (!mode) {
- /* mode == 0 means there is no such path -- remove */
- if (remove_file_from_cache(path_name))
- die("git-update-index: unable to remove %s",
- ptr);
- }
- else {
- /* mode ' ' sha1 '\t' name
- * ptr[-1] points at tab,
- * ptr[-41] is at the beginning of sha1
- */
- ptr[-42] = ptr[-1] = 0;
- if (add_cacheinfo(mode, sha1, path_name, stage))
- die("git-update-index: unable to update %s",
- path_name);
- }
- if (path_name != ptr)
- free(path_name);
- continue;
-
- bad_line:
- die("malformed index info %s", buf.buf);
- }
-}
-
-static const char update_index_usage[] =
-"git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again] [--ignore-missing] [-z] [--verbose] [--] <file>...";
-
-static unsigned char head_sha1[20];
-static unsigned char merge_head_sha1[20];
-
-static struct cache_entry *read_one_ent(const char *which,
- unsigned char *ent, const char *path,
- int namelen, int stage)
-{
- unsigned mode;
- unsigned char sha1[20];
- int size;
- struct cache_entry *ce;
-
- if (get_tree_entry(ent, path, sha1, &mode)) {
- if (which)
- error("%s: not in %s branch.", path, which);
- return NULL;
- }
- if (mode == S_IFDIR) {
- if (which)
- error("%s: not a blob in %s branch.", path, which);
- return NULL;
- }
- size = cache_entry_size(namelen);
- ce = xcalloc(1, size);
-
- memcpy(ce->sha1, sha1, 20);
- memcpy(ce->name, path, namelen);
- ce->ce_flags = create_ce_flags(namelen, stage);
- ce->ce_mode = create_ce_mode(mode);
- return ce;
-}
-
-static int unresolve_one(const char *path)
-{
- int namelen = strlen(path);
- int pos;
- int ret = 0;
- struct cache_entry *ce_2 = NULL, *ce_3 = NULL;
-
- /* See if there is such entry in the index. */
- pos = cache_name_pos(path, namelen);
- if (pos < 0) {
- /* If there isn't, either it is unmerged, or
- * resolved as "removed" by mistake. We do not
- * want to do anything in the former case.
- */
- pos = -pos-1;
- if (pos < active_nr) {
- struct cache_entry *ce = active_cache[pos];
- if (ce_namelen(ce) == namelen &&
- !memcmp(ce->name, path, namelen)) {
- fprintf(stderr,
- "%s: skipping still unmerged path.\n",
- path);
- goto free_return;
- }
- }
- }
-
- /* Grab blobs from given path from HEAD and MERGE_HEAD,
- * stuff HEAD version in stage #2,
- * stuff MERGE_HEAD version in stage #3.
- */
- ce_2 = read_one_ent("our", head_sha1, path, namelen, 2);
- ce_3 = read_one_ent("their", merge_head_sha1, path, namelen, 3);
-
- if (!ce_2 || !ce_3) {
- ret = -1;
- goto free_return;
- }
- if (!memcmp(ce_2->sha1, ce_3->sha1, 20) &&
- ce_2->ce_mode == ce_3->ce_mode) {
- fprintf(stderr, "%s: identical in both, skipping.\n",
- path);
- goto free_return;
- }
-
- cache_tree_invalidate_path(active_cache_tree, path);
- remove_file_from_cache(path);
- if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) {
- error("%s: cannot add our version to the index.", path);
- ret = -1;
- goto free_return;
- }
- if (!add_cache_entry(ce_3, ADD_CACHE_OK_TO_ADD))
- return 0;
- error("%s: cannot add their version to the index.", path);
- ret = -1;
- free_return:
- free(ce_2);
- free(ce_3);
- return ret;
-}
-
-static void read_head_pointers(void)
-{
- if (read_ref(git_path("HEAD"), head_sha1))
- die("No HEAD -- no initial commit yet?\n");
- if (read_ref(git_path("MERGE_HEAD"), merge_head_sha1)) {
- fprintf(stderr, "Not in the middle of a merge.\n");
- exit(0);
- }
-}
-
-static int do_unresolve(int ac, const char **av,
- const char *prefix, int prefix_length)
-{
- int i;
- int err = 0;
-
- /* Read HEAD and MERGE_HEAD; if MERGE_HEAD does not exist, we
- * are not doing a merge, so exit with success status.
- */
- read_head_pointers();
-
- for (i = 1; i < ac; i++) {
- const char *arg = av[i];
- const char *p = prefix_path(prefix, prefix_length, arg);
- err |= unresolve_one(p);
- if (p < arg || p > arg + strlen(arg))
- free((char*)p);
- }
- return err;
-}
-
-static int do_reupdate(int ac, const char **av,
- const char *prefix, int prefix_length)
-{
- /* Read HEAD and run update-index on paths that are
- * merged and already different between index and HEAD.
- */
- int pos;
- int has_head = 1;
- const char **pathspec = get_pathspec(prefix, av + 1);
-
- if (read_ref(git_path("HEAD"), head_sha1))
- /* If there is no HEAD, that means it is an initial
- * commit. Update everything in the index.
- */
- has_head = 0;
- redo:
- for (pos = 0; pos < active_nr; pos++) {
- struct cache_entry *ce = active_cache[pos];
- struct cache_entry *old = NULL;
- int save_nr;
-
- if (ce_stage(ce) || !ce_path_match(ce, pathspec))
- continue;
- if (has_head)
- old = read_one_ent(NULL, head_sha1,
- ce->name, ce_namelen(ce), 0);
- if (old && ce->ce_mode == old->ce_mode &&
- !memcmp(ce->sha1, old->sha1, 20)) {
- free(old);
- continue; /* unchanged */
- }
- /* Be careful. The working tree may not have the
- * path anymore, in which case, under 'allow_remove',
- * or worse yet 'allow_replace', active_nr may decrease.
- */
- save_nr = active_nr;
- update_one(ce->name + prefix_length, prefix, prefix_length);
- if (save_nr != active_nr)
- goto redo;
- }
- return 0;
-}
-
-int main(int argc, const char **argv)
-{
- int i, newfd, entries, has_errors = 0, line_termination = '\n';
- int allow_options = 1;
- int read_from_stdin = 0;
- const char *prefix = setup_git_directory();
- int prefix_length = prefix ? strlen(prefix) : 0;
- char set_executable_bit = 0;
- unsigned int refresh_flags = 0;
-
- git_config(git_default_config);
-
- newfd = hold_lock_file_for_update(&lock_file, get_index_file());
- if (newfd < 0)
- die("unable to create new index file");
-
- entries = read_cache();
- if (entries < 0)
- die("cache corrupted");
-
- for (i = 1 ; i < argc; i++) {
- const char *path = argv[i];
-
- if (allow_options && *path == '-') {
- if (!strcmp(path, "--")) {
- allow_options = 0;
- continue;
- }
- if (!strcmp(path, "-q")) {
- refresh_flags |= REFRESH_QUIET;
- continue;
- }
- if (!strcmp(path, "--add")) {
- allow_add = 1;
- continue;
- }
- if (!strcmp(path, "--replace")) {
- allow_replace = 1;
- continue;
- }
- if (!strcmp(path, "--remove")) {
- allow_remove = 1;
- continue;
- }
- if (!strcmp(path, "--unmerged")) {
- refresh_flags |= REFRESH_UNMERGED;
- continue;
- }
- if (!strcmp(path, "--refresh")) {
- has_errors |= refresh_cache(refresh_flags);
- continue;
- }
- if (!strcmp(path, "--really-refresh")) {
- has_errors |= refresh_cache(REFRESH_REALLY | refresh_flags);
- continue;
- }
- if (!strcmp(path, "--cacheinfo")) {
- unsigned char sha1[20];
- unsigned int mode;
-
- if (i+3 >= argc)
- die("git-update-index: --cacheinfo <mode> <sha1> <path>");
-
- if ((sscanf(argv[i+1], "%o", &mode) != 1) ||
- get_sha1_hex(argv[i+2], sha1) ||
- add_cacheinfo(mode, sha1, argv[i+3], 0))
- die("git-update-index: --cacheinfo"
- " cannot add %s", argv[i+3]);
- i += 3;
- continue;
- }
- if (!strcmp(path, "--chmod=-x") ||
- !strcmp(path, "--chmod=+x")) {
- if (argc <= i+1)
- die("git-update-index: %s <path>", path);
- set_executable_bit = path[8];
- continue;
- }
- if (!strcmp(path, "--assume-unchanged")) {
- mark_valid_only = MARK_VALID;
- continue;
- }
- if (!strcmp(path, "--no-assume-unchanged")) {
- mark_valid_only = UNMARK_VALID;
- continue;
- }
- if (!strcmp(path, "--info-only")) {
- info_only = 1;
- continue;
- }
- if (!strcmp(path, "--force-remove")) {
- force_remove = 1;
- continue;
- }
- if (!strcmp(path, "-z")) {
- line_termination = 0;
- continue;
- }
- if (!strcmp(path, "--stdin")) {
- if (i != argc - 1)
- die("--stdin must be at the end");
- read_from_stdin = 1;
- break;
- }
- if (!strcmp(path, "--index-info")) {
- if (i != argc - 1)
- die("--index-info must be at the end");
- allow_add = allow_replace = allow_remove = 1;
- read_index_info(line_termination);
- break;
- }
- if (!strcmp(path, "--unresolve")) {
- has_errors = do_unresolve(argc - i, argv + i,
- prefix, prefix_length);
- if (has_errors)
- active_cache_changed = 0;
- goto finish;
- }
- if (!strcmp(path, "--again")) {
- has_errors = do_reupdate(argc - i, argv + i,
- prefix, prefix_length);
- if (has_errors)
- active_cache_changed = 0;
- goto finish;
- }
- if (!strcmp(path, "--ignore-missing")) {
- refresh_flags |= REFRESH_IGNORE_MISSING;
- continue;
- }
- if (!strcmp(path, "--verbose")) {
- verbose = 1;
- continue;
- }
- if (!strcmp(path, "-h") || !strcmp(path, "--help"))
- usage(update_index_usage);
- die("unknown option %s", path);
- }
- update_one(path, prefix, prefix_length);
- if (set_executable_bit)
- chmod_path(set_executable_bit, path);
- }
- if (read_from_stdin) {
- struct strbuf buf;
- strbuf_init(&buf);
- while (1) {
- char *path_name;
- const char *p;
- read_line(&buf, stdin, line_termination);
- if (buf.eof)
- break;
- if (line_termination && buf.buf[0] == '"')
- path_name = unquote_c_style(buf.buf, NULL);
- else
- path_name = buf.buf;
- p = prefix_path(prefix, prefix_length, path_name);
- update_one(p, NULL, 0);
- if (set_executable_bit)
- chmod_path(set_executable_bit, p);
- if (p < path_name || p > path_name + strlen(path_name))
- free((char*) p);
- if (path_name != buf.buf)
- free(path_name);
- }
- }
-
- finish:
- if (active_cache_changed) {
- if (write_cache(newfd, active_cache, active_nr) ||
- commit_lock_file(&lock_file))
- die("Unable to write new index file");
- }
-
- return has_errors ? 1 : 0;
-}
+++ /dev/null
-#include "cache.h"
-#include "refs.h"
-
-static const char git_update_ref_usage[] =
-"git-update-ref <refname> <value> [<oldval>] [-m <reason>]";
-
-int main(int argc, char **argv)
-{
- const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL;
- struct ref_lock *lock;
- unsigned char sha1[20], oldsha1[20];
- int i;
-
- setup_git_directory();
- git_config(git_default_config);
-
- for (i = 1; i < argc; i++) {
- if (!strcmp("-m", argv[i])) {
- if (i+1 >= argc)
- usage(git_update_ref_usage);
- msg = argv[++i];
- if (!*msg)
- die("Refusing to perform update with empty message.");
- if (strchr(msg, '\n'))
- die("Refusing to perform update with \\n in message.");
- continue;
- }
- if (!refname) {
- refname = argv[i];
- continue;
- }
- if (!value) {
- value = argv[i];
- continue;
- }
- if (!oldval) {
- oldval = argv[i];
- continue;
- }
- }
- if (!refname || !value)
- usage(git_update_ref_usage);
-
- if (get_sha1(value, sha1))
- die("%s: not a valid SHA1", value);
- memset(oldsha1, 0, 20);
- if (oldval && get_sha1(oldval, oldsha1))
- die("%s: not a valid old SHA1", oldval);
-
- lock = lock_any_ref_for_update(refname, oldval ? oldsha1 : NULL, 0);
- if (!lock)
- return 1;
- if (write_ref_sha1(lock, sha1, msg) < 0)
- return 1;
- return 0;
-}
+++ /dev/null
-/*
- * GIT - The information manager from hell
- *
- * Copyright (C) Linus Torvalds, 2005
- */
-#include "cache.h"
-#include "tree.h"
-#include "cache-tree.h"
-
-static int missing_ok = 0;
-static char *prefix = NULL;
-
-static const char write_tree_usage[] =
-"git-write-tree [--missing-ok] [--prefix=<prefix>/]";
-
-static struct lock_file lock_file;
-
-int main(int argc, char **argv)
-{
- int entries, was_valid, newfd;
-
- setup_git_directory();
-
- newfd = hold_lock_file_for_update(&lock_file, get_index_file());
- entries = read_cache();
-
- while (1 < argc) {
- char *arg = argv[1];
- if (!strcmp(arg, "--missing-ok"))
- missing_ok = 1;
- else if (!strncmp(arg, "--prefix=", 9))
- prefix = arg + 9;
- else
- die(write_tree_usage);
- argc--; argv++;
- }
-
- if (argc > 2)
- die("too many options");
-
- if (entries < 0)
- die("git-write-tree: error reading cache");
-
- if (!active_cache_tree)
- active_cache_tree = cache_tree();
-
- was_valid = cache_tree_fully_valid(active_cache_tree);
- if (!was_valid) {
- if (cache_tree_update(active_cache_tree,
- active_cache, active_nr,
- missing_ok, 0) < 0)
- die("git-write-tree: error building trees");
- if (0 <= newfd) {
- if (!write_cache(newfd, active_cache, active_nr))
- commit_lock_file(&lock_file);
- }
- /* Not being able to write is fine -- we are only interested
- * in updating the cache-tree part, and if the next caller
- * ends up using the old index with unupdated cache-tree part
- * it misses the work we did here, but that is just a
- * performance penalty and not a big deal.
- */
- }
- if (prefix) {
- struct cache_tree *subtree =
- cache_tree_find(active_cache_tree, prefix);
- printf("%s\n", sha1_to_hex(subtree->sha1));
- }
- else
- printf("%s\n", sha1_to_hex(active_cache_tree->sha1));
- return 0;
-}
int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
xdemitcb_t *ecb) {
+ int i = 2;
mmbuffer_t mb[3];
- int i;
mb[0].ptr = (char *) pre;
mb[0].size = psize;
mb[1].ptr = (char *) rec;
mb[1].size = size;
- i = 2;
-
- if (!size || rec[size-1] != '\n') {
- mb[2].ptr = "\n\\ No newline at end of file\n";
+ if (size > 0 && rec[size - 1] != '\n') {
+ mb[2].ptr = (char *) "\n\\ No newline at end of file\n";
mb[2].size = strlen(mb[2].ptr);
- i = 3;
+ i++;
}
-
if (ecb->outf(ecb->priv, mb, i) < 0) {
return -1;
#define XUTILS_H
+
long xdl_bogosqrt(long n);
int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
xdemitcb_t *ecb);