13 /* Some systems do not define EXIT_*, despite otherwise supporting C89 */
18 /* FIXME -- WCN : Currently not support corporation statistic */
23 struct company
*child
;
30 struct list_head list
;
33 unsigned long long int chgline
;
37 struct list_head
*child
;
38 struct list_head
*dir
;
42 struct list_head list
;
45 unsigned long long int chgline
;
46 struct list_head
*child
;
47 struct list_head
*dir
;
51 struct list_head list
;
52 struct list_head cnt_list
;
54 struct company
*parent
;
55 struct country
*nation
;
57 unsigned long long int chgline
;
61 /* to find out employers interest in which area */
63 struct list_head list
;
67 unsigned long long int chgline
;
70 struct list_head
*cnty_list
;
72 /* The name this program was run with. */
77 int g_comtop
= NSELECT
;
80 int g_person
= NSELECT
;
81 int g_nation
= NSELECT
;
82 int g_pertop
= NSELECT
;
86 int g_notconv
= NSELECT
;
88 int g_interest
= NSELECT
;
89 int g_nat_interest
= NSELECT
;
90 /* Other statistics, such as: Reported-by, Reviewed-by, Tested-by, Acked-by */
91 int g_other
= NSELECT
;
92 int g_warning
= NSELECT
;
93 int g_nospam
= NSELECT
;
102 char *p_nat_interest
;
105 char *p_rls
="linux"; /* set it to "linux" as default */
106 const char *html_tmpl_h
= "./html_tmpl_h.html";
107 const char *html_tmpl_f
= "./html_tmpl_f.html";
108 const char *tmp_author_file
= "./tmp_author";
109 const char *BUGREPORT
= "ellre923@gmail.com";
111 /* what kind of statistics */
113 #define OTHER_REPORT 0
114 #define OTHER_REVIEW 1
119 const char *str_line
= "changed lines";
120 const char *str_patch
= "patch sets";
121 const char *str_report
= "Reported-by";
122 const char *str_review
= "Reviewed-by";
123 const char *str_test
= "Tested-by";
124 const char *str_ack
= "Acked-by";
125 const char *str_sof
= "Signed-off-by";
126 char statistics_msg
[32];
128 #define STRUCT_INIT(type) (type *)malloc(sizeof(type))
130 #define NODE_INIT(type, node) do { \
131 node = STRUCT_INIT(type); \
132 if (node == NULL) { \
133 printf("[ERROR]: No enough mem\n"); \
136 memset(node, 0, sizeof(type)); \
137 INIT_LIST_HEAD(&(node->list)); } while (0)
139 #define NODE_SET_NAME(node, str) do {\
140 node->name = (char *)malloc(strlen(str)+1);\
141 if (node->name == NULL) {\
142 printf("[ERROR]: No enough mem\n"); \
145 memcpy(node->name, str, strlen(str)+1); } while (0)
147 #define NODE_SET_CNT(node, str) do {\
148 node->country = (char *)malloc(strlen(str)+1);\
149 if (node->country == NULL) {\
150 printf("[ERROR]: No enough mem\n"); \
153 memcpy(node->country, str, strlen(str)+1); } while (0)
155 #define LIST_RESORT(head, list_node, type, member) do {\
156 struct list_head *list_cur; \
157 type *node = list_entry(list_node, type, member); \
158 int cnt = node->cnt; \
159 int chgline = node->chgline; \
160 list_for_each(list_cur, head) { \
161 type *node_cur = list_entry(list_cur, type, member); \
162 if (g_line == SELECT) { \
163 if (node_cur->chgline <= chgline) \
166 if (node_cur->cnt <= cnt) \
170 if (list_node != list_cur) \
171 list_move_tail(list_node, list_cur); } while (0)
173 /* Update the child's info of the com. */
174 static void update_child(struct person
*per_cur
, unsigned long long int chgline
)
177 per_cur
->chgline
+= chgline
;
178 LIST_RESORT(per_cur
->parent
->child
, &(per_cur
->list
),
179 struct person
, list
);
182 /* Update the dir list of nation */
183 static int update_cnty_dir(struct country
*cnty
, struct list_head
*dir_list
)
185 struct directory
*dir_current
, *dir
, *dir_current2
;
187 if (list_empty(dir_list
))
190 list_for_each_entry(dir_current
, dir_list
, list
) {
191 list_for_each_entry(dir_current2
, cnty
->dir
, list
)
192 if (strcasestr(dir_current2
->name
, dir_current
->name
))
194 if (&dir_current2
->list
== cnty
->dir
) {
196 NODE_INIT(struct directory
, dir
);
197 NODE_SET_NAME(dir
, dir_current
->name
);
199 list_add_tail(&(dir
->list
), cnty
->dir
);
201 struct list_head
*cur_dir_list
= &(dir_current2
->list
);
203 LIST_RESORT(cnty
->dir
, cur_dir_list
, struct directory
, list
);
209 /* Update the person's info in the global per list. */
210 static void update_per(struct person
*per_cur
, struct list_head
*per_list
,
211 unsigned long long int chgline
,
212 struct list_head
*dir_list
)
215 per_cur
->chgline
+= chgline
;
216 LIST_RESORT(per_list
, &(per_cur
->list
), struct person
, list
);
218 per_cur
->nation
->cnt
++;
219 per_cur
->nation
->chgline
+= chgline
;
220 update_cnty_dir(per_cur
->nation
, dir_list
);
221 LIST_RESORT(per_cur
->nation
->child
, &(per_cur
->cnt_list
),
222 struct person
, cnt_list
);
223 LIST_RESORT(cnty_list
, &(per_cur
->nation
->list
), struct country
, list
);
227 * new_per: Create and add a per node to com's child list. If the global per
228 * list has no this per node, create and add the same node to global
230 * @com_cur: The com node which should link the new per node.
231 * @per_list: The global per list.
232 * @per_name: The person's name.
233 * @chgline: The commit's changed lines.
234 * @dir_list: The patch's dir list used for nation dir list update.
235 * Return: 0 - successful
238 static int new_per(struct company
*com_cur
, struct list_head
*per_list
,
239 char *per_name
, unsigned long long int chgline
,
240 struct list_head
*dir_list
)
243 char *per_cnt
= NULL
;
244 char *mail_name
= NULL
;
246 struct person
*per_current
;
247 struct country
*cnty
;
249 /* create a new person node which will be added to the com */
250 NODE_INIT(struct person
, per
);
251 NODE_SET_NAME(per
, per_name
);
252 conv_cnt(per_name
, &per_cnt
);
253 NODE_SET_CNT(per
, per_cnt
);
254 per
->parent
= com_cur
;
256 per
->chgline
+= chgline
;
258 /* find the nation in global list */
259 list_for_each_entry(cnty
, cnty_list
, list
)
260 if (memcmp(cnty
->name
, per_cnt
, strlen(per_cnt
)+1)
263 if (&(cnty
->list
) == cnty_list
) {
264 /* create a new nation */
265 NODE_INIT(struct country
, cnty
);
266 NODE_SET_NAME(cnty
, per_cnt
);
267 /* alloc mem for child list */
268 cnty
->child
= STRUCT_INIT(struct list_head
);
269 INIT_LIST_HEAD(cnty
->child
);
271 cnty
->dir
= STRUCT_INIT(struct list_head
);
272 INIT_LIST_HEAD(cnty
->dir
);
273 list_add_tail(&(cnty
->list
), cnty_list
);
277 /* add the person to company's per_list */
278 list_add_tail(&(per
->list
), com_cur
->child
);
279 LIST_RESORT(com_cur
->child
, &(per
->list
), struct person
, list
);
281 /* get mail from author info */
282 if (mail_from_per(&mail_name
, per_name
) < 0)
284 /* get person's name */
285 if (name_from_per(&name
, per_name
) < 0)
287 /* lookup person in global per list */
288 list_for_each_entry(per_current
, per_list
, list
)
289 if (strcasestr(per_current
->name
, mail_name
))
291 else if ((g_warning
== SELECT
) &&
292 strcasestr(per_current
->name
, name
)) {
293 char *mail_from
= NULL
, *mail_to
= NULL
;
294 mail_from_per(&mail_from
, per_current
->name
);
295 mail_from_per(&mail_to
, per_name
);
297 "WARNING: %s and %s might same person.\n",
298 per_current
->name
, per_name
);
299 fprintf(stderr
, "Patch number is %d.\n",per_current
->cnt
);
301 "Suggestion: CONV_PER(\"%s\", \"%s\", NULL),\n",
306 if (&per_current
->list
== per_list
) {
307 /* before using the pointer again, set it to NULL */
309 NODE_INIT(struct person
, per
);
310 NODE_SET_NAME(per
, per_name
);
311 NODE_SET_CNT(per
, per_cnt
);
312 per
->parent
= com_cur
;
314 per
->chgline
+= chgline
;
316 /* add the person to nation's per_list */
317 list_add_tail(&(per
->cnt_list
), cnty
->child
);
318 LIST_RESORT(cnty
->child
, &(per
->cnt_list
), struct person
, cnt_list
);
319 /* update the nation list */
321 cnty
->chgline
+= chgline
;
322 update_cnty_dir(cnty
, dir_list
);
323 LIST_RESORT(cnty_list
, &(cnty
->list
), struct country
, list
);
324 /* add the person to global per_list */
325 list_add_tail(&(per
->list
), per_list
);
326 LIST_RESORT(per_list
, &(per
->list
), struct person
, list
);
328 update_per(per_current
, per_list
, chgline
, dir_list
);
339 int new_com(struct list_head
*com_list
, struct list_head
*per_list
,
340 char *com_name
, char *per_name
, struct list_head
*dir_list
,
341 unsigned long long int chgline
)
344 struct directory
*dir_current
, *dir
;
346 /* create a new company node */
347 NODE_INIT(struct company
, com
);
348 NODE_SET_NAME(com
, com_name
);
349 /* alloc mem for child list */
350 com
->child
= STRUCT_INIT(struct list_head
);
351 INIT_LIST_HEAD(com
->child
);
352 list_add_tail(&(com
->list
), com_list
);
354 new_per(com
, per_list
, per_name
, chgline
, dir_list
);
356 /* add directory distribute infor */
357 com
->dir
= STRUCT_INIT(struct list_head
);
358 INIT_LIST_HEAD(com
->dir
);
359 if (!list_empty(dir_list
)) {
360 list_for_each_entry(dir_current
, dir_list
, list
) {
361 NODE_INIT(struct directory
, dir
);
362 NODE_SET_NAME(dir
, dir_current
->name
);
364 list_add_tail(&(dir
->list
), com
->dir
);
368 /* update the company list */
370 com
->chgline
+= chgline
;
371 LIST_RESORT(com_list
, &(com
->list
), struct company
, list
);
376 int update_com(struct company
*com_cur
, struct list_head
*com_list
,
377 struct list_head
*per_list
, char *per_name
,
378 struct list_head
*dir_list
, unsigned long long int chgline
)
380 struct person
*per_current
;
381 char *mail_name
= NULL
;
382 struct directory
*dir_current
, *dir
, *dir_current2
;
384 /* get mail from person's name */
385 if (mail_from_per(&mail_name
, per_name
) < 0)
387 /* search for this person in com's child */
388 list_for_each_entry(per_current
, com_cur
->child
, list
)
389 if (strcasestr(per_current
->name
, mail_name
))
391 if (&per_current
->list
== com_cur
->child
) {
392 /* the person is new, we add it to list */
393 if (new_per(com_cur
, per_list
, per_name
, chgline
, dir_list
))
396 /* the person is exist, we update the info of person and com */
397 update_child(per_current
, chgline
);
398 /* find the person in global per list and update */
399 list_for_each_entry(per_current
, per_list
, list
)
400 if (strcasestr(per_current
->name
, mail_name
))
402 if (&per_current
->list
== per_list
)
405 update_per(per_current
, per_list
, chgline
, dir_list
);
408 if (list_empty(dir_list
))
411 /* update directory distribute infor */
412 list_for_each_entry(dir_current
, dir_list
, list
) {
413 list_for_each_entry(dir_current2
, com_cur
->dir
, list
)
414 if (strcasestr(dir_current2
->name
, dir_current
->name
))
416 if (&dir_current2
->list
== com_cur
->dir
) {
418 NODE_INIT(struct directory
, dir
);
419 NODE_SET_NAME(dir
, dir_current
->name
);
421 list_add_tail(&(dir
->list
), com_cur
->dir
);
423 struct list_head
*cur_dir_list
= &(dir_current2
->list
);
425 LIST_RESORT(com_cur
->dir
, cur_dir_list
, struct directory
, list
);
430 /* update the person's company info */
432 com_cur
->chgline
+= chgline
;
433 LIST_RESORT(com_list
, &(com_cur
->list
), struct company
, list
);