Git

Antoine Jacquet [Sat, 20 Mar 2004 23:00:00 +0000 (00:00 +0100)]
* no hard user limit anymore (dynamic table size)
* alternate CSS themes
* quarters support in top hours statistics
* words/letters ranking
* top words can be disabled to use less memory
* old polish translation was restored

CHANGELOG [new file with mode: 0644]
README
data/pisg.css
irssistats.c
sample.configfile

diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644 (file)
index 0000000..ecb08b7
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,80 @@
+Change log file for irssistats
+
+version 0.6    (2004-03-21)
+       * no hard user limit anymore (dynamic table size)
+       * alternate CSS themes
+       * quarters support in top hours statistics
+       * words/letters ranking
+       * top words can be disabled to use less memory
+       * old polish translation was restored
+\r
+version 0.51   (2003-12-14)\r
+       * bugfixes and polish language updated (thank you Jakub Jankowski) \r
+       * "CHARSET" is now a language parameter \r
+       * Internet Explorer specific bugfix in themes \r
+\r
+version 0.5    (2003-12-07)\r
+       * configuration file \r
+       * it is now possible to build multiple stats in one run \r
+       * customizable header and footer \r
+       * now produces XHTML with CSS templates as suggested by some users \r
+       * "grayscale" and "pisg" theme were added \r
+       * italian support (thank you Coviello Giuseppe) \r
+       * dutch support and BSD include patch (thank you Jeroen Ubbink) \r
+       * patch nickmode (thank you Philipp Haegi) \r
+\r
+version 0.44   (2003-05-25)\r
+       * finnish support (thank you Antti Huopana) \r
+       * minor updates \r
+\r
+version 0.43   (2002-11-24)\r
+       * manpage was added \r
+       * increased number of users \r
+       * "blue" theme was added \r
+       * improved Makefile \r
+\r
+version 0.42   (2002-11-16)\r
+       * W3C validated HTML \r
+       * better quote selection during nick alias \r
+       * auto refresh (suggested by Charles Blackburn) \r
+\r
+version 0.41   (2002-10-19)\r
+       * polish support (thank you Piotr Jarmuz) \r
+       * you can now ignore some users \r
+       * improved Makefile \r
+       * the # in channel name is not imposed anymore (to support "&channels") \r
+       * number of total days are now displayed \r
+\r
+version 0.4    (2002-10-14)\r
+       * nick alias support using regular expression \r
+       * some code fix \r
+\r
+version 0.32   (2002-09-30)\r
+       * german support (thank you Valentin Gelhorn) \r
+\r
+version 0.31   (2002-09-01)\r
+       * spanish support (thank you Alex) \r
+       * minor code changes \r
+       * bugfix : division by 0 (thank you Qball) \r
+       * better random topics / urls algorithm \r
+\r
+version 0.3    (2002-05-29)\r
+       * top users by time of day \r
+       * some big numbers \r
+       * some new themes \r
+       * increased number of users \r
+       * better HTML output \r
+\r
+version 0.2    (2002-05-16)\r
+       * languages support (currently english and french) \r
+       * themes support \r
+       * most used words \r
+       * now handles personal messages and "/me" \r
+       * parameters on command line \r
+       * some code change \r
+       * faster \r
+       * no more image when 0 lines \r
+       * maximum height for graph is now calculated \r
+\r
+version 0.1    (2002-05-01)\r
+       * initial release
\ No newline at end of file
diff --git a/README b/README
index 3e1adf0..53a1565 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-irssistats 0.51
+irssistats 0.6
 site: http://royale.zerezo.com/irssistats/
 mail: royale@zerezo.com
 
index c306040..e4fb009 100644 (file)
@@ -125,6 +125,7 @@ body {
        padding: 0;
        border: 0;
   font-size: 0;
+       margin: auto;
 }
 
 #irssistats div.h1 {
