-/* Usage: cat /path/to/file.log | ./irssistats channel maintainer language theme > /path/to/file.html */
+/* Usage: cat /path/to/file.log | ./irssistats \#channel maintainer language theme [nickfile] > /path/to/file.html */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
+#include <regex.h>
/* Config */
#define MAXUSERS 5000
#define MINWORDLENGTH 5
/* irssistats */
-#define VERSION "0.3"
+#define VERSION "0.41"
#define URL "http://royale.zerezo.com/programmation/irssistats/"
/* Counters */
char *counters[NBCOUNTERS]={"C_SMILE","C_FROWN","C_EXCLAM","C_QUESTION","C_ME","C_TOPIC","C_MODE","C_KICK","C_KICKED","C_URL","C_JOIN","C_NICK","C_MONOLOGUE"};
/* Languages */
-#define NBLANGUAGES 2
+#define NBLANGUAGES 5
#define NBKEYS 38
char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and abbreviation */
{
{ /* English language */
{ "English", "en" },
- { "HEADER", "Statistics for #%s by %s" },
+ { "HEADER", "Statistics for %s by %s" },
{ "LEGEND", "Legend" },
{ "LASTDAYS", "Lastdays statistics" },
{ "TOPHOURS", "Hourly statistics" },
{ "OCCURRENCES", "occurrences" },
{ "BIGNUMBERS", "Some big numbers..." },
{ "NUMBERS", "numbers" },
- { "TIME", "%d lines parsed in %d seconds" },
+ { "TIME", "%d lines (%d days) parsed in %d seconds" },
{ "FOOTER", "Statistics generated by" },
{ "C_SMILE", "is often happy :)" },
{ "C_FROWN", "is often sad :(" },
},
{ /* French language */
{ "Français", "fr" },
- { "HEADER", "Statistiques de #%s par %s" },
+ { "HEADER", "Statistiques de %s par %s" },
{ "LEGEND", "Légende" },
{ "LASTDAYS", "Statistiques des derniers jours" },
{ "TOPHOURS", "Statistiques horaires" },
{ "OCCURRENCES", "occurrences" },
{ "BIGNUMBERS", "Quelques grands nombres..." },
{ "NUMBERS", "nombres" },
- { "TIME", "%d lignes traitées en %d secondes" },
+ { "TIME", "%d lignes (%d jours) traitées en %d secondes" },
{ "FOOTER", "Statistiques générées par" },
{ "C_SMILE", "est souvent heureux :)" },
{ "C_FROWN", "est souvent triste :(" },
{ "C_JOIN", "ne sait pas s'il doit rester ou partir" },
{ "C_NICK", "change souvent de nick" },
{ "C_MONOLOGUE", "parle beaucoup de monologues" }
+ },
+ { /* German language */
+ /* contributed by Valentin Gelhorn <valentin.gelhorn@web.de> */
+ { "German", "de" },
+ { "HEADER", "Statistiken für %s von %s" },
+ { "LEGEND", "Legende" },
+ { "LASTDAYS", "Statistik der letzten Tage" },
+ { "TOPHOURS", "Stündliche Statistik" },
+ { "TOPUSERS", "Die aktivsten Personen" },
+ { "OTHERS", "Es bleiben noch %d uneingetragene" },
+ { "NBLINES", "Zeilen" },
+ { "NICK", "Nick" },
+ { "AVGLETTERS", "Buchstaben/Zeile" },
+ { "HOURS", "Stunden" },
+ { "QUOTE", "Zufällig ausgewaehlte Zitate" },
+ { "TOPUSERSTIME", "Die aktivsten Personen zur bestimmten Tageszeit" },
+ { "RANDTOPICS", "Ein paar Topics" },
+ { "CHANGEDBY", "Gesetzt von" },
+ { "NEWTOPIC", "Neues topic" },
+ { "RANDURLS", "Ein paar URLs" },
+ { "POSTEDBY", "Geschrieben von" },
+ { "POSTEDURL", "URL" },
+ { "TOPWORDS", "Am häufigsten benutze Wörter" },
+ { "WORD", "Wort" },
+ { "OCCURRENCES", "Vorkommen" },
+ { "BIGNUMBERS", "Ein paar grosse Zahlen" },
+ { "NUMBERS", "Zahlen" },
+ { "TIME", "%d Zeilen (%d Tage) analysiert in %d Sekunden" },
+ { "FOOTER", "Statistiken wurden erstellt von" },
+ { "C_SMILE", "ist oft glüklich :)" },
+ { "C_FROWN", "ist oft traurig :(" },
+ { "C_EXCLAM", "schreit oft !" },
+ { "C_QUESTION", "stellt viele Fragen ?" },
+ { "C_ME", "mag /me'en" },
+ { "C_TOPIC", "aendert oft das Topico" },
+ { "C_MODE", "aendert oft die Modes" },
+ { "C_KICK", "mag /kick'en" },
+ { "C_KICKED", "wird oft gekickt"},
+ { "C_URL", "schreibt viele URLs"},
+ { "C_JOIN", "kann sich nicht entscheiden ob er bleiben oder gehen soll" },
+ { "C_NICK", "ändert oft seinen Nick" },
+ { "C_MONOLOGUE", "spricht oft Monologe" }
+ },
+ { /* Spanish language */
+ /* contributed by Alex <ainaker@gmx.net> */
+ { "Spanish", "es" },
+ { "HEADER", "Estadísticas de %s por %s" },
+ { "LEGEND", "Leyenda" },
+ { "LASTDAYS", "Estadísticas de los últimos días" },
+ { "TOPHOURS", "Estadísticas por horas" },
+ { "TOPUSERS", "Los que más escriben" },
+ { "OTHERS", "Hay %d más que no llegaron..." },
+ { "NBLINES", "líneas" },
+ { "NICK", "nick" },
+ { "AVGLETTERS", "letras por línea" },
+ { "HOURS", "horas" },
+ { "QUOTE", "Frase aleatoria" },
+ { "TOPUSERSTIME", "Los que más escriben según la hora" },
+ { "RANDTOPICS", "Algunos topics" },
+ { "CHANGEDBY", "Puestos por" },
+ { "NEWTOPIC", "topic" },
+ { "RANDURLS", "Algunas URLs" },
+ { "POSTEDBY", "puestas por" },
+ { "POSTEDURL", "URL" },
+ { "TOPWORDS", "Palabras más usadas" },
+ { "WORD", "Palabra" },
+ { "OCCURRENCES", "Frecuencia" },
+ { "BIGNUMBERS", "Algunos datos..." },
+ { "NUMBERS", "Número de veces" },
+ { "TIME", "%d lineas (%d días) procesadas en %d segundos" },
+ { "FOOTER", "Estadísticas generadas por" },
+ { "C_SMILE", "Suele estar felíz :)" },
+ { "C_FROWN", "Suele estar triste :(" },
+ { "C_EXCLAM", "Grita mucho !" },
+ { "C_QUESTION", "Hace muchas preguntas ?" },
+ { "C_ME", "Abusa del comando /me" },
+ { "C_TOPIC", "Suele cambiar el topic" },
+ { "C_MODE", "Cambia a veces los modos del canal" },
+ { "C_KICK", "Le gusta patear" },
+ { "C_KICKED", "Es pateado con frecuencia" },
+ { "C_URL", "Pone muchas URLs" },
+ { "C_JOIN", "No sabe si irse o quedarse" },
+ { "C_NICK", "Cambia mucho de nick" },
+ { "C_MONOLOGUE", "Habla solo" }
+ },
+ { /* Polish language */
+ /* contributed by Piotr Jarmuz <coreupper@yahoo.com> */
+ { "Polish", "pl" },
+ { "HEADER", "Statystyki dla %s przez %s" },
+ { "LEGEND", "Legenda" },
+ { "LASTDAYS", "Statystyki z ostatnich dni" },
+ { "TOPHOURS", "Statystyki godzinne" },
+ { "TOPUSERS", "Najaktywniejsi ludzie" },
+ { "OTHERS", "Zostalo jeszcze %d nie sklasyfikowanych..." },
+ { "NBLINES", "linie" },
+ { "NICK", "nick" },
+ { "AVGLETTERS", "litery/linie" },
+ { "HOURS", "godziny" },
+ { "QUOTE", "przypadkowa wiadomosc" },
+ { "TOPUSERSTIME", "Najaktywniejsi ludzie wedlug czasu dnia" },
+ { "RANDTOPICS", "Pare tematow" },
+ { "CHANGEDBY", "zmienione przez" },
+ { "NEWTOPIC", "nowy temat" },
+ { "RANDURLS", "Pare URL-i" },
+ { "POSTEDBY", "wyslane przez" },
+ { "POSTEDURL", "URL" },
+ { "TOPWORDS", "Najczestsze slowa" },
+ { "WORD", "slowo" },
+ { "OCCURRENCES", "wystapienia" },
+ { "BIGNUMBERS", "Pare wielkich liczb..." },
+ { "NUMBERS", "liczby" },
+ { "TIME", "%d linii (%d dni) sparsowanych w %d sekund" },
+ { "FOOTER", "Statystyki wygenerowane przez" },
+ { "C_SMILE", "jest czesto szczesliwy :)" },
+ { "C_FROWN", "jest czesto smutny :(" },
+ { "C_EXCLAM", "duzo krzyczy !" },
+ { "C_QUESTION", "zadaje duzo pytan ?" },
+ { "C_ME", "lubi /mnie polecenie" },
+ { "C_TOPIC", "czesto zmienia temat" },
+ { "C_MODE", "czesto zmienia tryb" },
+ { "C_KICK", "lubi /kopac" },
+ { "C_KICKED", "czesto go wykopuja" },
+ { "C_URL", "wysyla duzo URL-i" },
+ { "C_JOIN", "nie wie czy zostac czy wyjsc" },
+ { "C_NICK", "czesto zmienia swojego nicka" },
+ { "C_MONOLOGUE", "czesto mowi monologiem" }
}
};
char *channel;
char *maintainer;
-struct
+struct
{
char nick[MAXNICKLENGTH];
int lines;
while (isletter(*message))
{
c=lowercase(*message)-'a';
- if ((*pos).next[(int)c]==NULL)
+ if (pos->next[(int)c]==NULL)
{
tmp=malloc(sizeof(struct letter));
- (*tmp).nb=0;
- for (i=0;i<26;i++) (*tmp).next[i]=NULL;
- (*pos).next[(int)c]=tmp;
+ tmp->nb=0;
+ for (i=0;i<26;i++) tmp->next[i]=NULL;
+ pos->next[(int)c]=tmp;
}
- pos=(*pos).next[(int)c];
+ pos=pos->next[(int)c];
message++;
}
- (*pos).nb++;
+ pos->nb++;
}
return;
}
int main(int argc,char *argv[])
{
int i,j,k;
- int max,user,hour;
+ int max,user,temp,hour;
int mononick,monolines;
time_t debut;
int totallines=0;
char c;
char *nick,*message;
char line[MAXLINELENGTH];
+ FILE *fic;
+ regex_t preg;
/*** INIT ***/
- if (argc!=5)
+ if ((argc<5) || (argc>6))
{
- fprintf(stderr,"Usage: cat /path/to/file.log | ./irssistats channel maintainer language theme > /path/to/file.html\n\n");
+ fprintf(stderr,"Usage: cat /path/to/file.log | ./irssistats \\#channel maintainer language theme [nickfile] > /path/to/file.html\n\n");
fprintf(stderr,"Version :\nirssistats %s\n\n",VERSION);
fprintf(stderr,"Supported languages :\n");
for (i=0;i<NBLANGUAGES;i++) fprintf(stderr,"%s = %s\n",keys[i][0][1],keys[i][0][0]);
for (j=0;j<4;j++) lastdays[0].hours[j]=0;
days++;
}
- else if (strncmp("-!- mode/",&line[6],9)==0) /* 00:00 -!- mode/#channel [...] by Nick(, Nick2, Nick3...) */
+ else if (strncmp("-!- mode/",&line[6],9)==0) /* 00:00 -!- mode/#channel [...] by (Nick, Nick2, )Nick3 */
{
- for (i=15;(line[i]!=']')||(line[i+1]!=' ');i++);
- nick=&line[i+5];
- for (i=0;(nick[i]!='\0')&&(nick[i]!=',');i++);
- nick[i]='\0';
+ for (i=strlen(line);line[i]!=' ';i--);
+ nick=&line[i+1];
users[dichotomic(nick)].counters[D_MODE]++;
}
else if (strncmp("-!-",&line[6],3)==0) /* 00:00 -!- Nick something... */
for (i=21;message[i]!=':';i++);
message=&message[i+2];
nbtopics++;
- if ((nbtopics<=5) || (rand()%nbtopics==0))
+ if ((nbtopics<=NBTOPICS) || (rand()%(nbtopics/NBTOPICS)==0))
{
- for (i=4;i>0;i--)
- {
- strcpy(topics[i].nick,topics[i-1].nick);
- strcpy(topics[i].topic,topics[i-1].topic);
- }
- strcpy(topics[0].nick,nick);
- strncpy(topics[0].topic,message,MAXQUOTELENGTH);
+ temp=nbtopics<=NBTOPICS?nbtopics-1:rand()%NBTOPICS;
+ strcpy(topics[temp].nick,nick);
+ strncpy(topics[temp].topic,message,MAXQUOTELENGTH);
}
}
else if (strncmp("was kicked from",message,15)==0) /* 00:00 -!- Nick was kicked from #channel by Nick [Reason] */
message=&line[i+1];
}
else if (line[7]=='>') /* 00:00 <>>>?Nick<<<> the personal message */
+ /* 00:00 <>>?Nick<<> the personal message */
{
- for (i=11;line[i]!='<';i++);
- nick=&line[11];
+ for (i=10;line[i]!='<';i++);
+ nick=&line[10];
+ if (line[9]=='>') nick++;
message=&line[i+5];
}
else /* 00:00 <?Nick> the message */
for (i=0;(message[i]!=' ') && (i<strlen(message));i++);
message[i]='\0';
nburls++;
- if ((nburls<=5) || (rand()%nburls==0))
+ if ((nburls<=NBURLS) || (rand()%(nburls/NBURLS)==0))
{
- for (i=4;i>0;i--)
- {
- strcpy(urls[i].nick,urls[i-1].nick);
- strcpy(urls[i].url,urls[i-1].url);
- strcpy(urls[i].shorturl,urls[i-1].shorturl);
- }
- strcpy(urls[0].nick,nick);
- strcpy(urls[0].url,message);
- strncpy(urls[0].shorturl,message,MAXQUOTELENGTH);
+ temp=nburls<=NBURLS?nburls-1:rand()%NBURLS;
+ strcpy(urls[temp].nick,nick);
+ strcpy(urls[temp].url,message);
+ strncpy(urls[temp].shorturl,message,MAXQUOTELENGTH);
}
}
findwords(message);
bestwords(words,0);
+ /*** ALIAS ***/
+
+ if (argc==6)
+ {
+ if ((fic=fopen(argv[5],"rt"))==NULL) { fprintf(stderr,"can't open nick file\n"); exit(1); }
+ while (fscanf(fic,"%s",line)==1)
+ {
+ user=dichotomic(line);
+ fscanf(fic,"%s",line);
+ if (regcomp(&preg,line,0)!=0) { fprintf(stderr,"error in nick file"); exit(1); }
+ temp=users[user].lines;
+ for (i=0;i<nbusers;i++) if ((i!=user) && (regexec(&preg,users[i].nick,0,0,0)==0) && (users[i].lines>=0))
+ {
+ if (users[i].lines>temp) /* for nick alias, keep the random quote of the most used nick */
+ {
+ strcpy(users[user].quote,users[i].quote);
+ temp=users[i].lines;
+ }
+ users[user].lines+=users[i].lines;
+ users[user].letters+=users[i].letters;
+ for (j=0;j<4;j++) users[user].hours[j]+=users[i].hours[j];
+ for (j=0;j<NBCOUNTERS;j++) users[user].counters[j]+=users[i].counters[j];
+ /* "remove" old user */
+ users[i].lines=-1;
+ users[i].letters=-1;
+ for (j=0;j<4;j++) users[i].hours[j]=-1;
+ for (j=0;j<NBCOUNTERS;j++) users[i].counters[j]=-1;
+ }
+ regfree(&preg);
+ }
+ fclose(fic);
+ /* "remove" the ignored nicks */
+ i=dichotomic("<NULL>");
+ users[i].lines=-1;
+ users[i].letters=-1;
+ for (j=0;j<4;j++) users[i].hours[j]=-1;
+ for (j=0;j<NBCOUNTERS;j++) users[i].counters[j]=-1;
+ }
+
/*** HTML ***/
/* header */
for (i=1;i<=NBUSERS;i++)
{
user=-1;
- max=-1;
+ max=0;
for (j=0;j<nbusers;j++) if (users[j].lines>max) max=users[user=j].lines;
if (user!=-1)
{
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"));
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);
- printf("</td><td bgcolor=\"%s\">%d</td><td bgcolor=\"%s\"><img src=\"hm.png\" width=\"%d\" height=\"15\"></td><td bgcolor=\"%s\">\"",T("BGTABLE"),users[user].letters/users[user].lines,T("BGTABLE"),users[user].letters/users[user].lines,T("BGTABLE"));
+ printf("</td><td bgcolor=\"%s\">%d</td><td bgcolor=\"%s\"><img src=\"hm.png\" width=\"%d\" height=\"15\"></td><td bgcolor=\"%s\">\"",T("BGTABLE"),users[user].lines!=0?users[user].letters/users[user].lines:0,T("BGTABLE"),users[user].lines!=0?users[user].letters/users[user].lines:0,T("BGTABLE"));
printhtml(users[user].quote);
printf("\"</td></tr>\n");
users[user].lines=-1;
}
}
printf("</table>\n");
- if (nbusers>NBUSERS)
+ temp=0;
+ for (i=0;i<=nbusers;i++) if (users[i].lines>=0) temp++;
+ if (temp>0)
{
printf("<br>");
- printf(L("OTHERS"),nbusers-50);
+ printf(L("OTHERS"),temp);
printf("<br>\n");
}
printf("<br><br>\n\n");
for (j=0;j<4;j++)
{
user=-1;
- max=-1;
+ max=0;
for (k=0;k<nbusers;k++) if (users[k].hours[j]>max) max=users[user=k].hours[j];
if (user!=-1)
{
printf("</table>\n<br><br>\n\n");
/* footer */
- printf(L("TIME"),totallines,(int)(time(NULL)-debut));
+ printf(L("TIME"),totallines,days,(int)(time(NULL)-debut));
printf("<br>\n%s <a href=\"%s\">irssistats %s</a>",L("FOOTER"),URL,VERSION);
printf("\n\n</center>\n\n</body>\n\n</html>\n");