#include #include #include /* Simple dictionary tool. A dictionary consists of two files in $home/lib/dict: • dictname: flat file with entries separated by lines like: ⇒headwordkey • dictname.idx: a sorted file of lines like: headword offset length There is a separate tool to create an index: dictidx dictname | sort | uniq > dictname.idx Usage: d [dictname] headword prints all entries with keys exactly matching headword prints nearest match if headword not found potential additions but too lazy: • zipped dictionaries?? or just chmod +t them... • line folding • context/browsing */ Biobuf *index, *dictionary, *output; char *word; enum{ PATHLEN = 128, BUFLEN = 8192 }; vlong getvlong(char delim){ vlong x; char *str; str = Brdstr(index, delim, 1); if(str == nil) sysfatal("getvlong: could not read string"); x = atoll(str); free(str); return x; } int checkhw(int *ip, int guess) { char *hw; hw = Brdstr(index, '\t', 1); if(hw == nil) return 0; *ip = strcmp(hw, word); if(guess && *ip > 0) sysfatal("nearest match: %s", hw); free(hw); return 1; } vlong findfirst(void) { vlong min, mid, max; int c; min = 0; max = Bseek(index, 0, 2); for(;;){ Bseek(index, min + (max - min) / 2, 0); Brdline(index, '\n'); mid = Boffset(index); if(mid == max || !checkhw(&c, 0)) break; if(c < 0) min = mid; else max = mid; } Bseek(index, min, 0); for(;;){ if(!checkhw(&c, 1)) sysfatal("could not find %s", word); if(c == 0) break; Brdline(index, '\n'); min = Boffset(index); } return min; } void main(int argc, char **argv) { char dict[PATHLEN], idx[PATHLEN], buf[BUFLEN]; int c; vlong off, len; sprint(dict, "%s/lib/dict/oed", getenv("home")); ARGBEGIN { } ARGEND; switch(argc){ case 2: sprint(dict, "%s/lib/dict/%s", getenv("home"), *argv++); case 1: word = *argv; if(*word == '\0') sysfatal("empty search key"); break; default: sysfatal("Usage: %s [dict] headword\n", argv0); } sprint(idx, "%s.idx", dict); index = Bopen(idx, OREAD); if(index == nil) sysfatal("Bopen: %r"); dictionary = Bopen(dict, OREAD); if(dictionary == nil) sysfatal("Bopen: %r"); output = Bfdopen(1, OWRITE); if(output == nil) sysfatal("Bfdopen: %r"); Bseek(index, findfirst(), 0); for(;;){ if(!checkhw(&c, 0) || c != 0) break; off = getvlong('\t'); len = getvlong('\n'); Bseek(dictionary, off, 0); for(; len > BUFLEN; len -= BUFLEN){ Bread(dictionary, buf, BUFLEN); Bwrite(output, buf, BUFLEN); } Bread(dictionary, buf, len); Bwrite(output, buf, len); Bputc(output, '\n'); } exits(nil); }