index 7b5d209..7bb52cf 100644 (file)
@@ -1,4 +1,27 @@
-/* Usage: irssistats [/path/to/file.conf] */
+/*
+ * irssistats version 0.6
+ *
+ * This tool generates IRC stats based on irssi logs.
+ * Usage: irssistats [/path/to/file.conf]
+ *
+ * Copyright (C) 2002-2004  Antoine Jacquet <royale@zerezo.com>
+ * http://royale.zerezo.com/irssistats/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
 
 #include <sys/types.h>
 #include <stdio.h>
@@ -8,7 +31,7 @@
 #include <regex.h>
 
 /* Config */
-#define MAXUSERS 10000
+#define BASEUSERS 1000
 #define MAXNICKLENGTH 50
 #define MAXLINELENGTH 2000
 #define MAXQUOTELENGTH 100
@@ -20,7 +43,7 @@
 #define MINWORDLENGTH 5
 
 /* irssistats */
-#define VERSION "0.51"
+#define VERSION "0.6"
 #define URL "http://royale.zerezo.com/irssistats/"
 
 /* Counters */
@@ -41,7 +64,7 @@
 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 8
+#define NBLANGUAGES 9
 #define NBKEYS 39
 char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and abbreviation */
 {
@@ -216,8 +239,7 @@ char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and ab
     { "C_MONOLOGUE",  "Habla solo" }
   },
   { /* Polish language */
-    /* contributed by Piotr Jarmuz <coreupper@yahoo.com> */
-    /* updated by Jakub Jankowski <shasta@atn.pl> */
+    /* contributed by Jakub Jankowski <shasta@atn.pl> */
     { "Polish",       "pl" },
     { "CHARSET",      "ISO-8859-2" },
     { "HEADER",       "Statystyki dla %s zebrane przez %s" },
@@ -259,6 +281,49 @@ char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and ab
     { "C_NICK",       "czêsto zmienia nick" },
     { "C_MONOLOGUE",  "uwielbia monologi" }
   },
+  { /* Polish language */
+    /* contributed by Piotr Jarmuz <coreupper@yahoo.com> */
+    { "Polish",       "pl-old" },
+    { "CHARSET",      "ISO-8859-1" },
+    { "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" }
+  },
   { /* Finnish language */
     /* contributed by Antti Huopana <ahuopana@ratol.fi> */
     { "Finnish",      "fi" },
@@ -405,25 +470,30 @@ char *L(char *key)
 int debug=1; /* 0 = none ; 1 = normal ; 2 = verbose */
 char channel[MAXLINELENGTH]="set_channel_in_config_file";
 char maintainer[MAXLINELENGTH]="set_maintainer_in_config_file";
-char theme[MAXLINELENGTH]="default";
+char theme[MAXLINELENGTH]="default,blue,dark,grayscale,namour,pisg,zeduel,zerezo";
 int refresh_time=0; /* 0 = disabled */
 int w3c_link=1; /* 0 = disabled */
 char header[MAXLINELENGTH]="none";
 char footer[MAXLINELENGTH]="none";
 int totallines=0;
 time_t debut;
+int top_words=1; /* 0 = disabled */
+int ranking=0; /* 0 = lines ; 1 = words ; 2 = letters */
+int quarter=0; /* 1 = enabled */
 
-struct
+struct user
 {
   char nick[MAXNICKLENGTH];
   int lines;
+  int words;
   int letters;
   int hours[4];
   char quote[MAXQUOTELENGTH+1];
   int counters[NBCOUNTERS];
   int temp;
-} users[MAXUSERS];
+} *users;
 int nbusers=0;
+int maxusers=BASEUSERS;
 
 struct
 {
@@ -447,7 +517,7 @@ struct
 } lastdays[31];
 int days=0;
 
-int hours[24];
+int hours[24*4];
 int lines=0;
 
 struct letter
