Fixed some recent GCC + 64-bit arch warnings.
[timeplan.git] / timeplan.c
index 357f9d0..5021932 100644 (file)
@@ -10,7 +10,7 @@
 #include <regex.h>
 
 #define ACTS_MAX 20
-#define HASH_SIZE 211
+#define HASH_SIZE 971
 #define CONFIGFILE "/.timeplanrc" /* HOME prepended */
 #define DEF_TIMEPLAN "/.timeplan" /* HOME prepended */
 #define MARK_DAY "_days"
@@ -25,7 +25,7 @@
 #define ERRNO2 strerror(errno)
 #define FAKEUSE =0
 
-static const char version[]="This is TimePlan, version 1.0\n";
+static const char version[]="This is TimePlan, version 1.0.1\n";
 static const char *pname;
 static char *finame;
 static FILE *fi;
@@ -39,9 +39,9 @@ static unsigned long lifetime_seq=1;
 
 static void usage(void)
 {
-       fprintf(stderr,"\
-%s\
-This command summarizes the timelog information:\n\
+       fprintf(stderr,"%s%s%s",
+version,
+"This command summarizes the timelog information:\n\
 \n\
 Usage: timeplan [-u|--unsort] [-s|--stores] [-T|--timetot]  [-t|--tree]\n\
                 [-c|--condition <cond>] [-f|--formtotal <fmtstring>]\n\
@@ -51,6 +51,7 @@ Usage: timeplan [-u|--unsort] [-s|--stores] [-T|--timetot]  [-t|--tree]\n\
   -u, --unsort\t\tDon't sort the result in any way\n\
   -s, --stores\t\tSort the result by stores count\n\
   -T, --timetot\t\tSort the result by total time (default)\n\
+","\
   -t, --tree\t\tOrganize data as hierarchy tree\n\
   -a, --average\t\tDisplay all times as average-per-day value\n\
   -c, --condition\tDefine condition variable\n\
@@ -59,7 +60,7 @@ Usage: timeplan [-u|--unsort] [-s|--stores] [-T|--timetot]  [-t|--tree]\n\
   -v, --verbose\t\tInform about phases of transfer\n\
   -h, --help\t\tPrint a summary of the options\n\
   -V, --version\t\tPrint the version number\n\
-",version);
+");
        exit(EXIT_FAILURE);
 }
 
@@ -114,7 +115,7 @@ char *end,*s2;
                                for (s2=s+1;isdigit(*s2);s2++);
                                l=strtol(s+1,&end,10);
                                if (end!=s2) {
-                                       fprintf(ERRH1"Number parse error at column %d of formtotal string!\n",ERRH2,s-formtotal);
+                                       fprintf(ERRH1"Number parse error at column %ld of formtotal string!\n",ERRH2,(long)(s-formtotal));
                                        exit(EXIT_FAILURE);
                                        }
                                if (*s=='*') tot*=l;
@@ -191,6 +192,7 @@ static unsigned calchash(const char *s)
 unsigned r=57;
 
        while (*s) r=r*7+11*toupper(*s++);
+       r=r%HASH_SIZE;
        return r;
 }
 
@@ -201,7 +203,7 @@ struct action **actionp,*action;
        if (!*what)
                return;
        if (verbose) printf("storeone: %d: %s\n",length,what);
