+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
+}
+