@@ -464,13 +534,13 @@ struct
 
 #define isletter(c) (((c>='a')&&(c<='z'))||((c>='A')&&(c<='Z')))
 #define lowercase(c) (((c>='A')&&(c<='Z'))?c-'A'+'a':c)
-void findwords(char *message)
+int findwords(char *message)
 {
-  int i,c;
+  int i,c,n=0;
   struct letter *pos,*tmp;
   for (;;)
   {
-    while (!isletter(*message)) if (*message=='\0') return; else message++;
+    while (!isletter(*message)) if (*message=='\0') return n; else message++;
     pos=&words;
     while (isletter(*message))
     {
@@ -491,8 +561,9 @@ void findwords(char *message)
       message++; 
     }
     pos->nb++;
+    n++;
   }
-  return;
+  return n;
 }
 
 char tempword[MAXLINELENGTH];
@@ -556,11 +627,17 @@ int dichotomic(char *nick)
   if (strcmp(nick,users[start].nick)!=0)
   {
     nbusers++;
-    if (nbusers>=MAXUSERS) { fprintf(stderr,"too many users\n"); exit(1); }
+    if (nbusers>=maxusers)
+    {
+      maxusers+=BASEUSERS;
+      if (debug==2) fprintf(stderr,"allocating more users : %d\n",maxusers);
+      if ((users=realloc(users,maxusers*sizeof(struct user)))==NULL) { fprintf(stderr,"too many users : unable to realloc memory\n"); exit(1); }
+    }
     for (i=nbusers-1;i>start;i--)
     {
       strcpy(users[i].nick,users[i-1].nick);
       users[i].lines=users[i-1].lines;
+      users[i].words=users[i-1].words;
       users[i].letters=users[i-1].letters;
       for (j=0;j<4;j++) users[i].hours[j]=users[i-1].hours[j];
       strcpy(users[i].quote,users[i-1].quote);
@@ -569,6 +646,7 @@ int dichotomic(char *nick)
     }
     strcpy(users[start].nick,nick);
     users[start].lines=0;
+    users[start].words=0;
     users[start].letters=0;
     for (j=0;j<4;j++) users[start].hours[j]=0;
     users[start].quote[0]='\0';
@@ -708,11 +786,17 @@ void parse_log(char *logfile)
       }
       j=strlen(message);
       users[i].lines++;
+      if (top_words || ranking==1) users[i].words+=findwords(message);
       users[i].letters+=j;
       users[i].hours[hour/6]++;
       lastdays[0].lines++;
       lastdays[0].hours[hour/6]++;
       lines++;
+      if (quarter)
+      {
+        line[5]='\0';
+        hour=hour*4+atoi(&line[3])/15;
+      }
       hours[hour]++;
       if (message[j-1]=='?') users[i].counters[D_QUESTION]++;
       else if (message[j-1]=='!') users[i].counters[D_EXCLAM]++;
@@ -736,7 +820,6 @@ void parse_log(char *logfile)
           strncpy(urls[temp].shorturl,message,MAXQUOTELENGTH);
         }
       }
-      findwords(message);
     }
     pos=0;
   }
@@ -767,11 +850,13 @@ void parse_nick(char *nickfile)
         users[user].temp=users[i].temp;
       }
       users[user].lines+=users[i].lines;
+      users[user].words+=users[i].words;
       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].words=-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;
@@ -782,6 +867,7 @@ void parse_nick(char *nickfile)
   /* "remove" the ignored nicks */
   i=dichotomic("<NULL>");
   users[i].lines=-1;
+  users[i].words=-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;
@@ -794,6 +880,7 @@ void gen_xhtml(char *xhtmlfile)
   int i,j,k;
   int user,max,temp;
   char line[MAXLINELENGTH];
+  char *subtheme;
   
   if ((fic=fopen(xhtmlfile,"wt"))==NULL) { fprintf(stderr,"can't open xhtml file \"%s\"\n",xhtmlfile); exit(1); }
   
