From: Jon Seymour <jon.seymour@gmail.com>
To: git@vger.kernel.org
Cc: torvalds@osdl.org, jon.seymour@gmail.com
Subject: [PATCH] Add support for --wrt-author, --author and --exclude-author switches to git-rev-list
Date: Tue, 07 Jun 2005 19:15:23 +1000 [thread overview]
Message-ID: <20050607091523.14051.qmail@blackcubes.dyndns.org> (raw)
[PATCH] Add support for --wrt-author, --author and --exclude-author switches to git-rev-list
This patch is a complete replacement for:
[PATCH] Add support for --wrt flag to git-rev-list
This patch adds support for --wrt-author, --exclude-author and --author switches
to git-rev-list.
When --wrt-author is specified, --merge-order is implied but
the linearisation of non-linear epochs is adjusted so that branches
contributed to by the author sort after branches contributed to by
others. This has the effect of presenting a linear history of changes as seen
by the author's own workspace.
For example, given this commit history:
a4 ---
| \ \
| b4 |
|/ | |
a3 | |
| | |
a2 | |
| | c3
| | |
| | c2
| b3 |
| | /|
| b2 |
| | c1
| | /
| b1 <-- commit authored by author@domain
a1 |
| |
a0 |
| /
root
--merge-order alone would sort it as follows:
= a4
| c3
| c2
| c1
^ b4
| b3
| b2
| b1
^ a3
| a2
| a1
| a0
= root
however, with --wrt-author --author=author@domain, git-rev-list sorts as follows:
= a4
| c3
| c2
| c1
^ b4
| a3
| a2
| a1
| a0
^ b3
| b2
| b1
= root
If --exclude-author is specified, then git-rev-list behaves as if a
^argument had been added for each commit authored by the author.
The --exclude-author option allows an author to see a brief summary of
changes since they last made a contribution to the commit graph. For example:
git-rev-list --exclude-author --pretty HEAD
To configure which author git-rev-list uses when processing the --wrt-author
and --exclude-author switches, use the --author=author@domain option. If this
option is not specified, git-rev-list uses GIT_AUTHOR_EMAIL or a value
derived from the local user, host and domain names (per git-commit-tree's algorithm)
To support this change, some additional functions were added to commit.c to allow
the extraction of author from the commit header.
Also, --show-breaks, like --wrt-author now implies --merge-order rather than requires it.
This change also updates Documentation/git-rev-list.txt to include documentation for
--wrt-author and other git-rev-list options not currently documented.
A test case has been included in t/t6000-rev-list.sh to verify this change works as
expected.
Use of --wrt-author implies a small overhead (linear with respect to nodes printed) compared with --merge-order.
This change extracts real email id formatting functions from commit-tree.c into user.c and user.h.
NOTE TO REVIEWERS: please pay special attention to get_real_identity()
which was extracted from commit-tree.c and placed into user.c. It was essentially
a cut and paste, but since this has the potential to affect the operation of git-commit-tree,
it would be worth being very careful about checking this change.
Signed-off-by: Jon Seymour <jon.seymour@gmail.com>
Diverged from ed37b5b2b94398f3ab8312dfdf23cfd25549e3ec by Linus Torvalds <torvalds@ppc970.osdl.org>
---
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -9,13 +9,25 @@ git-rev-list - Lists commit objects in r
SYNOPSIS
--------
-'git-rev-list' [ *--max-count*=number ] [ *--max-age*=timestamp ] [ *--min-age*=timestamp ] [ *--merge-order* [ *--show-breaks* ] ] <commit>
+'git-rev-list' [ *--max-count*=number ] [ *--max-age*=timestamp ] [ *--min-age*=timestamp ] [ *--pretty* ] [ *--parents* ] [ *--header* ] [ *--merge-order* ] [ *--show-breaks* ] [ *--wrt-author* ] [ *--exclude-author* ] [ *--author=author@domain* ] <head-to-include> <head-to-include> ...
+^<base-to-exclude>
+^<base-to-exclude> ...
DESCRIPTION
-----------
-Lists commit objects in reverse chronological order starting at the
-given commit, taking ancestry relationship into account. This is
-useful to produce human-readable log output.
+
+Lists commit objects in reverse chronological order starting at the commits specified by head-to-include values,
+taking ancestry relationship into account. git-rev-list will not print any commits that are reachable
+by any of the base-to-exclude values.
+
+If *--pretty* is specified, git-rev-list prints a short summary of each commit on stdout. This can be usefully
+parsed by git-shortlog to produce a short log of changes.
+
+If *--parents* is specified, git-rev-list prints a space separated list of parents on the same line as the
+commit identifier.
+
+If *--header* is specified, git-rev-list prints to stdout, on line after the identifier of each commit,
+the contents of the commit's header followed by a trailing NUL.
If *--merge-order* is specified, the commit history is decomposed into a unique sequence of minimal, non-linear
epochs and maximal, linear epochs. Non-linear epochs are then linearised by sorting them into merge order, which
@@ -42,17 +54,30 @@ Commits marked with (=) represent the bo
Commits marked with (|) are direct parents of commits immediately preceding the marked commit in the list.
Commits marked with (^) are not parents of the immediately preceding commit. These "breaks" represent necessary discontinuities implied by trying to represent an arbtirary DAG in a linear form.
-*--show-breaks* is only valid if *--merge-order* is also specified.
+The *--author* option is used to specify the author used by the *--wrt-author* and *--exclude-author* switches. If
+an *--author* option is not specified, the author used is derived from GIT_AUTHOR_EMAIL or, ultimately,
+from the local user, host and domain names as per the logic used by git-commit-tree.
+
+If *--wrt=author* is specified, then git-rev-list sorts commits so that contemporaneously
+developed commits appear to occur after (that is, sort before) any commits authored by the
+author specified by *--author*. This reflects the order in which that author
+sees contemporaneously developed commits appear in her own workspace.
+
+If *--exclude-author* is specified, then any commit authored by the author is marked as uninteresting as if it
+had been specified with ^ on the command line. This option restricts git-rev-list's to just the changes since
+the author contributed a change.
+
+Use of *--show-breaks*, *--exclude-author* or *--wrt-author* implies *--merge-order*.
Author
------
Written by Linus Torvalds <torvalds@osdl.org>
-Original *--merge-order* logic by Jon Seymour <jon.seymour@gmail.com>
+Original *--merge-order*, *--wrt-author* and *--exclude-author* logic by Jon Seymour <jon.seymour@gmail.com>
Documentation
--------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+Documentation by David Greaves, Junio C Hamano, Jon Seymour and the git-list <git@vger.kernel.org>.
GIT
---
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -41,9 +41,9 @@ install: $(PROG) $(SCRIPTS)
LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
tag.o delta.o date.o index.o diff-delta.o patch-delta.o entry.o \
- epoch.o refs.o
+ epoch.o refs.o user.o
LIB_FILE=libgit.a
-LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h epoch.h
+LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h epoch.h user.h
LIB_H += strbuf.h
LIB_OBJS += strbuf.o
@@ -138,6 +138,7 @@ diffcore-pickaxe.o : $(LIB_H) diffcore.h
diffcore-break.o : $(LIB_H) diffcore.h
diffcore-order.o : $(LIB_H) diffcore.h
epoch.o: $(LIB_H)
+user.o: $(LIB_H)
test: all
$(MAKE) -C t/ all
diff --git a/commit-tree.c b/commit-tree.c
--- a/commit-tree.c
+++ b/commit-tree.c
@@ -4,10 +4,11 @@
* Copyright (C) Linus Torvalds, 2005
*/
#include "cache.h"
+#include "user.h"
-#include <pwd.h>
#include <time.h>
#include <ctype.h>
+#include <pwd.h>
#define BLOCKING (1ul << 14)
@@ -100,17 +101,16 @@ static char *commit_tree_usage = "git-co
int main(int argc, char **argv)
{
- int i, len;
+ int i;
int parents = 0;
unsigned char tree_sha1[20];
unsigned char parent_sha1[MAXPARENT][20];
unsigned char commit_sha1[20];
char *gecos, *realgecos, *commitgecos;
- char *email, *commitemail, realemail[1000];
+ char *email, *commitemail, *realemail;
char date[50], realdate[50];
char *audate, *cmdate;
char comment[1000];
- struct passwd *pw;
char *buffer;
unsigned int size;
@@ -128,18 +128,8 @@ int main(int argc, char **argv)
}
if (!parents)
fprintf(stderr, "Committing initial tree %s\n", argv[1]);
- pw = getpwuid(getuid());
- if (!pw)
- die("You don't exist. Go away!");
- realgecos = pw->pw_gecos;
- len = strlen(pw->pw_name);
- memcpy(realemail, pw->pw_name, len);
- realemail[len] = '@';
- gethostname(realemail+len+1, sizeof(realemail)-len-1);
- if (!strchr(realemail+len+1, '.')) {
- strcat(realemail, ".");
- getdomainname(realemail+strlen(realemail), sizeof(realemail)-strlen(realemail)-1);
- }
+
+ get_real_identity(&realemail, &realgecos);
datestamp(realdate, sizeof(realdate));
strcpy(date, realdate);
diff --git a/commit.c b/commit.c
--- a/commit.c
+++ b/commit.c
@@ -302,3 +302,65 @@ int count_parents(struct commit * commit
return count;
}
+int copy_commit_header(struct commit * commit, char * header, int index, char * buffer, int len)
+{
+ char * p = commit->buffer;
+
+ while (*p) {
+
+ char * q = header;
+ if (*p == '\n') {
+ break;
+ }
+
+ int matched;
+
+ for (matched = 1; *p != ' ' && *p != '\n'; p++, q++) {
+ matched = matched & (*q==*p);
+ }
+
+ if (matched && index) {
+ // if we matched but we haven't seen the index'th element yet,
+ // just decrement the index then pretend we didn't match
+ index--;
+ matched = 0;
+ }
+
+ if (!matched) {
+
+ // skip to start of next header line
+
+ for (;*p!='\n';p++)
+ ;
+ p++;
+
+ } else {
+
+ int count = 0; // number of characters in value
+
+ if (*p == ' ') {
+ p++;
+
+ for (count = 0; *p != '\n'; p++, count++, len--) {
+ if (len > 0) {
+ *buffer++=*p;
+ }
+ }
+
+ }
+
+ if (len > 0) {
+ *buffer = 0;
+ }
+
+ return (len > 0) ? count+1 : -(count+1);
+
+ }
+ }
+ return 0;
+}
+
+int copy_author(struct commit * commit, char * buffer, int len)
+{
+ return copy_commit_header(commit, "author", 0, buffer, len);
+}
diff --git a/commit.h b/commit.h
--- a/commit.h
+++ b/commit.h
@@ -53,4 +53,17 @@ struct commit *pop_most_recent_commit(st
struct commit *pop_commit(struct commit_list **stack);
int count_parents(struct commit * commit);
+
+//
+// Copies the value of the (index+1)'th commit header matching the name specified
+// into the buffer supplied and append a trailing NUL.
+//
+// Returns n<0 if the buffer was too short (-n is the required length)
+// Returns 0 if the header doesn't exist.
+// Returns n>0 where n is the length of the copied zero-terminated value, including the terminating zero.
+//
+int copy_commit_header(struct commit * commit, char * header, int index, char * buffer, int len);
+
+// Copies the commit's author value into the buffer supplied. Return values as per copy_commit_header.
+int copy_author(struct commit * commit, char * buffer, int len);
#endif /* COMMIT_H */
diff --git a/epoch.c b/epoch.c
--- a/epoch.c
+++ b/epoch.c
@@ -450,11 +450,15 @@ static void mark_ancestors_uninteresting
// Sorts the nodes of the first epoch of the epoch sequence of the epoch headed at head
// into merge order.
//
-static void sort_first_epoch(struct commit *head, struct commit_list **stack)
+static void sort_first_epoch(struct commit *head, struct commit_list **stack, marker_func marker)
{
struct commit_list *parents;
struct commit_list *reversed_parents = NULL;
+ if (marker) {
+ (*marker)(head);
+ }
+
head->object.flags |= VISITED;
//
@@ -464,17 +468,21 @@ static void sort_first_epoch(struct comm
// so we need to reverse this list to output the oldest (or most "local") commits last.
//
- for (parents = head->parents; parents; parents = parents->next)
- commit_list_insert(parents->item, &reversed_parents);
-
- //
- // todo: by sorting the parents in a different order, we can alter the
- // merge order to show contemporaneous changes in parallel branches
- // occurring after "local" changes. This is useful for a developer
- // when a developer wants to see all changes that were incorporated
- // into the same merge as her own changes occur after her own
- // changes.
- //
+ if (!head->object.util) {
+
+ for (parents = head->parents; parents; parents = parents->next)
+ commit_list_insert(parents->item, &reversed_parents);
+
+ } else {
+
+ // reverse the locally sorted parents and reset utility pointer to NULL
+
+ parents = (struct commit_list *)head->object.util;
+ head->object.util = NULL;
+ while (parents) {
+ commit_list_insert(pop_commit(&parents), &reversed_parents);
+ }
+ }
while (reversed_parents) {
@@ -502,7 +510,7 @@ static void sort_first_epoch(struct comm
} else {
- sort_first_epoch(parent, stack);
+ sort_first_epoch(parent, stack, marker);
if (reversed_parents) {
//
@@ -555,13 +563,82 @@ static int emit_stack(struct commit_list
}
//
+// Sort a list of commits in local last order. A commit is "local" if any of its ancestors (except the base)
+// causes (*local_test)() to return a non-zero value.
+//
+// The sorted list is returned in *sorted. A side effect of this function is to set each object.util
+// pointer to a list of parents sorted in local_last order.
+//
+// Does nothing except set *sorted to NULL if either list or local_test are NULL.
+//
+static void sort_list_in_local_last_order(struct commit_list * list, local_test_func local_test, struct commit_list ** sorted)
+{
+ if (!list || !local_test) {
+ *sorted = NULL;
+ return;
+ }
+
+ struct commit_list * next;
+
+ for ( next = list ; next; next = next->next) {
+
+ struct commit * item = next->item;
+
+ if (item->object.flags & BOUNDARY || item->object.util) {
+ // we have already visited this item or we have
+ // reached the boundary.
+ continue;
+ }
+
+ if ((*local_test)(item)) {
+ item->object.flags |= LOCAL;
+ }
+
+ sort_list_in_local_last_order(item->parents, local_test, (struct commit_list **)&item->object.util);
+
+ struct commit_list * sorted_parents = (struct commit_list *)&item->object.util;
+
+ if (sorted_parents && (sorted_parents->item->object.flags & LOCAL)) {
+ item->object.flags |= LOCAL;
+ }
+ }
+
+ //
+ // Iterate over the original list and generate two lists - a list of the
+ // non-local parents and list of local parents. Then splice the list
+ // of local parents onto the end of the non-local parents to form
+ // a new list.
+ //
+
+ struct commit_list * non_local = NULL;
+ struct commit_list * local = NULL;
+ struct commit_list **p = &local;
+ struct commit_list **q = &non_local;
+
+ for (next = list; next; next = next->next) {
+
+ if (next->item->object.flags & LOCAL) {
+ *p = commit_list_insert(next->item, p);
+ p = &(*p)->next;
+ } else {
+ *q = commit_list_insert(next->item, q);
+ q = &(*q)->next;
+ }
+ }
+
+ *q = local;
+ *sorted = non_local;
+
+}
+
+//
// Sorts an arbitrary epoch into merge order by sorting each epoch
// of its epoch sequence into order.
//
// Note: this algorithm currently leaves traces of its execution in the
// object flags of nodes it discovers. This should probably be fixed.
//
-static int sort_in_merge_order(struct commit *head_of_epoch, emitter_func emitter)
+static int sort_in_merge_order(struct commit *head_of_epoch, emitter_func emitter, local_test_func local_test, marker_func marker)
{
struct commit *next = head_of_epoch;
int ret = 0;
@@ -586,6 +663,10 @@ static int sort_in_merge_order(struct co
while (HAS_EXACTLY_ONE_PARENT(next)
&& (action != STOP)
&& !ret) {
+
+ if (marker) {
+ (*marker)(next);
+ }
if (next->object.flags & UNINTERESTING) {
action = STOP;
@@ -602,7 +683,10 @@ static int sort_in_merge_order(struct co
} else {
struct commit_list *stack = NULL;
- sort_first_epoch(next, &stack);
+
+ sort_list_in_local_last_order(next->parents, local_test, (struct commit_list **)&next->object.util);
+
+ sort_first_epoch(next, &stack, marker);
action = emit_stack(&stack, emitter);
next = base;
@@ -623,7 +707,7 @@ static int sort_in_merge_order(struct co
// subgraph using the sort_first_epoch algorithm. Once we have reached the base
// we can continue sorting using sort_in_merge_order.
//
-int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter)
+int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter, local_test_func local_test, marker_func marker)
{
struct commit_list *stack = NULL;
struct commit *base;
@@ -631,7 +715,8 @@ int sort_list_in_merge_order(struct comm
int ret = 0;
int action = CONTINUE;
- struct commit_list *reversed = NULL;
+ struct commit_list *filtered = NULL;
+ struct commit_list **p = &filtered;
for (; list; list = list->next) {
@@ -642,37 +727,50 @@ int sort_list_in_merge_order(struct comm
fprintf(stderr, "%s: duplicate commit %s ignored\n", __FUNCTION__, sha1_to_hex(next->object.sha1));
} else {
next->object.flags |= DUPCHECK;
- commit_list_insert(list->item, &reversed);
+ *p = commit_list_insert(list->item, p);
+ p = &(*p)->next;
}
}
}
- if (!reversed->next) {
+ if (!filtered->next) {
// if there is only one element in the list, we can sort it using
// sort_in_merge_order.
- base = reversed->item;
+ base = filtered->item;
} else {
// otherwise, we search for the base of the list
- if ((ret = find_base_for_list(reversed, &base)))
+ if ((ret = find_base_for_list(filtered, &base)))
return ret;
if (base) {
base->object.flags |= BOUNDARY;
}
-
+
+ struct commit_list * sorted;
+
+ sort_list_in_local_last_order(filtered, local_test, &sorted);
+
+ if (!sorted) {
+ sorted = filtered;
+ }
+
+ struct commit_list * reversed = NULL;
+ while (sorted)
+ commit_list_insert(pop_commit(&sorted), &reversed);
+
while (reversed) {
- sort_first_epoch(pop_commit(&reversed), &stack);
+ sort_first_epoch(pop_commit(&reversed), &stack, marker);
if (reversed) {
//
// if we have more commits to push, then the
- // first push for the next parent may (or may not)
+ // first push for the next commit may (or may not)
// represent a discontinuity with respect to the
- // parent currently on the top of the stack.
+ // commit currently on the top of the stack.
//
// mark it for checking here, and check it
// with the next push...see sort_first_epoch for
@@ -686,8 +784,9 @@ int sort_list_in_merge_order(struct comm
}
if (base && (action != STOP)) {
- ret = sort_in_merge_order(base, emitter);
+ ret = sort_in_merge_order(base, emitter, local_test, marker);
}
return ret;
}
+
diff --git a/epoch.h b/epoch.h
--- a/epoch.h
+++ b/epoch.h
@@ -8,13 +8,19 @@
#define DO 2
typedef int (*emitter_func) (struct commit *);
-int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter);
+// functions of this type return non-zero if the commit is "local" by some private assessment of
+// what it is for a commit to be local.
+typedef int (*local_test_func) (struct commit *);
+typedef void (*marker_func) (struct commit *);
+
+extern int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter, local_test_func local_test, marker_func marker);
#define UNINTERESTING (1u<<2)
#define BOUNDARY (1u<<3)
#define VISITED (1u<<4)
#define DISCONTINUITY (1u<<5)
#define DUPCHECK (1u<<6)
+#define LOCAL (1u<<7)
#endif /* EPOCH_H */
diff --git a/rev-list.c b/rev-list.c
--- a/rev-list.c
+++ b/rev-list.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "commit.h"
#include "epoch.h"
+#include "user.h"
#define SEEN (1u << 0)
#define INTERESTING (1u << 1)
@@ -11,8 +12,13 @@ static const char rev_list_usage[] =
" --max-age=epoch\n"
" --min-age=epoch\n"
" --header\n"
+ " --parents\n"
" --pretty\n"
- " --merge-order [ --show-breaks ]";
+ " --merge-order\n"
+ " --wrt-author\n"
+ " --exclude-author\n"
+ " --author author@domain\n"
+ " --show-breaks ]";
static int verbose_header = 0;
static int show_parents = 0;
@@ -24,6 +30,9 @@ static int max_count = -1;
static enum cmit_fmt commit_format = CMIT_FMT_RAW;
static int merge_order = 0;
static int show_breaks = 0;
+static char * local_author = NULL;
+static int exclude_author = 0;
+static int wrt_author = 0;
static void show_commit(struct commit *commit)
{
@@ -147,6 +156,23 @@ static enum cmit_fmt get_commit_format(c
usage(rev_list_usage);
}
+static int is_local_author(struct commit * commit)
+{
+ static char author[16384];
+ if (copy_author(commit, author, sizeof(author)) > 0) {
+ if (strstr(author, local_author)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void mark_authors_own_uninteresting(struct commit * commit)
+{
+ if (is_local_author(commit)) {
+ commit->object.flags |= UNINTERESTING;
+ }
+}
int main(int argc, char **argv)
{
@@ -192,6 +218,19 @@ int main(int argc, char **argv)
}
if (!strncmp(arg, "--show-breaks", 13)) {
show_breaks = 1;
+ merge_order = 1;
+ continue;
+ }
+ if (!strncmp(arg, "--author=", 9)) {
+ local_author=strdup(&arg[9]);
+ continue;
+ }
+ if (!strncmp(arg, "--wrt-author", 6)) {
+ wrt_author = 1;
+ continue;
+ }
+ if (!strncmp(arg, "--exclude-author", 16)) {
+ exclude_author = 1;
continue;
}
@@ -201,7 +240,7 @@ int main(int argc, char **argv)
arg++;
limited = 1;
}
- if (get_sha1(arg, sha1) || (show_breaks && !merge_order))
+ if (get_sha1(arg, sha1))
usage(rev_list_usage);
commit = lookup_commit_reference(sha1);
if (!commit || parse_commit(commit) < 0)
@@ -213,6 +252,8 @@ int main(int argc, char **argv)
if (!list)
usage(rev_list_usage);
+ merge_order = merge_order || wrt_author || exclude_author || show_breaks;
+
if (!merge_order) {
if (limited)
@@ -220,11 +261,31 @@ int main(int argc, char **argv)
show_commit_list(list);
} else {
+
+ if ((exclude_author|wrt_author) && !local_author) {
+ local_author = strdup(gitenv("GIT_AUTHOR_EMAIL")) ? : NULL;
+ if (!local_author) {
+ get_real_identity(&local_author, NULL);
+ }
+ }
- if (sort_list_in_merge_order(list, &process_commit)) {
- die("merge order sort failed\n");
+ if (local_author) {
+ // add delimiters to improve accuracy of match
+ char * tmp=xmalloc(strlen(local_author)+3);
+ sprintf(tmp, "<%s>", local_author);
+ free(local_author);
+ local_author = tmp;
+ }
+
+ if (sort_list_in_merge_order(
+ list,
+ &process_commit,
+ local_author ? &is_local_author : NULL,
+ exclude_author ? &mark_authors_own_uninteresting : NULL)
+ ) {
+ die("merge order sort failed\n");
}
-
+
}
return 0;
diff --git a/user.c b/user.c
new file mode 100644
--- /dev/null
+++ b/user.c
@@ -0,0 +1,32 @@
+#include "cache.h"
+#include "user.h"
+#include <string.h>
+#include <pwd.h>
+
+void get_real_identity(char **email, char **gecos)
+{
+ static char buffer[1000];
+ struct passwd *pw;
+ int len;
+
+ pw = getpwuid(getuid());
+ if (!pw)
+ die("You don't exist. Go away!");
+
+ len = strlen(pw->pw_name);
+ memcpy(buffer, pw->pw_name, len);
+ buffer[len] = '@';
+ gethostname(buffer + len + 1, sizeof(buffer) - len - 1);
+ if (!strchr(buffer + len + 1, '.')) {
+ strcat(buffer, ".");
+ getdomainname(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer) - 1);
+ }
+
+ if (gecos) {
+ *gecos = strdup(pw->pw_gecos);
+ }
+
+ if (email) {
+ *email = strdup(buffer);
+ }
+}
diff --git a/user.h b/user.h
new file mode 100644
--- /dev/null
+++ b/user.h
@@ -0,0 +1,8 @@
+#ifndef USER_H
+#define USER_H
+//
+// Allocates two new strings to contain the real email and
+// name of the current user.
+//
+extern void get_real_identity(char **email, char **gecos);
+#endif
next reply other threads:[~2005-06-07 9:14 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-06-07 9:15 Jon Seymour [this message]
2005-06-07 9:30 ` [PATCH] Add support for --wrt-author, --author and --exclude-author switches to git-rev-list Jon Seymour
2005-06-07 9:49 ` Petr Baudis
[not found] ` <2cfc403205060702594da21fb1@mail.gmail.com>
[not found] ` <2cfc403205060702596dee7341@mail.gmail.com>
2005-06-07 15:58 ` Jon Seymour
2005-06-08 0:54 ` Jon Seymour
2005-06-08 8:58 ` Petr Baudis
2005-06-08 9:31 ` Jon Seymour
2005-06-08 10:52 ` Jon Seymour
2005-06-08 11:14 ` Jon Seymour
2005-06-08 16:36 ` [WITHDRAW PATCH] " Jon Seymour
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20050607091523.14051.qmail@blackcubes.dyndns.org \
--to=jon.seymour@gmail.com \
--cc=git@vger.kernel.org \
--cc=torvalds@osdl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).