Plan 9 from Bell Labs’s /usr/web/sources/contrib/mjl/wip/deluge/bee.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#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);
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.