@@ -807,7 +894,10 @@ void gen_xhtml(char *xhtmlfile)
     fprintf(fic,"</title>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\" />\n",L("CHARSET"));
     if (refresh_time)
       fprintf(fic,"<meta http-equiv=\"Refresh\" content=\"%d\" />\n",refresh_time);
-    fprintf(fic,"<link rel=\"stylesheet\" type=\"text/css\" href=\"%s.css\" />\n",theme);
+    subtheme=strtok(theme,",");
+    fprintf(fic,"<link rel=\"stylesheet\" type=\"text/css\" href=\"%s.css\" title=\"%s\" />\n",subtheme,subtheme);
+    while ((subtheme=strtok(NULL,","))!=NULL)
+      fprintf(fic,"<link rel=\"alternate stylesheet\" type=\"text/css\" href=\"%s.css\" title=\"%s\" />\n",subtheme,subtheme);
     fprintf(fic,"</head>\n\n");
     fprintf(fic,"<body>\n\n");
   }
@@ -844,8 +934,14 @@ void gen_xhtml(char *xhtmlfile)
   /* top hours */
   fprintf(fic,"<div id=\"irssistats_tophours\">\n<h2>%s</h2>\n<table>\n<tr>\n",L("TOPHOURS"));
   max=-1;
-  for (i=0;i<24;i++) if (hours[i]>max) max=hours[i];
-  for (i=0;i<24;i++)
+  for (i=0;i<24*4;i++) if (hours[i]>max) max=hours[i];
+  if (quarter) for (i=0;i<24*4;i++)
+  {
+    fprintf(fic,"<td align=\"center\" valign=\"bottom\">");
+    if (hours[i]!=0) fprintf(fic,"<div class=\"v%d\" style=\"width:4px;height:%dpx\"></div>",i/4/6+1,150*hours[i]/max);
+    fprintf(fic,"</td>\n");
+  }
+  else for (i=0;i<24;i++)
   {
     fprintf(fic,"<td align=\"center\" valign=\"bottom\"><small>%.1f%%</small>",lines!=0?(float)100*hours[i]/lines:0);
     if (hours[i]!=0) fprintf(fic,"<div class=\"v%d\" style=\"height:%dpx\"></div>",i/6+1,150*hours[i]/max);
@@ -853,25 +949,59 @@ void gen_xhtml(char *xhtmlfile)
   }
   fprintf(fic,"</tr>\n<tr>\n");
   for (i=0;i<24;i++)
-    fprintf(fic,"<th>%d</th>\n",i);
+    if (quarter) fprintf(fic,"<th colspan=\"4\">%d</th>\n",i);
+    else fprintf(fic,"<th>%d</th>\n",i);
   fprintf(fic,"</tr>\n</table>\n</div>\n\n");
   
   /* top users */
   fprintf(fic,"<div id=\"irssistats_topusers\">\n<h2>%s</h2>\n",L("TOPUSERS"));
