stew

a monorepo of some sort
git clone git://git.nsmpr.xyz/stew.git
Log | Files | Refs

tablist.c (7049B)


      1 /***** TODO *****
      2 
      3 	Implement decoding from buffer (aka file) instead of stream.
      4 	Boilerplate should include capability of navigating the buffer
      5 	via next_token/prev_token commands, while keeping track of
      6 	current line and indentation level.
      7 
      8 */
      9 
     10 #include <u.h>
     11 #include <libc.h>
     12 
     13 #include "../util/util.h"
     14 #include "tablist.h"
     15 
     16 Type TLnodeType = {.nbytes = sizeof(TLnode *), };
     17 
     18 TLnode *
     19 allocTLnode(void)
     20 {
     21 	TLnode *node = mallocz(sizeof(TLnode), 1);
     22 	node->children = allocslice(&TLnodeType, 0, 0);
     23 	return node;
     24 }
     25 
     26 void
     27 freeTLnode(TLnode *node)
     28 {
     29 	free(node->name);
     30 	free(node->value);
     31 	freeslice(node->children);
     32 	free(node);
     33 }
     34 
     35 int
     36 TLnodeappend(TLnode *parent, TLnode *child)
     37 {
     38 	sliceappendp(parent->children, 1, &child);
     39 	return 0;
     40 }
     41 
     42 static void
     43 _printnode(TLnode *n)
     44 {
     45 	print("NODE %p\n", n);
     46 	if (n->name != nil) print("NAME:  %.*s\n", n->name->len, n->name->p);
     47 	if (n->value != nil) print("VALUE: %.*s\n", n->value->len, n->value->p);
     48 	print("CHILDREN: %d\n", n->children->len);
     49 	print("END\n");
     50 }
     51 
     52 /***** DECODER *****/
     53 
     54 
     55 TLdecoder *
     56 initTLdecoder(char *file)
     57 {
     58 	TLdecoder *tlp;
     59 	tlp = mallocz(sizeof(TLdecoder), 1);
     60 	tlp->nodes = allocslice(&TLnodeType, 0, 1);
     61 	tlp->acc = allocslice(&CharType, 0, 256);
     62 	tlp->file = file;
     63 	return tlp;
     64 }
     65 
     66 int
     67 TLdecode(TLdecoder *r, char *buf, usize count)
     68 {
     69 	enum {
     70 		Start, Begin, Node, Name, FlushName, Value, FlushValue, Indent,
     71 	};
     72 	usize i;
     73 	TLnode *new;
     74 	for (i = 0; i < count;) {
     75 		switch (r->state) {
     76 		case Start:
     77 			r->state = Begin;
     78 
     79 		case Begin:
     80 			r->indent = 0;
     81 			if (buf[i] == '\t') r->state = Indent;
     82 			else r->sp = 0, r->state = Node;
     83 			break;
     84 
     85 		case Node:
     86 			r->acc->len = 0;
     87 			if (buf[i] == '\\') r->state = Value, i++;
     88 			else r->state = Name;
     89 			break;
     90 
     91 		case Name:
     92 			if ((buf[i] != ' ') && (buf[i] != '\n')) {
     93 				r->acc = sliceappendp(r->acc, 1, buf+i), i++;
     94 				break;
     95 			}
     96 			r->state = FlushName;
     97 
     98 		case FlushName:
     99 			new = allocTLnode();
    100 			new->name = slicecopy(r->acc);
    101 
    102 			if (r->indent == 0) {
    103 				r->sp = 0;
    104 				sliceappendp(r->nodes, 1, &new);
    105 			} else if (r->indent == -1) {
    106 				sliceappendp(r->stack[r->sp]->children, 1, &new);
    107 			} else if (r->indent <= r->sp) {
    108 				r->sp = r->indent;
    109 				sliceappendp(r->stack[r->sp - 1]->children, 1, &new);
    110 			} else if (r->indent == r->sp + 1) {
    111 				sliceappendp(r->stack[r->sp]->children, 1, &new);
    112 				r->sp = r->indent;
    113 			} else sysfatal("TLdecode/FlushName: indent is no good");
    114 
    115 			r->stack[r->sp] = new;
    116 
    117 			if (buf[i] == ' ') r->state = Node, r->indent = -1, i++;
    118 			else r->state = Begin, i++;
    119 			break;
    120 
    121 		case Value:
    122 			if (buf[i] != '\n') {
    123 				r->acc = sliceappendp(r->acc, 1, buf+i), i++;
    124 				break;
    125 			} else r->state = FlushValue;
    126 
    127 		case FlushValue:
    128 			new = allocTLnode();
    129 			new->value = slicecopy(r->acc);
    130 
    131 			if (r->indent == 0) {
    132 				r->sp = 0;
    133 				sliceappendp(r->nodes, 1, &new);
    134 			} else if (r->indent == -1) {
    135 				sliceappendp(r->stack[r->sp]->children, 1, &new);
    136 			} else if (r->indent <= r->sp) {
    137 				r->sp = r->indent;
    138 				sliceappendp(r->stack[r->sp - 1]->children, 1, &new);
    139 			} else if (r->indent == r->sp + 1) {
    140 				sliceappendp(r->stack[r->sp]->children, 1, &new);
    141 				r->sp = r->indent;
    142 			} else sysfatal("TLdecode/FlushName: indent is no good");
    143 
    144 			r->stack[r->sp] = new;
    145 
    146 			r->state = Begin, i++;
    147 			break;
    148 
    149 		case Indent:
    150 			if (buf[i] == '\t') r->indent++, i++;
    151 			else r->state = Node;
    152 			break;
    153 
    154 		default:
    155 			sysfatal("TLdecode: unknown state %d", r->state);
    156 		}
    157 	}
    158 	return 0;
    159 }
    160 
    161 /******* ENCODER *******/
    162 
    163 typedef void * (TLencstate)(TLencoder *, char *);
    164 TLencstate _encstart, _encnode, _encname, _encvalue, _encnext,
    165 	_encnl, _encsp, _encind, _encend;
    166 
    167 
    168 #define ENCTOS(X) ( *(TLnode **)slicegetp(X->ns[X->sp], X->cs[X->sp]) )
    169 
    170 TLencoder *
    171 initTLencoder(Slice *nodes)
    172 {
    173 	TLencoder *w = mallocz(sizeof(TLencoder), 1);
    174 	w->ns[0] = nodes;
    175 	w->state = _encstart;
    176 	return w;
    177 }
    178 
    179 void *
    180 _encstart(TLencoder *w, char *c)
    181 {
    182 	if (w->ns[0]->len == 0) return _encend(w, c);
    183 	return _encnode(w, c);
    184 }
    185 
    186 void *
    187 _encnode(TLencoder *w, char *c)
    188 {
    189 	TLnode *n = ENCTOS(w);
    190 	assert(n != nil);
    191 	w->i = 0;
    192 	if (n->name  != nil) return _encname(w, c);
    193 	if (n->value != nil) return _encvalue(w, c);
    194 	return _encend(w, c);
    195 }
    196 
    197 void *
    198 _encname(TLencoder *w, char *c)
    199 {
    200 	TLnode *n = ENCTOS(w);
    201 	if (w->i >= n->name->len) return _encnext(w, c);
    202 	char *s = slicegetp(n->name, w->i);
    203 	*c = *s;
    204 	w->i++;
    205 	return _encname;
    206 }
    207 
    208 void *
    209 _encvalue(TLencoder *w, char *c)
    210 {
    211 	if (w->i == 0) {
    212 		*c = '\\';
    213 		w->i++;
    214 		return _encvalue;
    215 	}
    216 	TLnode *n = ENCTOS(w);
    217 	if (w->i >= n->value->len + 1) return _encnext(w, c);
    218 	char *s = slicegetp(n->value, w->i - 1);
    219 	*c = *s;
    220 	w->i++;
    221 	return _encvalue;
    222 }
    223 
    224 void *
    225 _encnext(TLencoder *w, char *c)
    226 {
    227 	TLnode *n = ENCTOS(w);
    228 	// TODO: delete? don't remember what this was for
    229 	// TLnode *fc = nil;
    230 	// if (n->children->len > 0) fc = *(TLnode **)slicegetp(n->children, 0);
    231 
    232 	if (n->children->len == 0) {
    233 		w->cs[w->sp]++;
    234 		return _encnl(w, c);
    235 
    236 	} else if ( (n->children->len > 1) || (n->value != nil) ) {
    237 		w->sp++;
    238 		w->ns[w->sp] = n->children;
    239 		w->cs[w->sp] = 0;
    240 		return _encnl(w, c);
    241 
    242 	} else {
    243 		w->sp++;
    244 		w->ns[w->sp] = n->children;
    245 		w->cs[w->sp] = 0;
    246 		return _encsp(w, c);
    247 
    248 	}
    249 }
    250 
    251 void *
    252 _encnl(TLencoder *w, char *c)
    253 {
    254 	*c = '\n';
    255 	while (w->cs[w->sp] == w->ns[w->sp]->len) {
    256 		w->sp--;
    257 		if (w->sp < 0) return _encend;
    258 		w->cs[w->sp]++;
    259 	}
    260 	w->i = 0;
    261 	return _encind;
    262 }
    263 
    264 void *
    265 _encsp(TLencoder *, char *c)
    266 {
    267 	*c = ' ';
    268 	return _encnode;
    269 }
    270 
    271 void *
    272 _encind(TLencoder *w, char *c)
    273 {
    274 	if (w->i < w->sp) {
    275 		*c = '\t';
    276 		w->i++;
    277 		return _encind;
    278 	}
    279 	return _encnode(w, c);
    280 }
    281 
    282 void *
    283 _encend(TLencoder *, char *c)
    284 {
    285 	*c = '\0';
    286 	return nil;
    287 }
    288 
    289 int
    290 TLencode(TLencoder *w, char *buf, usize count)
    291 {
    292 	usize i;
    293 	for (i = 0; i < count; i++) {
    294 		if (w->state == nil) return i;
    295 		w->state = w->state(w, buf+i);
    296 	}
    297 	return i;
    298 }
    299 
    300 TLnode *
    301 TLgetnode(Slice *list, char *name, char *value)
    302 {
    303 	if (list == nil) sysfatal("TLgetnode: list is nil");
    304 	if (list->arr->type != &TLnodeType) sysfatal("TLgetnode: list is not TLnodeType");
    305 	if (list->len == 0) return nil;
    306 	int i;
    307 	for (i = 0; i < list->len; i++) {
    308 		TLnode **p = slicegetp(list, i);
    309 		TLnode *n = *p;
    310 		if (name != nil) {
    311 			if (strlen(name) != n->name->len) continue;
    312 			if (memcmp(name, n->name->p, n->name->len) == 0)
    313 				return n;
    314 		} else if (value != nil) {
    315 			if (strlen(value) != n->value->len) continue;
    316 			if (memcmp(value, n->value->p, n->value->len) == 0)
    317 				return n;
    318 		} else return nil;
    319 	}
    320 	return nil;
    321 }
    322 
    323 char *
    324 TLval2str(TLnode *n)
    325 {
    326 	usize len = 0;
    327 	int i;
    328 	for(i = 0; i < n->children->len; i++) {
    329 		TLnode **v = slicegetp(n->children, i);
    330 		TLnode *nn = *v;
    331 		if (nn->value == nil) continue;
    332 		len += nn->value->len + 1;
    333 	}
    334 	if (len == 0) len = 1;
    335 	char *buf = malloc(len);
    336 	char *p = buf;
    337 	for(i = 0; i < n->children->len; i++) {
    338 		TLnode **v = slicegetp(n->children, i);
    339 		TLnode *nn = *v;
    340 		if (nn->value == nil) continue;
    341 		memcpy(p, nn->value->p, nn->value->len);
    342 		p += nn->value->len;
    343 		*p = '\n';
    344 		p++;
    345 	}
    346 	buf[len - 1] = '\0';
    347 	// fprint(2, "TLval2str: %s\n", buf);
    348 	return buf;
    349 }