#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define BUFFSIZE 3 /* >= 2 */
char *mygetline(FILE *fp) {
static char inbuff[BUFFSIZE];
char *outbuff_malloc, *tmpbuff;
char *p, *r;
int fEOL;
if ((outbuff_malloc = malloc(1)) == NULL) {
return NULL;
}
*outbuff_malloc = '\0';
fEOL = 0;
do {
r = fgets(inbuff, BUFFSIZE, fp);
if (r == NULL)
break;
for (p = inbuff; *p != '\0'; p++)
;
if (*(p - 1) == '\n')
fEOL = 1;
if ((tmpbuff = realloc(outbuff_malloc, strlen(outbuff_malloc) + strlen(inbuff) + 1)) == NULL) {
free(outbuff_malloc);
return NULL;
}
strcat(tmpbuff, inbuff);
outbuff_malloc = tmpbuff;
} while (!fEOL);
if (strlen(outbuff_malloc) > 0) {
for (p = outbuff_malloc; *p != '\0'; p++)
;
if (*(p - 1) == '\n')
*(p - 1) = '\0';
return outbuff_malloc;
}
free(outbuff_malloc);
return NULL;
}
struct node {
void *data;
struct node *left;
struct node *right;
};
void *push(struct node **root, void *data, int (*cmp)(void *, void *)) {
struct node *p;
int c;
if (!*root) {
p = malloc(sizeof(struct node));
p->data = data;
p->left = p->right = NULL;
*root = p;
return data;
}
if ((c = (*cmp)(data, (*root)->data)) != 0) {
if (c < 0) {
return push(&((*root)->left), data, cmp);
} else {
return push(&((*root)->right), data, cmp);
}
}
return (*root)->data;
}
void *pop(struct node **root) {
struct node *p;
void *data;
if (*root == NULL) {
return NULL;
}
if ((*root)->left) {
data = pop(&((*root)->left));
return data;
}
assert((*root)->left == NULL);
p = *root;
data = p->data;
*root = p->right;
free(p);
return data;
}
/*------------------------------------------------------------*/
struct data1 {
int point;
int n;
struct node *groot;
};
int cmp_const1(char *a, char *b) {
return 1;
}
void cut_tsv(char *line, struct node **root) {
int s;
char *p, *q, *col, c;
p = q = line;
do {
c = *p;
if (c == '\t' || c == '\0') {
*p = '\0';
s = strlen(q);
if (s > 0) {
col = malloc(s + 1);
strcpy(col, q);
} else
col = NULL;
push(root, col, (int (*)(void *, void *))cmp_const1);
p++;
q = p;
} else {
p++;
}
} while (c);
}
void usr_analyze_tsv(struct node **root, char **col1, char **col2, int *col3, int *col4, int *col5) {
int i;
char *p;
for (i = 0; i < 5; i++) {
if ((p = pop(root)) != NULL) {
switch (i) {
case 0:
*col1 = p;
break;
case 1:
*col2 = p;
break;
case 2:
*col3 = atoi(p);
free(p);
break;
case 3:
*col4 = atoi(p);
free(p);
break;
case 4:
*col5 = atoi(p);
free(p);
break;
}
} else {
switch (i) {
case 0:
*col1 = NULL;
break;
case 1:
*col2 = NULL;
break;
case 2:
*col3 = -1;
break;
case 3:
*col4 = -1;
break;
case 4:
*col5 = -1;
break;
}
}
}
}
void release_tsv(struct node **root) {
char *p;
while ((p = pop(root)) != NULL)
free(p);
}
int cmp_data1(struct data1 *p, struct data1 *q) {
return p->point - q->point;
}
int cmp_col2(char *p, char *q) {
if (!p || !q)
return 0;
return strcmp(p, q);
}
void analyze(struct node **root, char *line) {
struct node *tsvroot;
struct data1 *p, *q, *r;
char *col1, *col2;
int j, m, e;
tsvroot = NULL;
cut_tsv(line, &tsvroot);
usr_analyze_tsv(&tsvroot, &col1, &col2, &j, &m, &e);
release_tsv(&tsvroot);
free(col1);
if (col2 == NULL || j < 0 || m < 0 || e < 0)
return;
p = malloc(sizeof(struct data1));
if (!p) {
fprintf(stderr, "cannot allocate enough memory.(analyze: struct data1)\n");
exit(-1);
}
p->point = j + m + e;
p->n = 1;
p->groot = NULL;
push(&(p->groot), col2, (int (*)(void *, void *))cmp_const1);
if ((q = push(root, p, (int (*)(void *, void *))cmp_data1)) != p) {
while (r = pop(&(p->groot)))
;
free(p);
(q->n)++;
if (push(&(q->groot), col2, (int (*)(void *, void *))cmp_col2) != col2) {
free(col2);
}
} else {
}
}
void result_output(struct node **root) {
struct data1 *p;
char *q;
int i;
while (p = pop(root)) {
printf("point: %d, n = %d, ", p->point, p->n);
i = 0;
while (q = pop(&(p->groot))) {
free(q);
i++;
}
printf("group: %d\n", i);
free(p);
}
}
int main() {
struct node *root;
char *p;
root = NULL;
while (p = mygetline(stdin)) {
analyze(&root, p);
free(p);
}
result_output(&root);
return 0;
}
/* end */