Make git-cherry-pick in target "all"
[git.git] / ident.c
1 /*
2  * ident.c
3  *
4  * create git identifier lines of the form "name <email> date"
5  *
6  * Copyright (C) 2005 Linus Torvalds
7  */
8 #include "cache.h"
9
10 #include <pwd.h>
11
12 static char git_default_date[50];
13
14 static void copy_gecos(struct passwd *w, char *name, int sz)
15 {
16         char *src, *dst;
17         int len, nlen;
18
19         nlen = strlen(w->pw_name);
20
21         /* Traditionally GECOS field had office phone numbers etc, separated
22          * with commas.  Also & stands for capitalized form of the login name.
23          */
24
25         for (len = 0, dst = name, src = w->pw_gecos; len < sz; src++) {
26                 int ch = *src;
27                 if (ch != '&') {
28                         *dst++ = ch;
29                         if (ch == 0 || ch == ',')
30                                 break;
31                         len++;
32                         continue;
33                 }
34                 if (len + nlen < sz) {
35                         /* Sorry, Mr. McDonald... */
36                         *dst++ = toupper(*w->pw_name);
37                         memcpy(dst, w->pw_name + 1, nlen - 1);
38                         dst += nlen - 1;
39                 }
40         }
41         if (len < sz)
42                 name[len] = 0;
43         else
44                 die("Your parents must have hated you!");
45
46 }
47
48 int setup_ident(void)
49 {
50         int len;
51         struct passwd *pw = getpwuid(getuid());
52
53         if (!pw)
54                 die("You don't exist. Go away!");
55
56         /* Get the name ("gecos") */
57         copy_gecos(pw, git_default_name, sizeof(git_default_name));
58
59         /* Make up a fake email address (name + '@' + hostname [+ '.' + domainname]) */
60         len = strlen(pw->pw_name);
61         if (len > sizeof(git_default_email)/2)
62                 die("Your sysadmin must hate you!");
63         memcpy(git_default_email, pw->pw_name, len);
64         git_default_email[len++] = '@';
65         gethostname(git_default_email + len, sizeof(git_default_email) - len);
66         if (!strchr(git_default_email+len, '.')) {
67                 len = strlen(git_default_email);
68                 git_default_email[len++] = '.';
69                 getdomainname(git_default_email+len, sizeof(git_default_email)-len);
70         }
71         /* And set the default date */
72         datestamp(git_default_date, sizeof(git_default_date));
73         return 0;
74 }
75
76 static int add_raw(char *buf, int size, int offset, const char *str)
77 {
78         int len = strlen(str);
79         if (offset + len > size)
80                 return size;
81         memcpy(buf + offset, str, len);
82         return offset + len;
83 }
84
85 static int crud(unsigned char c)
86 {
87         static char crud_array[256];
88         static int crud_array_initialized = 0;
89
90         if (!crud_array_initialized) {
91                 int k;
92
93                 for (k = 0; k <= 31; ++k) crud_array[k] = 1;
94                 crud_array[' '] = 1;
95                 crud_array['.'] = 1;
96                 crud_array[','] = 1;
97                 crud_array[':'] = 1;
98                 crud_array[';'] = 1;
99                 crud_array['<'] = 1;
100                 crud_array['>'] = 1;
101                 crud_array['"'] = 1;
102                 crud_array['\''] = 1;
103                 crud_array_initialized = 1;
104         }
105         return crud_array[c];
106 }
107
108 /*
109  * Copy over a string to the destination, but avoid special
110  * characters ('\n', '<' and '>') and remove crud at the end
111  */
112 static int copy(char *buf, int size, int offset, const char *src)
113 {
114         int i, len;
115         unsigned char c;
116
117         /* Remove crud from the beginning.. */
118         while ((c = *src) != 0) {
119                 if (!crud(c))
120                         break;
121                 src++;
122         }
123
124         /* Remove crud from the end.. */
125         len = strlen(src);
126         while (len > 0) {
127                 c = src[len-1];
128                 if (!crud(c))
129                         break;
130                 --len;
131         }
132
133         /*
134          * Copy the rest to the buffer, but avoid the special
135          * characters '\n' '<' and '>' that act as delimeters on
136          * a identification line
137          */
138         for (i = 0; i < len; i++) {
139                 c = *src++;
140                 switch (c) {
141                 case '\n': case '<': case '>':
142                         continue;
143                 }
144                 if (offset >= size)
145                         return size;
146                 buf[offset++] = c;
147         }
148         return offset;
149 }
150
151 char *get_ident(const char *name, const char *email, const char *date_str)
152 {
153         static char buffer[1000];
154         char date[50];
155         int i;
156
157         if (!name)
158                 name = git_default_name;
159         if (!email)
160                 email = git_default_email;
161         strcpy(date, git_default_date);
162         if (date_str)
163                 parse_date(date_str, date, sizeof(date));
164
165         i = copy(buffer, sizeof(buffer), 0, name);
166         i = add_raw(buffer, sizeof(buffer), i, " <");
167         i = copy(buffer, sizeof(buffer), i, email);
168         i = add_raw(buffer, sizeof(buffer), i, "> ");
169         i = copy(buffer, sizeof(buffer), i, date);
170         if (i >= sizeof(buffer))
171                 die("Impossibly long personal identifier");
172         buffer[i] = 0;
173         return buffer;
174 }
175
176 char *git_author_info(void)
177 {
178         return get_ident(getenv("GIT_AUTHOR_NAME"), getenv("GIT_AUTHOR_EMAIL"), getenv("GIT_AUTHOR_DATE"));
179 }
180
181 char *git_committer_info(void)
182 {
183         return get_ident(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"), getenv("GIT_COMMITTER_DATE"));
184 }