| #include "constmap.h" |
| #include "alloc.h" |
| #include "case.h" |
| |
| static constmap_hash hash(const char *s,int len) |
| { |
| unsigned char ch; |
| constmap_hash h; |
| h = 5381; |
| while (len > 0) { |
| ch = *s++ - 'A'; |
| if (ch <= 'Z' - 'A') ch += 'a' - 'A'; |
| h = ((h << 5) + h) ^ ch; |
| --len; |
| } |
| return h; |
| } |
| |
| /* Returns index of string in constmap. 1 = first string, 2 = second ... */ |
| /* 0 not found. Use for commands */ |
| int constmap_index(const struct constmap *cm,const char *s,int len) |
| { |
| constmap_hash h; |
| struct constmap_entry *e; |
| int pos; |
| h = hash(s,len); |
| pos = cm->first[h & cm->mask]; |
| while (pos != -1) { |
| e = &cm->entries[pos]; |
| if (h == e->hash) |
| if (len == e->inputlen) |
| if (!case_diffb(e->input,len,s)) |
| return pos + 1; |
| pos = e->next; |
| } |
| return 0; |
| } |
| |
| /* returns pointer to sz of string with index "idx". 1 = first, 2 = second...*/ |
| const char *constmap_get(struct constmap *cm,unsigned int idx) |
| { |
| if (idx <= 0 || idx > cm->num) |
| return 0; |
| else |
| return cm->entries[idx-1].input; |
| } |
| |
| const char *constmap(struct constmap *cm,const char *s,int len) |
| { |
| constmap_hash h; |
| struct constmap_entry *e; |
| int pos; |
| h = hash(s,len); |
| pos = cm->first[h & cm->mask]; |
| while (pos != -1) { |
| e = &cm->entries[pos]; |
| if (h == e->hash) |
| if (len == e->inputlen) |
| if (!case_diffb(e->input,len,s)) |
| return e->input + e->inputlen + 1; |
| pos = e->next; |
| } |
| return 0; |
| } |
| |
| int constmap_init(struct constmap *cm,const char *s,int len,int splitchar) |
| /* if splitchar is set, we process only the stuff before that character |
| * on each line. Otherwise, it's the entire line. Still, the entire line |
| * is stored! */ |
| { |
| int i; |
| int j; |
| int k; |
| int pos; |
| constmap_hash h; |
| struct constmap_entry *e; |
| |
| cm->num = 0; |
| for (j = 0;j < len;++j) if (!s[j]) ++cm->num; |
| |
| h = 64; |
| while (h && (h < cm->num)) h += h; |
| cm->mask = h - 1; |
| |
| cm->first = (int *) alloc(sizeof(int) * h); |
| if (cm->first) { |
| cm->entries = alloc(cm->num * sizeof *cm->entries); |
| if (cm->entries) { |
| for (h = 0;h <= cm->mask;++h) |
| cm->first[h] = -1; |
| pos = 0; |
| i = 0; |
| for (j = 0;j < len;++j) |
| if (!s[j]) { |
| k = j - i; |
| if (splitchar) { |
| for (k = i;k < j;++k) |
| if (s[k] == splitchar) |
| break; |
| if (k >= j) { i = j + 1; continue; } |
| k -= i; |
| } |
| h = hash(s + i,k); |
| e = &cm->entries[pos]; |
| e->input = s + i; |
| e->inputlen = k; |
| e->hash = h; |
| h &= cm->mask; |
| e->next = cm->first[h]; |
| cm->first[h] = pos; |
| ++pos; |
| i = j + 1; |
| } |
| return 1; |
| } |
| alloc_free(cm->first); |
| } |
| return 0; |
| } |
| |
| void constmap_free(struct constmap *cm) |
| { |
| alloc_free(cm->entries); |
| alloc_free(cm->first); |
| } |