/************************************************************************ * hash.c * Copyright (C) 2002 Marcello Barnaba * * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * FNV rocks. */ #include #include #include #include #include #include #include extern int errno; #define HASHSIZE 223 #define BUFSZ 64 typedef unsigned long hash_t; typedef struct nlist { char *name; char *defn; unsigned short f_o, l_o; struct nlist *next; } Nlist; static Nlist *hashtab[HASHSIZE]; static __inline__ char *xstrdup(char *s) { char *ret = strdup(s); if(!ret) err(-1, "out of memory"); return ret; } static __inline__ void *xmalloc(size_t sz) { void *ret = malloc(sz); if(!ret) err(-1, "out of memory"); memset(ret, 0x0, sz); return ret; } static __inline__ void xfree(void *p) { if(p) free(p); } /* * Fowler / Noll / Vo (FNV) Hash . . * Noll, Landon Curt (LCN2) * chongo /\../\ * * #define HASH(sta, end, hash) while(end != sta) { hash = ((hash * 16777619UL) ^ (*end--)) } */ #define FNV_prime 16777619UL __inline__ hash_t fnv_hash(char *s) { hash_t h = 0; char *e = s + strlen(s) - 1; while(e != s) h = ((h * FNV_prime) ^ *e--); return h % HASHSIZE; } Nlist *lookup(char *s) { Nlist *np = hashtab[fnv_hash(s)]; for(; np; np = np->next) if(strcmp(s, np->name) == 0) return np; return NULL; } Nlist *insert(char *n, char *d, unsigned short occ) { Nlist *np = lookup(n); if(np == NULL) { Nlist **trav; np = xmalloc(sizeof(Nlist)); np->name = xstrdup(n); np->defn = xstrdup(d); np->f_o = np->l_o = occ; trav = &hashtab[fnv_hash(n)]; if(*trav) { for(; *trav && (*trav)->next; *trav = (*trav)->next); (*trav)->next = np; } else (*trav) = np; return np; } else if(strcmp(np->defn, d)) { fprintf(stderr, "warning, %s redefined from \"%s\"[%d] to \"%s\"\n", n, np->defn, np->l_o, d); xfree((void *)np->defn); np->defn = xstrdup(d); np->l_o = occ; return np; } return NULL; } void hash_acquire(char *f) { FILE *in; char bufn[BUFSZ], bufd[BUFSZ]; unsigned int linenum, r; memset(hashtab, 0x0, sizeof(hashtab)); if(!f || (f[0] == '-' && f[1] == '\0')) { in = stdin; fprintf(stderr, "using standard input as input stream.\n"); } else if((in = fopen(f, "r")) == NULL) err(1, "cannot open input file %s", f); linenum = 0; while((r = fscanf(in, "%64s -> %64s\n", bufn, bufd)) != EOF) { linenum++; (r == 2) ? insert(bufn, bufd, linenum) : (void) printf("parse error.\n"); } } void hash_print(void) { unsigned short i = 0; Nlist *trav; for(; i < HASHSIZE; ++i) { if((trav = hashtab[i])) { printf("hashtab[%d]: ", i); for(; trav; trav = trav->next) printf("define %s -> %s; ", trav->name, trav->defn); puts(""); } } } void hash_query(void) { char buf[BUFSZ]; printf("insert a word to search into hashtable: "); while(fscanf(stdin, "%64s", buf) != EOF) { Nlist *np; ((np = lookup(buf))) ? printf("found in hashtab[%ld]: %-20s | defn: %-20s | f_o: %10d | l_o: %10d\n", fnv_hash(buf), np->name, np->defn, np->f_o, np->l_o) : printf("not found.\n"); printf("insert a word to search into hashtable: "); } } static __inline__ void version(char *me) { fprintf(stderr, "%s: version 0.6\n", me); } static __inline__ void usage(char *me) { fprintf(stderr, "%s: usage:\n" " -f -- use as your input\n" " -h -- this crap\n" " -v -- version crap\n", me); } int main(int argc, char **argv) { char *f = NULL; extern int optind, optopt; extern char *optarg; int c; while((c = getopt(argc, argv, "f:vh")) != -1) { switch(c) { case 'f': f = xstrdup(optarg); break; case 'v': version(argv[0]); exit(0); break; case 'h': usage(argv[0]); exit(1); break; case '?': switch(optopt) { case 'f': exit(1); } } } argv += optind; argc -= optind; hash_acquire(f); hash_print(); hash_query(); return 0; }