#include "deluge.h"
static void
indentprint(int fd, int indent)
{
while(indent-- > 0)
fprint(fd, " ");
}
void
beeprint(int fd, int indent, Bee *b)
{
int i;
Bee *key;
switch(b->type){
case TString:
indentprint(fd, indent);
if(b->slen > 200)
fprint(fd, "\"%200.200s...\",\n", b->s);
else
fprint(fd, "\"%*.*s\",\n", b->slen, b->slen, b->s);
break;
case TInteger:
indentprint(fd, indent);
fprint(fd, "%lld,\n", b->i);
break;
case TList:
indentprint(fd, indent);
fprint(fd, "list [\n");
for(i = 0; i < b->nl; i++)
beeprint(fd, indent+1, &b->l[i]);
indentprint(fd, indent);
fprint(fd, "],\n");
break;
case TDict:
indentprint(fd, indent);
fprint(fd, "dict {\n");
for(i = 0; i < b->dlen; i++){
key = &b->keys[i];
indentprint(fd, indent+1);
fprint(fd, "%-20.*s\n", key->slen, key->s);
beeprint(fd, indent+2, &b->values[i]);
}
indentprint(fd, indent);
fprint(fd, "},\n");
break;
default:
sysfatal("unknown Bee type (%d)", b->type);
}
}
void
beefree(Bee *b)
{
int i;
switch(b->type){
case TString:
free(b->s);
break;
case TInteger:
break;
case TList:
for(i = 0; i < b->nl; i++)
beefree(&b->l[i]);
free(b->l);
break;
case TDict:
for(i = 0; i < b->dlen; i++){
beefree(&b->keys[i]);
beefree(&b->values[i]);
}
free(b->keys);
free(b->values);
break;
default:
sysfatal("cannot happen in beefree");
}
}
char *
beeunpickle(Biobuf *bp, Bee *b)
{
int c;
char buf[64];
int i;
char *errmsg;
c = Bgetc(bp);
if(c < 0)
return smprint("unexpected eof while reading type");
switch(c){
case 'i': /* integer */
b->type = TInteger;
i = 0;
c = Bgetc(bp);
if(c == '-'){
buf[i++] = c;
c = Bgetc(bp);
}
while(c >= '0' && c <= '9' && c >= 0 && i < nelem(buf)){
buf[i++] = c;
c = Bgetc(bp);
}
buf[i] = 0;
if(c < 0)
return smprint("unexpected eof while reading integer");
if(c != 'e')
return smprint("unexpected character after integer ('%c', want 'e')", c);
if(strcmp(buf, "-0") == 0 || (strlen(buf) > 1 && buf[0] == '0'))
return smprint("invalid integer value '%s'", buf);
b->i = strtoll(buf, nil, 10);
break;
case 'l': /* list */
b->type = TList;
b->l = nil;
b->nl = 0;
for(;;){
c = Bgetc(bp);
if(c < 0)
return smprint("unexpected eof while reading list elements");
if(c == 'e'){
goto done;
}
Bungetc(bp);
b->l = erealloc(b->l, sizeof b->l[0] * (b->nl+1));
errmsg = beeunpickle(bp, &b->l[b->nl]);
if(errmsg)
return errmsg;
b->nl++;
}
return smprint("cannot happen in beeunpickle, list");
break;
case 'd': /* dict */
b->type = TDict;
b->keys = b->values = nil;
b->dlen = 0;
for(;;){
Bee *key, *value;
c = Bgetc(bp);
if(c < 0)
return smprint("unexpected eof while reading dict elements");
if(c == 'e'){
goto done;
}
Bungetc(bp);
b->keys = erealloc(b->keys, sizeof b->keys[0] * (b->dlen+1));
b->values = erealloc(b->values, sizeof b->values[0] * (b->dlen+1));
key = &b->keys[b->dlen];
value = &b->values[b->dlen];
errmsg = beeunpickle(bp, key);
if(errmsg)
return errmsg;
if(key->type != TString)
return smprint("read non-string type as key in dict (type=%d)", key->type);
errmsg = beeunpickle(bp, value);
if(errmsg)
return errmsg;
b->dlen++;
}
return smprint("cannot happen in beeunpickle, dict");
break;
default:
if(c >= '0' && c <= '9'){
b->type = TString;
i = 0;
buf[i++] = c;
while((c = Bgetc(bp)) >= 0 && c >= '0' && c <= '9')
buf[i++] = c;
buf[i] = 0;
if(c < 0)
return smprint("unexpected eof while reading length of string");
if(c != ':')
return smprint("unexpected character while reading string ('%c', wanted ':')", c);
b->slen = atoi(buf);
b->s = emalloc(b->slen+1);
for(i = 0; i < b->slen; i++){
c = Bgetc(bp);
if(c < 0)
return smprint("unexpected eof while reading string");
b->s[i] = c;
}
b->s[b->slen] = 0;
} else
return smprint("unexpected type character (%c)", c);
}
done:
return nil;
}
static void
_beepickle(Bee *b, String *s)
{
char *p;
int i;
switch(b->type){
case TString:
p = smprint("%d:", b->slen);
s_append(s, p);
free(p);
s_memappend(s, b->s, b->slen);
break;
case TInteger:
s_append(s, "i");
p = smprint("%lld", b->i);
s_append(s, p);
free(p);
s_append(s, "e");
break;
case TList:
s_append(s, "l");
for(i = 0; i < b->nl; i++)
_beepickle(&b->l[i], s);
s_append(s, "e");
break;
case TDict:
s_append(s, "d");
for(i = 0; i < b->dlen; i++){
_beepickle(&b->keys[i], s);
_beepickle(&b->values[i], s);
}
s_append(s, "e");
break;
default:
sysfatal("unknown type in _beepickle (%d)", b->type);
}
}
void
beepickle(Bee *b, char **pp, int *plenp)
{
String *s;
char *p;
s = s_new();
_beepickle(b, s);
p = emalloc(s_len(s)+1);
memmove(p, s_to_c(s), s_len(s));
*pp = p;
*plenp = s_len(s);
s_free(s);
}
Bee *
beedictget(Bee *b, char *key, int type)
{
int i;
if(b->type != TDict)
return nil;
for(i = 0; i < b->dlen; i++)
if(strcmp(b->keys[i].s, key) == 0)
if(b->values[i].type == type)
return &b->values[i];
else
return nil;
return nil;
}
void
ebeedictget(Bee *b, char *key, int type, void *p1, void *p2)
{
Bee *r;
char **sp;
vlong *ip;
Bee **bp;
r = beedictget(b, key, type);
if(r == nil)
sysfatal("missing key \"%s\"", key);
switch(type){
case TString:
sp = p1;
*sp = r->s;
if(p2){
ip = p2;
*ip = r->slen;
}
break;
case TInteger:
ip = p1;
*ip = r->i;
break;
case TList:
case TDict:
bp = p1;
*bp = r;
break;
default:
sysfatal("cannot happen, invalid type in ebeedictget (%d)", type);
}
}
|