-  fprintf(fic,"<table>\n<tr><th></th><th>%s</th><th>%s</th><th>%s</th><th colspan=\"2\">%s</th><th>%s</th></tr>\n",L("NICK"),L("NBLINES"),L("HOURS"),L("AVGLETTERS"),L("QUOTE"));
+  switch (ranking)
+  {
+    case 0:
+      fprintf(fic,"<table>\n<tr><th></th><th>%s</th><th>%s</th><th>%s</th><th colspan=\"2\">%s</th><th>%s</th></tr>\n",L("NICK"),L("NBLINES"),L("HOURS"),L("AVGLETTERS"),L("QUOTE"));
+      break;
+    default:
+      /* "letters" and "words" ranking are not yet translated so we use the generic word "rank" ... */
+      fprintf(fic,"<table>\n<tr><th></th><th>%s</th><th>%s</th><th>%s</th><th colspan=\"2\">%s</th><th>%s</th></tr>\n",L("NICK"),"rank",L("HOURS"),L("AVGLETTERS"),L("QUOTE"));
+      break;
+  }
   for (i=1;i<=NBUSERS;i++)
   {
     user=-1;
     max=0;
-    for (j=0;j<nbusers;j++) if (users[j].lines>max) max=users[user=j].lines;
+    switch (ranking)
+    {
+      case 0:
+        for (j=0;j<nbusers;j++) if (users[j].lines>max) max=users[user=j].lines;
+        break;
+      case 1:
+        for (j=0;j<nbusers;j++) if (users[j].words>max) max=users[user=j].words;
+        break;
+      case 2:
+        for (j=0;j<nbusers;j++) if (users[j].letters>max) max=users[user=j].letters;
+        break;
+    }
     if (user!=-1)
     {
-      fprintf(fic,"<tr><td>%d</td><td>%s</td><td>%d</td><td class=\"oneline\">",i,users[user].nick,users[user].lines);
+      switch (ranking)
+      {
+        case 0:
+          fprintf(fic,"<tr><td>%d</td><td>%s</td><td>%d</td><td class=\"oneline\">",i,users[user].nick,users[user].lines);
+          break;
+        case 1:
+          fprintf(fic,"<tr><td>%d</td><td>%s</td><td>%d</td><td class=\"oneline\">",i,users[user].nick,users[user].words);
+          break;
+        case 2:
+          fprintf(fic,"<tr><td>%d</td><td>%s</td><td>%d</td><td class=\"oneline\">",i,users[user].nick,users[user].letters);
+          break;
+      }
       for (j=0;j<4;j++) if (users[user].hours[j]!=0) fprintf(fic,"<div class=\"h%d\" style=\"width:%dpx\"></div>",j+1,100*users[user].hours[j]/users[user].lines);
       fprintf(fic,"</td><td>%d</td><td><div class=\"hm\" style=\"width:%dpx\"></div></td><td>\"",users[user].lines!=0?users[user].letters/users[user].lines:0,users[user].lines!=0?users[user].letters/users[user].lines:0);
       printhtml(fic,users[user].quote);
       fprintf(fic,"\"</td></tr>\n");
       users[user].lines=-1;
+      users[user].words=-1;
+      users[user].letters=-1;
     }    
   }
   fprintf(fic,"</table>\n");
@@ -934,12 +1064,15 @@ void gen_xhtml(char *xhtmlfile)
   fprintf(fic,"</table>\n</div>\n\n");
   
   /* top words */
-  fprintf(fic,"<div id=\"irssistats_topwords\">\n<h2>%s</h2>\n",L("TOPWORDS"));
-  fprintf(fic,"<table>\n<tr><th></th><th>%s</th><th>%s</th></tr>\n",L("WORD"),L("OCCURRENCES"));
-  for (i=0;i<NBWORDS;i++)
-    if (topwords[i].nb!=0) fprintf(fic,"<tr><td>%d</td><td>\"%s\"</td><td>%d</td></tr>\n",i+1,topwords[i].word,topwords[i].nb);
-  fprintf(fic,"</table>\n</div>\n\n");
-
+  if (top_words)
+  {
+    fprintf(fic,"<div id=\"irssistats_topwords\">\n<h2>%s</h2>\n",L("TOPWORDS"));
+    fprintf(fic,"<table>\n<tr><th></th><th>%s</th><th>%s</th></tr>\n",L("WORD"),L("OCCURRENCES"));
+    for (i=0;i<NBWORDS;i++)
+      if (topwords[i].nb!=0) fprintf(fic,"<tr><td>%d</td><td>\"%s\"</td><td>%d</td></tr>\n",i+1,topwords[i].word,topwords[i].nb);
+    fprintf(fic,"</table>\n</div>\n\n");
+  }
+  
   /* big numbers */
   fprintf(fic,"<div id=\"irssistats_bignumbers\">\n<h2>%s</h2>\n",L("BIGNUMBERS"));
   fprintf(fic,"<table>\n<tr><th>%s</th><th>%s</th><th>%s</th></tr>\n",L("NICK"),L("NUMBERS"),L("NBLINES"));
