Barf nicely when "git push" is run without parameter.
[git/gitweb.git] / tools / mailinfo.c
bloba36123a1f5bc27e90debcf19d5348937c738d2f2
1 /*
2 * Another stupid program, this one parsing the headers of an
3 * email to figure out authorship and subject
4 */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <ctype.h>
10 static FILE *cmitmsg, *patchfile;
12 static int keep_subject = 0;
13 static char line[1000];
14 static char date[1000];
15 static char name[1000];
16 static char email[1000];
17 static char subject[1000];
19 static char *sanity_check(char *name, char *email)
21 int len = strlen(name);
22 if (len < 3 || len > 60)
23 return email;
24 if (strchr(name, '@') || strchr(name, '<') || strchr(name, '>'))
25 return email;
26 return name;
29 static int handle_from(char *line)
31 char *at = strchr(line, '@');
32 char *dst;
34 if (!at)
35 return 0;
38 * If we already have one email, don't take any confusing lines
40 if (*email && strchr(at+1, '@'))
41 return 0;
43 while (at > line) {
44 char c = at[-1];
45 if (isspace(c) || c == '<')
46 break;
47 at--;
49 dst = email;
50 for (;;) {
51 unsigned char c = *at;
52 if (!c || c == '>' || isspace(c))
53 break;
54 *at++ = ' ';
55 *dst++ = c;
57 *dst++ = 0;
59 at = line + strlen(line);
60 while (at > line) {
61 unsigned char c = *--at;
62 if (isalnum(c))
63 break;
64 *at = 0;
67 at = line;
68 for (;;) {
69 unsigned char c = *at;
70 if (!c)
71 break;
72 if (isalnum(c))
73 break;
74 at++;
77 at = sanity_check(at, email);
79 strcpy(name, at);
80 return 1;
83 static void handle_date(char *line)
85 strcpy(date, line);
88 static void handle_subject(char *line)
90 strcpy(subject, line);
93 static void check_line(char *line, int len)
95 if (!memcmp(line, "From:", 5) && isspace(line[5]))
96 handle_from(line+6);
97 else if (!memcmp(line, "Date:", 5) && isspace(line[5]))
98 handle_date(line+6);
99 else if (!memcmp(line, "Subject:", 8) && isspace(line[8]))
100 handle_subject(line+9);
103 static char * cleanup_subject(char *subject)
105 if (keep_subject)
106 return subject;
107 for (;;) {
108 char *p;
109 int len, remove;
110 switch (*subject) {
111 case 'r': case 'R':
112 if (!memcmp("e:", subject+1, 2)) {
113 subject +=3;
114 continue;
116 break;
117 case ' ': case '\t': case ':':
118 subject++;
119 continue;
121 case '[':
122 p = strchr(subject, ']');
123 if (!p) {
124 subject++;
125 continue;
127 len = strlen(p);
128 remove = p - subject;
129 if (remove <= len *2) {
130 subject = p+1;
131 continue;
133 break;
135 return subject;
139 static void cleanup_space(char *buf)
141 unsigned char c;
142 while ((c = *buf) != 0) {
143 buf++;
144 if (isspace(c)) {
145 buf[-1] = ' ';
146 c = *buf;
147 while (isspace(c)) {
148 int len = strlen(buf);
149 memmove(buf, buf+1, len);
150 c = *buf;
156 static void handle_rest(void)
158 FILE *out = cmitmsg;
159 char *sub = cleanup_subject(subject);
160 cleanup_space(name);
161 cleanup_space(date);
162 cleanup_space(email);
163 cleanup_space(sub);
164 printf("Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n", name, email, sub, date);
166 do {
167 if (!memcmp("diff -", line, 6) ||
168 !memcmp("---", line, 3) ||
169 !memcmp("Index: ", line, 7))
170 out = patchfile;
172 fputs(line, out);
173 } while (fgets(line, sizeof(line), stdin) != NULL);
175 if (out == cmitmsg) {
176 fprintf(stderr, "No patch found\n");
177 exit(1);
180 fclose(cmitmsg);
181 fclose(patchfile);
184 static int eatspace(char *line)
186 int len = strlen(line);
187 while (len > 0 && isspace(line[len-1]))
188 line[--len] = 0;
189 return len;
192 static void handle_body(void)
194 int has_from = 0;
195 int has_date = 0;
197 /* First lines of body can have From: and Date: */
198 while (fgets(line, sizeof(line), stdin) != NULL) {
199 int len = eatspace(line);
200 if (!len)
201 continue;
202 if (!memcmp("From:", line, 5) && isspace(line[5])) {
203 if (!has_from && handle_from(line+6)) {
204 has_from = 1;
205 continue;
208 if (!memcmp("Date:", line, 5) && isspace(line[5])) {
209 if (!has_date) {
210 handle_date(line+6);
211 has_date = 1;
212 continue;
215 line[len] = '\n';
216 handle_rest();
217 break;
221 static int read_one_header_line(char *line, int sz, FILE *in)
223 int ofs = 0;
224 while (ofs < sz) {
225 int peek, len;
226 if (fgets(line + ofs, sz - ofs, in) == NULL)
227 return ofs;
228 len = eatspace(line + ofs);
229 if (len == 0)
230 return ofs;
231 peek = fgetc(in); ungetc(peek, in);
232 if (peek == ' ' || peek == '\t') {
233 /* Yuck, 2822 header "folding" */
234 ofs += len;
235 continue;
237 return ofs + len;
239 return ofs;
242 static void usage(void)
244 fprintf(stderr, "mailinfo msg-file patch-file < email\n");
245 exit(1);
248 static const char mailinfo_usage[] =
249 "git-mailinfo [-k] msg patch <mail >info";
250 int main(int argc, char ** argv)
252 while (1 < argc && argv[1][0] == '-') {
253 if (!strcmp(argv[1], "-k"))
254 keep_subject = 1;
255 else {
256 fprintf(stderr, "usage: %s\n", mailinfo_usage);
257 exit(1);
259 argc--; argv++;
262 if (argc != 3)
263 usage();
264 cmitmsg = fopen(argv[1], "w");
265 if (!cmitmsg) {
266 perror(argv[1]);
267 exit(1);
269 patchfile = fopen(argv[2], "w");
270 if (!patchfile) {
271 perror(argv[2]);
272 exit(1);
274 while (1) {
275 int len = read_one_header_line(line, sizeof(line), stdin);
276 if (!len) {
277 handle_body();
278 break;
280 check_line(line, len);
282 return 0;