-       for (actionp=hashtable+(calchash(what)%HASH_SIZE);(action=*actionp);actionp=&action->next)
+       for (actionp=hashtable+calchash(what);(action=*actionp);actionp=&action->next)
                if (!strcasecmp(action->what,what)) break;
        if (!action) {
                if (!(action=malloc(sizeof(*action)+strlen(what)))) {
@@ -231,7 +233,7 @@ struct textlist {
        int line;
        char text[1];
        };
-struct textlist *conditions,**conditionstail=&conditions;
+static struct textlist *conditions,**conditionstail=&conditions;
 
 static int iscondition(const char *text)
 {
@@ -308,12 +310,12 @@ int isplus;
                        while (isspace(*s)) s++;
                        if (*s==':') break;
                        if (!isalpha(*s)) {
-                               fprintf(ERRH1"Invalid character at offset %d"WHERE1,ERRH2,s-buf+1,WHERE2);
+                               fprintf(ERRH1"Invalid character at offset %ld"WHERE1,ERRH2,(long)(s-buf+1),WHERE2);
                                exit(EXIT_FAILURE);
                                }
                        for (s2=s+1;isalpha(*s2);s2++);
                        if (*s2!='+' && *s2!='-') {
-                               fprintf(ERRH1"Only plus ('+') or minus ('-'), not '%c' expected at offset %d"WHERE1,ERRH2,*s2,s2-buf+1,WHERE2);
+                               fprintf(ERRH1"Only plus ('+') or minus ('-'), not '%c' expected at offset %ld"WHERE1,ERRH2,*s2,(long)(s2-buf+1),WHERE2);
                                exit(EXIT_FAILURE);
                                }
                        isplus=(*s2=='+'); *s2++='\0';
@@ -470,22 +472,86 @@ enum { PATT_START,PATT_MID,PATT_END,PATT_TERM } pattpos;
        /* NOTREACHED */
 }
 
+static struct modifycache {
+       struct modifycache *next;
+       char src[1]; /* dst[1] follows after '\0' */
+       } *mcachetable[HASH_SIZE];
+static unsigned long modifycache_hits;
+
+static char *modify_cached(char *what)
+{
+struct modifycache **mcachep,*mcache;
+char *dst;
+size_t whatl;
+
+       if (!*what)
+               return(NULL);
+       whatl=strlen(what);
+       if (verbose) printf("modify_cached: %s\n",what);
+       for (mcachep=mcachetable+calchash(what);(mcache=*mcachep);mcachep=&mcache->next)
+               if (!strcasecmp(mcache->src,what)) break;
+       if (!mcache) {
+               dst=modify(what);
+               if (!(mcache=malloc(sizeof(*mcache)+whatl+1+(dst?strlen(dst):0)))) {
+                       fprintf(ERRH1"malloc() for \"%s\""ERRNO1,ERRH2,what,ERRNO2);
+                       exit(EXIT_FAILURE);
+                       }
+               mcache->next=NULL;
+               memcpy(mcache->src,what,whatl+1);
+               if (dst)
+                       strcpy(mcache->src+whatl+1,dst);
+               else
+                       mcache->src[whatl+1]='\0'; /* dst will be empty */
+               *mcachep=mcache;
+               }
+       else {
+               if (verbose) printf("cache hit.\n");
+               /* if (verbose) would be performance hit */
+                       modifycache_hits++;
+               }
+       if (!mcache->src[whatl+1])
+               return(NULL);
+       return(mcache->src+whatl+1);
+}
+
+static void modify_cached_stats(void)
+{
+struct modifycache **mcachep,*mcache;
+unsigned long depth,maxdepth=0,entries_total=0;
+#define MODIFYCACHE_CALLS (modifycache_hits+entries_total)
+
+       for (mcachep=mcachetable;mcachep<mcachetable+HASH_SIZE;mcachep++) {
+               for (depth=0,mcache=*mcachep;mcache;mcache=mcache->next)
+                       depth++;
+               if (depth>maxdepth)
+                       maxdepth=depth;
+               entries_total+=depth;
+               }
+       printf("modify_cached cache stats: hits=%u.%02u%% (%lu/%lu), HASH_SIZE=%d, maxdepth=%lu\n",
+               (unsigned)(   100*modifycache_hits/MODIFYCACHE_CALLS     ),
+               (unsigned)((10000*modifycache_hits/MODIFYCACHE_CALLS)%100),
+                                 modifycache_hits,MODIFYCACHE_CALLS,
+               HASH_SIZE,maxdepth);
+#undef MODIFYCACHE_CALLS
+}
+
 static void store(char *what,int length)
 {
-char *ce;
+char ce_trash,*ce,*ceo=&ce_trash;
 
-       if (!(what=modify(what))) {
+       if (!(what=modify_cached(what))) {
                if (verbose) puts("discarded.");
                return;
                }
        if (verbose) printf("store: %d: %s\n",length,what);
-       while ((ce=(tree?strrchr:strchr)(what,'-'))) {
+       while ((ce=(tree?strrchr(what,'-'):strchr(what,'-')))) {
                if (!tree) *ce='\0';
                storeone(what,length);
-               if (!tree) what=ce+1;
-               else *ce='\0';
+               if (!tree) { *ce='-'; what=ce+1; }
+               else { *ceo='-'; *(ceo=ce)='\0'; }
                }
        storeone(what,length);
+       if (tree) *ceo='-';
        lifetime_seq++;
 }
 
@@ -628,7 +694,7 @@ const char *days[]={"Ne","Po","Ut","St","Ct","Pa","So"};
                        t=mktime(&tm);
                        if (t==-1 || tm.tm_wday<0 || tm.tm_wday>6
                            || tm.tm_mday<1 || tm.tm_mday>31
-                                       || tm.tm_mon <1 || tm.tm_mon >12
+                                       || tm.tm_mon <0 || tm.tm_mon >11
                                        || tm.tm_year<80 || tm.tm_year>150
                                  ) {
                                fprintf(ERRH1"Incorrect timestamp \"%s\""WHERE1,ERRH2,buf,WHERE2);
@@ -672,6 +738,8 @@ const char *days[]={"Ne","Po","Ut","St","Ct","Pa","So"};
        if (fi!=stdin && fclose(fi))
                fprintf(ERRH1"fclose(3) \"%s\""ERRNO1,ERRH2,finame,ERRNO2);
 
+       if (verbose)
+               modify_cached_stats();
        dumphashtable();
        return EXIT_SUCCESS;
 }