@@ -1020,7 +1153,8 @@ void parse_config(char *configfile)
         else
         if (strcmp("verbose",value)==0) { debug=2; fprintf(stderr,"switching to verbose output\n"); }
         else { fprintf(stderr,"unknown value for \"debug\" option, must be \"normal\", \"verbose\" or \"none\"\n"); exit(1); }
-      } else
+      }
+      else
       
       if (strcmp("channel",keyword)==0)
       {
@@ -1112,14 +1246,43 @@ void parse_config(char *configfile)
         nburls=0;
         nbtopics=0;
         days=0;
-        for (i=0;i<24;i++) hours[i]=0;
+        for (i=0;i<24*4;i++) hours[i]=0;
         lines=0;
         freewords(&words);
         for (i=0;i<NBWORDS;i++) topwords[i].nb=0;
         totallines=0;
         debut=time(NULL);
       }
+      else
       
+      if (strcmp("top_words",keyword)==0)
+      {
+        if (debug==2) fprintf(stderr,"setting top_words to \"%s\"\n",value);
+        if (strcmp("no",value)==0) top_words=0;
+        else if (strcmp("yes",value)==0) top_words=1;
+        else { fprintf(stderr,"unknown value for \"top_words\" option, must be \"yes\" or \"no\"\n"); exit(1); }
+      }
+      else
+      
+      if (strcmp("ranking",keyword)==0)
+      {
+        if (strcmp("lines",value)==0) ranking=0;
+        else
+        if (strcmp("words",value)==0) ranking=1;
+        else
+        if (strcmp("letters",value)==0) ranking=2;
+        else { fprintf(stderr,"unknown value for \"ranking\" option, must be \"lines\", \"words\" or \"letters\"\n"); exit(1); }
+      }
+      else
+      
+      if (strcmp("quarter",keyword)==0)
+      {
+        if (debug==2) fprintf(stderr,"setting quarter to \"%s\"\n",value);
+        if (strcmp("no",value)==0) quarter=0;
+        else if (strcmp("yes",value)==0) quarter=1;
+        else { fprintf(stderr,"unknown value for \"quarter\" option, must be \"yes\" or \"no\"\n"); exit(1); }
+      }
+
       else { fprintf(stderr,"error in config file : \"%s\" is an unknown keyword (line %d)\n",keyword,configlines); exit(1); }        
     }
   }
@@ -1128,6 +1291,7 @@ void parse_config(char *configfile)
 
 int main(int argc,char *argv[])
 {
+  if ((users=malloc(maxusers*sizeof(struct user)))==NULL) { fprintf(stderr,"unable to malloc memory\n"); exit(1); }
   srand(debut=time(NULL));
   if (argc==1) parse_config(NULL);
   else if (argc==2) parse_config(argv[1]);
index 1051de4..7a10ca8 100644 (file)
@@ -24,10 +24,24 @@ maintainer : royale
 # Default : en
 language : fr
 
-# Theme (colors) to use for the statistics
+# Theme (colors) to use for the statistics, separated by comas
 # In fact this is the name of the CSS file to include.
 # This option has no effect if you use a custom header : you'll have to include the CSS yourself.
-theme : default
+# The first theme is the primary stylesheet, and the others are alternate themes
+theme : default,blue,dark,grayscale,namour,pisg,zeduel,zerezo
+
+# Allows you to disable top words list which is using a lot of memory
+# Default : yes
+top_words : no
+
+# Specifies which ranking method to use
+# Values : lines / words / letters
+# Default : lines
+ranking : letters
+
+# Display quarters in top hours (smoother graphs)
+# Default : no
+quarter : yes
 
 # Specifies the refresh time in seconds (0 to disable)
 # This option has no effect if you use a custom header : you'll have to include the refresh code yourself.