1 /* Usage: cat /path/to/file.log | ./irssistats channel maintainer language theme > /path/to/file.html */
10 #define MAXNICKLENGTH 50
11 #define MAXLINELENGTH 2000
12 #define MAXQUOTELENGTH 100
17 #define MINWORDLENGTH 5
21 #define URL "http://royale.zerezo.com/programmation/irssistats/"
26 char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and abbreviation */
28 { /* English language */
30 { "HEADER", "Statistics for #%s by %s" },
31 { "LEGEND", "Legend" },
32 { "LASTDAYS", "Lastdays statistics" },
33 { "TOPHOURS", "Hourly statistics" },
34 { "TOPUSERS", "Most active people" },
35 { "OTHERS", "There are %d left not ranked..." },
36 { "NBLINES", "lines" },
38 { "AVGLETTERS", "letters/lines" },
40 { "QUOTE", "random message" },
41 { "RANDTOPICS", "Some topics" },
42 { "CHANGEDBY", "changed by" },
43 { "NEWTOPIC", "new topic" },
44 { "RANDURLS", "Some URLs" },
45 { "POSTEDBY", "posted by" },
46 { "POSTEDURL", "URL" },
47 { "TOPWORDS", "Most used words" },
49 { "OCCURRENCES", "occurrences" },
50 { "TIME", "%d lines parsed in %d seconds" },
51 { "FOOTER", "Statistics generated by" }
53 { /* French language */
55 { "HEADER", "Statistiques de #%s par %s" },
56 { "LEGEND", "Légende" },
57 { "LASTDAYS", "Statistiques des derniers jours" },
58 { "TOPHOURS", "Statistiques horaires" },
59 { "TOPUSERS", "Personnes les plus actives" },
60 { "OTHERS", "Il reste %d personnes non classées..." },
61 { "NBLINES", "lignes" },
63 { "AVGLETTERS", "lettres/lignes" },
64 { "HOURS", "heures" },
65 { "QUOTE", "message aléatoire" },
66 { "RANDTOPICS", "Quelques topics" },
67 { "CHANGEDBY", "changé par" },
68 { "NEWTOPIC", "nouveau topic" },
69 { "RANDURLS", "Quelques URLs" },
70 { "POSTEDBY", "postée par" },
71 { "POSTEDURL", "URL" },
72 { "TOPWORDS", "Mots les plus utilisés" },
74 { "OCCURRENCES", "occurrences" },
75 { "TIME", "%d lignes traitées en %d secondes" },
76 { "FOOTER", "Statistiques générées par" }
85 for (i=1;i<=NBKEYS;i++) if (strcmp(key,keys[language][i][0])==0) return(keys[language][i][1]);
86 fprintf(stderr,"unknown language key: %s\n",key);
93 char *colors[NBTHEMES][NBCOLORS+1][2]= /* first key used for theme name/description and abbreviation */
96 { "White background", "default" },
97 { "BGCOLOR", "#FFFFFF" },
98 { "TEXT", "#000000" },
99 { "LINK", "#0000EE" },
100 { "VLINK", "#551A8B" },
101 { "ALINK", "#FF0000" },
102 { "TITLE1", "#000000" },
103 { "TITLE2", "#000000" },
104 { "BGTABLE", "#EEEEEE" },
105 { "BGTITLE", "#FFEEEE" }
108 { "Black background", "dark" },
109 { "BGCOLOR", "#000000" },
110 { "TEXT", "#FFFFFF" },
111 { "LINK", "#AAAAFF" },
112 { "VLINK", "#CCCCDD" },
113 { "ALINK", "#FFAAAA" },
114 { "TITLE1", "#AAAAFF" },
115 { "TITLE2", "#FFAAAA" },
116 { "BGTABLE", "#225522" },
117 { "BGTITLE", "#552222" }
120 { "Green theme...", "zerezo" },
121 { "BGCOLOR", "#000000" },
122 { "TEXT", "#FFFFFF" },
123 { "LINK", "#14F024" },
124 { "VLINK", "#0CBA18" },
125 { "ALINK", "#FFFFFF" },
126 { "TITLE1", "#0CBA18" },
127 { "TITLE2", "#84DB8C" },
128 { "BGTABLE", "#085D10" },
129 { "BGTITLE", "#0B810B" }
138 for (i=1;i<=NBCOLORS;i++) if (strcmp(color,colors[theme][i][0])==0) return(colors[theme][i][1]);
139 fprintf(stderr,"unknown theme color: %s\n",color);
150 char nick[MAXNICKLENGTH];
154 char quote[MAXLINELENGTH];
160 char nick[MAXNICKLENGTH];
161 char url[MAXLINELENGTH];
167 char nick[MAXNICKLENGTH];
168 char topic[MAXLINELENGTH];
185 struct letter *next[26];
191 char word[MAXLINELENGTH];
194 #define isletter(c) (((c>='a')&&(c<='z'))||((c>='A')&&(c<='Z')))
195 #define lowercase(c) (((c>='A')&&(c<='Z'))?c-'A'+'a':c)
196 void findwords(char *message)
199 struct letter *pos,*tmp;
202 while (!isletter(*message)) if (*message=='\0') return; else message++;
204 while (isletter(*message))
206 c=lowercase(*message)-'a';
207 if ((*pos).next[(int)c]==NULL)
209 tmp=malloc(sizeof(struct letter));
211 for (i=0;i<26;i++) (*tmp).next[i]=NULL;
212 (*pos).next[(int)c]=tmp;
214 pos=(*pos).next[(int)c];
222 char tempword[MAXLINELENGTH];
223 void bestwords(struct letter pos,int cur)
226 if ((cur>=MINWORDLENGTH)&&(pos.nb>topwords[NBWORDS-1].nb))
228 for (i=0;pos.nb<topwords[i].nb;i++);
229 for (j=NBWORDS-1;j>i;j--)
231 topwords[j].nb=topwords[j-1].nb;
232 strcpy(topwords[j].word,topwords[j-1].word);
234 topwords[i].nb=pos.nb;
235 strcpy(topwords[i].word,tempword);
237 for (i=0;i<26;i++) if (pos.next[i]!=NULL)
240 bestwords(*(pos.next[i]),cur+1);
245 void unhtml(char *string) /* replace < and > by { and } */
247 while (*string!='\0')
249 if (*string=='<') *string='{';
250 if (*string=='>') *string='}';
256 int dichotomic(char *nick)
258 int i,j,start=0,end=nbusers-1,middle;
261 middle=(start+end)/2;
262 if (strcmp(nick,users[middle].nick)>0) start=middle+1; else end=middle-1;
264 if (strcmp(nick,users[start].nick)!=0)
267 if (nbusers>=MAXUSERS) { fprintf(stderr,"too many users\n"); exit(1); }
268 for (i=nbusers-1;i>start;i--)
270 strcpy(users[i].nick,users[i-1].nick);
271 users[i].lines=users[i-1].lines;
272 users[i].letters=users[i-1].letters;
273 for (j=0;j<4;j++) users[i].hours[j]=users[i-1].hours[j];
274 strcpy(users[i].quote,users[i-1].quote);
276 strcpy(users[start].nick,nick);
277 users[start].lines=0;
278 users[start].letters=0;
279 for (j=0;j<4;j++) users[start].hours[j]=0;
280 users[start].quote[0]='\0';
285 int main(int argc,char *argv[])
294 char line[MAXLINELENGTH];
299 fprintf(stderr,"Usage: cat /path/to/file.log | ./irssistats channel maintainer language theme > /path/to/file.html\n\n");
300 fprintf(stderr,"Supported languages :\n");
301 for (i=0;i<NBLANGUAGES;i++) fprintf(stderr,"%s = %s\n",keys[i][0][1],keys[i][0][0]);
302 fprintf(stderr,"\nSupported themes :\n");
303 for (i=0;i<NBTHEMES;i++) fprintf(stderr,"%s = %s\n",colors[i][0][1],colors[i][0][0]);
308 for (i=0;i<NBLANGUAGES;i++) if (strcmp(argv[3],keys[i][0][1])==0) { language=i; break; }
311 fprintf(stderr,"Invalid language : %s\n",argv[3]);
314 for (i=0;i<NBTHEMES;i++) if (strcmp(argv[4],colors[i][0][1])==0) { theme=i; break; }
317 fprintf(stderr,"Invalid theme : %s\n",argv[4]);
323 srand(debut=time(NULL));
324 fprintf(stderr,"working:");
329 if (pos>=MAXLINELENGTH) { fprintf(stderr,"line too long\n"); exit(1); }
333 if (totallines%10000==0) { fprintf(stderr,"."); fflush(stdout); }
334 if (strncmp("--- Day changed",line,15)==0) /* --- Day changed Wed May 01 2002 */
338 lastdays[i].lines=lastdays[i-1].lines;
339 for (j=0;j<4;j++) lastdays[i].hours[j]=lastdays[i-1].hours[j];
342 for (j=0;j<4;j++) lastdays[0].hours[j]=0;
345 else if (strncmp("-!-",&line[6],3)==0) /* 00:00 -!- Nick changed the topic of #channel to: new topic */
347 for (i=10;line[i]!=' ';i++);
353 if (strncmp("changed the topic of",message,20)==0)
355 for (i=21;message[i]!=':';i++);
356 message=&message[i+2];
359 if ((nbtopics<=5) || (rand()%nbtopics==0))
363 strcpy(topics[i].nick,topics[i-1].nick);
364 strcpy(topics[i].topic,topics[i-1].topic);
366 strcpy(topics[0].nick,nick);
367 strcpy(topics[0].topic,message);
371 else if ((line[6]=='<') || (line[7]=='*'))
375 if (line[7]=='*') /* 00:00 * Nick the message */
377 for (i=9;line[i]!=' ';i++);
381 else if (line[7]=='>') /* 00:00 <>>>?Nick<<<> the personal message */
383 for (i=11;line[i]!='<';i++);
387 else /* 00:00 <?Nick> the message */
389 for (i=8;line[i]!='>';i++);
399 users[i].letters+=strlen(message);
400 users[i].hours[hour/6]++;
402 lastdays[0].hours[hour/6]++;
405 if (rand()%users[i].lines==0) strncpy(users[i].quote,message,MAXQUOTELENGTH);
406 if (strncmp("http://",message,7)==0)
408 for (i=0;(message[i]!=' ') && (i<strlen(message));i++);
411 if ((nburls<=5) || (rand()%nburls==0))
415 strcpy(urls[i].nick,urls[i-1].nick);
416 strcpy(urls[i].url,urls[i-1].url);
418 strcpy(urls[0].nick,nick);
419 strcpy(urls[0].url,message);
427 fprintf(stderr,"done\n");
434 printf("<!-- Generated by irssistats %s : %s -->\n\n",VERSION,URL);
435 printf("<html>\n\n<head>\n<base target=\"_blank\">\n<title>");
436 printf(L("HEADER"),channel,maintainer);
437 printf("</title>\n</head>\n\n");
438 printf("<body bgcolor=\"%s\" text=\"%s\" link=\"%s\" vlink=\"%s\" alink=\"%s\">\n\n<center>\n\n<font color=\"%s\"><h1>",T("BGCOLOR"),T("TEXT"),T("LINK"),T("VLINK"),T("ALINK"),T("TITLE1"));
439 printf(L("HEADER"),channel,maintainer);
440 printf("</h1></font>\n%s<br>\n<br><br>\n\n",ctime(&debut));
443 printf("<font color=\"%s\"><h3>%s</h3></font>\n<table bgcolor=%s>\n<tr>\n",T("TITLE2"),L("LEGEND"),T("BGTABLE"));
444 for (i=0;i<4;i++) printf("<td><img src=\"h%d.png\" width=\"40\" height=\"15\"></td><td> : %s %d-%d </td><td width=\"10\"></td>\n",i+1,L("HOURS"),i*6,i*6+5);
445 printf("</tr>\n</table>\n<br><br>\n\n");
448 printf("<font color=\"%s\"><h3>%s</h3></font>\n<table>\n<tr>\n",T("TITLE2"),L("LASTDAYS"));
450 for (i=30;i>=0;i--) if (lastdays[i].lines>max) max=lastdays[i].lines;
453 printf("<td width=\"15\" align=\"center\" valign=\"bottom\"><font size=\"-2\">%d</font><br>",lastdays[i].lines);
454 for (j=0;j<4;j++) if (lastdays[i].hours[j]!=0) printf("<img src=\"v%d.png\" width=\"15\" height=\"%d\"><br>",j+1,150*lastdays[i].hours[j]/max);
457 printf("</tr>\n<tr>\n");
459 printf("<td align=\"center\" valign=\"center\" bgcolor=\"%s\">%d</td>\n",T("BGTABLE"),i);
460 printf("</tr>\n</table>\n<br><br>\n\n");
463 printf("<font color=\"%s\"><h3>%s</h3></font>\n<table>\n<tr>\n",T("TITLE2"),L("TOPHOURS"));
465 for (i=0;i<24;i++) if (hours[i]>max) max=hours[i];
468 printf("<td width=\"15\" align=\"center\" valign=\"bottom\"><font size=\"-2\">%.1f%%</font><br>",lines!=0?(float)100*hours[i]/lines:0);
469 if (hours[i]!=0) printf("<img src=\"v%d.png\" width=\"15\" height=\"%d\"><br>",i/6+1,150*hours[i]/max);
472 printf("</tr>\n<tr>\n");
474 printf("<td align=\"center\" valign=\"center\" bgcolor=\"%s\">%d</td>\n",T("BGTABLE"),i);
475 printf("</tr>\n</table>\n<br><br>\n\n");
478 printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("TOPUSERS"));
479 printf("<table>\n<tr><td></td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\" colspan=\"2\">%s</td><td bgcolor=\"%s\">%s</td>\n",T("BGTITLE"),L("NICK"),T("BGTITLE"),L("NBLINES"),T("BGTITLE"),L("HOURS"),T("BGTITLE"),L("AVGLETTERS"),T("BGTITLE"),L("QUOTE"));
480 for (i=1;i<=NBUSERS;i++)
484 for (j=0;j<nbusers;j++) if (users[j].lines>max) max=users[user=j].lines;
487 printf("<tr><td bgcolor=\"%s\" align=\"right\">%d</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%d</td><td bgcolor=\"%s\">",T("BGTABLE"),i,T("BGTABLE"),users[user].nick,T("BGTABLE"),users[user].lines,T("BGTABLE"));
488 for (j=0;j<4;j++) if (users[user].hours[j]!=0) printf("<img src=\"h%d.png\" width=\"%d\" height=\"15\">",j+1,100*users[user].hours[j]/users[user].lines);
489 printf("</td><td bgcolor=\"%s\">%d</td><td bgcolor=\"%s\"><img src=\"hm.png\" width=\"%d\" height=\"15\"></td><td bgcolor=\"%s\">\"%s\"</td></tr>\n",T("BGTABLE"),users[user].letters/users[user].lines,T("BGTABLE"),users[user].letters/users[user].lines,T("BGTABLE"),users[user].quote);
490 users[user].lines=-1;
493 printf("</table>\n");
497 printf(L("OTHERS"),nbusers-50);
500 printf("<br><br>\n\n");
503 printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("RANDTOPICS"));
504 printf("<table>\n<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("CHANGEDBY"),T("BGTITLE"),L("NEWTOPIC"));
505 for (i=nbtopics<NBTOPICS?nbtopics-1:NBTOPICS-1;i>=0;i--)
506 printf("<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">\"%s\"</td></tr>\n",T("BGTABLE"),topics[i].nick,T("BGTABLE"),topics[i].topic);
507 printf("</table>\n<br><br>\n\n");
510 printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("RANDURLS"));
511 printf("<table>\n<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("POSTEDBY"),T("BGTITLE"),L("POSTEDURL"));
512 for (i=nburls<NBURLS?nburls-1:NBURLS-1;i>=0;i--)
513 printf("<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">\"<a href=\"%s\">%s</a>\"</td></tr>\n",T("BGTABLE"),urls[i].nick,T("BGTABLE"),urls[i].url,urls[i].url);
514 printf("</table>\n<br><br>\n\n");
517 printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("TOPWORDS"));
518 printf("<table>\n<tr><td></td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("WORD"),T("BGTITLE"),L("OCCURRENCES"));
519 for (i=0;i<NBWORDS;i++)
520 if (topwords[i].nb!=0) printf("<tr><td bgcolor=\"%s\" align=\"right\">%d</td><td bgcolor=\"%s\">\"%s\"</td><td bgcolor=\"%s\">%d</td></tr>\n",T("BGTABLE"),i+1,T("BGTABLE"),topwords[i].word,T("BGTABLE"),topwords[i].nb);
521 printf("</table>\n<br><br>\n\n");
524 printf(L("TIME"),totallines,(int)(time(NULL)-debut));
525 printf("<br>\n%s <a href=\"%s\">irssistats %s</a>",L("FOOTER"),URL,VERSION);
526 printf("\n\n</center>\n\n</body>\n\n</html>\n");