Files
strans/dict.c

144 lines
2.7 KiB
C

#include <errno.h>
#include "dat.h"
#include "fn.h"
static char*
readline(Biobuf *b, char *path)
{
char *line;
errno = 0;
line = Brdstr(b, '\n', 1);
if(errno != 0)
die("can't read %s: %s", path, strerror(errno));
return line;
}
void
dictlookup(Dictreq *req, Dictres *res)
{
Lang *l;
Hmap *dict;
Hnode *n;
char *p, *e, *sp;
Str tmp;
res->key = req->pre;
res->nkouho = 0;
res->lang = req->lang;
res->seq = req->seq;
if(req->key.n == 0)
return;
l = getlang(req->lang);
dict = l ? l->dict : nil;
if(dict == nil)
return;
n = hmapget(dict, &req->key);
if(n == nil || n->vlen == 0)
return;
p = n->val;
e = p + n->vlen;
while(res->nkouho < Maxkouho && p < e){
while(p < e && *p == ' ')
p++;
if(p == e)
break;
sp = p;
while(p < e && *p != ' ')
p++;
if(!sinit(&tmp, sp, p - sp)){
res->nkouho = 0;
return;
}
if(req->lang == LangEMOJI || scmp(&tmp, &req->key) != 0)
res->kouho[res->nkouho++] = tmp;
if(p < e)
p++;
}
}
void
dictthread(void*)
{
Dictreq req;
static Dictres res;
threadsetname("dict");
for(;;){
if(chanrecv(dictreqc, &req) < 0)
break;
while(channbrecv(dictreqc, &req) > 0)
;
dictlookup(&req, &res);
chansend(dictresc, &res);
}
}
static Hmap*
dictopen(char *path)
{
Hmap *h;
Biobuf *b;
Str key, tmp;
char *line, *tab, *p, *e;
int len, lineno;
b = Bopen(path, OREAD);
if(b == nil)
die("can't open %s: %s", path, strerror(errno));
h = hmapalloc(4096);
lineno = 0;
while((line = readline(b, path)) != nil){
lineno++;
len = Blinelen(b);
if(memchr(line, '\0', len) != nil)
die("NUL in dictionary: %s:%d", path, lineno);
if(len > 0 && line[len-1] == '\r')
line[--len] = '\0';
if(len == 0 || line[0] == ';'){
free(line);
continue;
}
tab = memchr(line, '\t', len);
if(tab == nil || tab == line || tab >= line + len - 1 ||
memchr(tab+1, '\t', line+len-(tab+1)) != nil)
die("malformed dictionary: %s:%d", path, lineno);
*tab = '\0';
if(!sinit(&key, line, tab-line))
die("invalid or oversized dictionary key: %s:%d",
path, lineno);
for(p = tab+1; p < line+len; p = e+1){
e = memchr(p, ' ', line+len-p);
if(e == nil)
e = line+len;
if(!sinit(&tmp, p, e-p))
die("invalid or oversized dictionary candidate: %s:%d",
path, lineno);
if(e == line+len)
break;
}
hmapset(&h, &key, tab+1, len - (tab - line) - 1);
free(line);
}
if(Bterm(b) < 0)
die("can't close %s: %s", path, strerror(errno));
return h;
}
void
dictinit(char *dir)
{
char *path;
int i;
for(i = 0; i < nlang; i++){
if(langs[i].dictname == nil)
continue;
path = smprint("%s/%s.dict", dir, langs[i].dictname);
if(path == nil)
die("out of memory");
langs[i].dict = dictopen(path);
free(path);
}
}