1 /*
2  * This file generates parts of LibCSS.
3  * Licensed under the MIT License,
4  *		  http://www.opensource.org/licenses/mit-license.php
5  * Copyright 2010 Vincent Sanders <vince@netsurf-browser.org>
6  */
7 
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <stdbool.h>
12 
13 /* Descriptors are space separated key:value pairs brackets () are
14  * used to quote in values.
15  *
16  * Examples:
17  * list_style_image:CSS_PROP_LIST_STYLE_IMAGE IDENT:( INHERIT: NONE:0,LIST_STYLE_IMAGE_NONE IDENT:) URI:LIST_STYLE_IMAGE_URI
18  *
19  * list_style_position:CSS_PROP_LIST_STYLE_POSITION IDENT:( INHERIT: INSIDE:0,LIST_STYLE_POSITION_INSIDE OUTSIDE:0,LIST_STYLE_POSITION_OUTSIDE IDENT:)
20 */
21 
22 struct keyval {
23 	char *key;
24 	char *val;
25 };
26 
27 struct keyval_list {
28 	struct keyval *item[100];
29 	int count;
30 };
31 
get_keyval(char ** pos)32 struct keyval *get_keyval(char **pos)
33 {
34 	char *endpos;
35 	struct keyval *nkeyval;
36 	int kvlen;
37 
38 	endpos = strchr(*pos, ' '); /* single space separated pairs */
39 	if (endpos == NULL) {
40 		/* no space, but might be the end of the input */
41 		kvlen = strlen(*pos);
42 		if (kvlen == 0)
43 			return NULL;
44 	} else {
45 		kvlen = (endpos - *pos);
46 	}
47 	nkeyval = calloc(1, sizeof(struct keyval) + kvlen + 1);
48 
49 	memcpy(nkeyval + 1, *pos, kvlen);
50 
51 	nkeyval->key = (char *)nkeyval + sizeof(struct keyval);
52 
53 	endpos = strchr(nkeyval->key, ':'); /* split key and value on : */
54 	if (endpos != NULL) {
55 		endpos[0] = 0; /* change : to null terminator */
56 		nkeyval->val = endpos + 1; /* skip : */
57 	}
58 
59 	*pos += kvlen; /* update position */
60 
61 	/* skip spaces */
62 	while ((*pos[0] != 0) &&
63 	       (*pos[0] == ' ')) {
64 		(*pos)++;
65 	}
66 
67 	return nkeyval;
68 }
69 
output_header(FILE * outputf,const char * descriptor,struct keyval * parser_id,bool is_generic)70 void output_header(FILE *outputf, const char *descriptor, struct keyval *parser_id, bool is_generic)
71 {
72 	fprintf(outputf,
73 		"/*\n"
74 		" * This file was generated by LibCSS gen_parser \n"
75 		" * \n"
76 		" * Generated from:\n"
77 		" *\n"
78 		" * %s\n"
79 		" * \n"
80 		" * Licensed under the MIT License,\n"
81 		" *		  http://www.opensource.org/licenses/mit-license.php\n"
82 		" * Copyright 2010 The NetSurf Browser Project.\n"
83 		" */\n"
84 		"\n"
85 		"#include <assert.h>\n"
86 		"#include <string.h>\n"
87 		"\n"
88 		"#include \"bytecode/bytecode.h\"\n"
89 		"#include \"bytecode/opcodes.h\"\n"
90 		"#include \"parse/properties/properties.h\"\n"
91 		"#include \"parse/properties/utils.h\"\n"
92 		"\n"
93 		"/**\n"
94 		" * Parse %s\n"
95 		" *\n"
96 		" * \\param c	  Parsing context\n"
97 		" * \\param vector  Vector of tokens to process\n"
98 		" * \\param ctx	  Pointer to vector iteration context\n"
99 		" * \\param result  resulting style\n"
100 		"%s"
101 		" * \\return CSS_OK on success,\n"
102 		" *	   CSS_NOMEM on memory exhaustion,\n"
103 		" *	   CSS_INVALID if the input is not valid\n"
104 		" *\n"
105 		" * Post condition: \\a *ctx is updated with the next token to process\n"
106 		" *		   If the input is invalid, then \\a *ctx remains unchanged.\n"
107 		" */\n"
108 		"css_error css__parse_%s(css_language *c,\n"
109 		"		const parserutils_vector *vector, int *ctx,\n"
110 		"		css_style *result%s)\n"
111 		"{\n",
112 		descriptor,
113 		parser_id->key,
114 		is_generic ? " * \\param op	 Bytecode OpCode for CSS property to encode\n" : "",
115 		parser_id->key,
116 		is_generic ? ", enum css_properties_e op" : "");
117 }
118 
119 
output_token_type_check(FILE * outputf,bool do_token_check,struct keyval_list * IDENT,struct keyval_list * URI,struct keyval_list * NUMBER)120 void output_token_type_check(FILE *outputf, bool do_token_check, struct keyval_list *IDENT, struct keyval_list *URI, struct keyval_list *NUMBER)
121 {
122 	fprintf(outputf,
123 		"	int orig_ctx = *ctx;\n"
124 		"	css_error error;\n"
125 		"	const css_token *token;\n"
126 		"	bool match;\n\n"
127 		"	token = parserutils_vector_iterate(vector, ctx);\n"
128 		"	if (%stoken == NULL%s",
129 		do_token_check ? "(" : "",
130 		do_token_check ? ")" : "");
131 
132 	if (do_token_check) {
133 		bool prev = false; /* there was a previous check - add && */
134 		fprintf(outputf," || (");
135 
136 		if (IDENT->count > 0) {
137 			fprintf(outputf,"(token->type != CSS_TOKEN_IDENT)");
138 			prev = true;
139 		}
140 		if (URI->count > 0) {
141 			if (prev) fprintf(outputf," && ");
142 			fprintf(outputf,"(token->type != CSS_TOKEN_URI)");
143 			prev = true;
144 		}
145 		if (NUMBER->count > 0) {
146 			if (prev) fprintf(outputf," && ");
147 			fprintf(outputf,"(token->type != CSS_TOKEN_NUMBER)");
148 			prev = true;
149 		}
150 
151 		fprintf(outputf,")");
152 	}
153 
154 	fprintf(outputf,
155 		") {\n"
156 		"\t\t*ctx = orig_ctx;\n"
157 		"\t\treturn CSS_INVALID;\n"
158 		"\t}\n\n\t");
159 }
160 
output_ident(FILE * outputf,bool only_ident,struct keyval * parseid,struct keyval_list * IDENT)161 void output_ident(FILE *outputf, bool only_ident, struct keyval *parseid, struct keyval_list *IDENT)
162 {
163 	int ident_count;
164 
165 	for (ident_count = 0 ; ident_count < IDENT->count; ident_count++) {
166 		struct keyval *ckv = IDENT->item[ident_count];
167 
168 		fprintf(outputf,
169 			"if (");
170 		if (!only_ident) {
171 			fprintf(outputf,
172 			"(token->type == CSS_TOKEN_IDENT) && ");
173 		}
174 		fprintf(outputf,
175 			"(lwc_string_caseless_isequal(token->idata, c->strings[%s], &match) == lwc_error_ok && match)) {\n",
176 			ckv->key);
177 		if (strcmp(ckv->key,"INHERIT") == 0) {
178 		fprintf(outputf,
179 			"\t\t\terror = css_stylesheet_style_inherit(result, %s);\n",
180 			parseid->val);
181 		} else {
182 		fprintf(outputf,
183 			"\t\t\terror = css__stylesheet_style_appendOPV(result, %s, %s);\n",
184 			parseid->val,
185 			ckv->val);
186 		}
187 		fprintf(outputf,
188 			"\t} else ");
189 	}
190 }
191 
output_uri(FILE * outputf,struct keyval * parseid,struct keyval_list * kvlist)192 void output_uri(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist)
193 {
194 	struct keyval *ckv = kvlist->item[0];
195 
196 	fprintf(outputf,
197 		"if (token->type == CSS_TOKEN_URI) {\n"
198 		"		lwc_string *uri = NULL;\n"
199 		"		uint32_t uri_snumber;\n"
200 		"\n"
201 		"		error = c->sheet->resolve(c->sheet->resolve_pw,\n"
202 		"				c->sheet->url,\n"
203 		"				token->idata, &uri);\n"
204 		"		if (error != CSS_OK) {\n"
205 		"			*ctx = orig_ctx;\n"
206 		"			return error;\n"
207 		"		}\n"
208 		"\n"
209 		"		error = css__stylesheet_string_add(c->sheet, uri, &uri_snumber);\n"
210 		"		if (error != CSS_OK) {\n"
211 		"			*ctx = orig_ctx;\n"
212 		"			return error;\n"
213 		"		}\n"
214 		"\n"
215 		"		error = css__stylesheet_style_appendOPV(result, %s, 0, %s);\n"
216 		"		if (error != CSS_OK) {\n"
217 		"			*ctx = orig_ctx;\n"
218 		"			return error;\n"
219 		"		}\n"
220 		"\n"
221 		"		error = css__stylesheet_style_append(result, uri_snumber);\n"
222 		"	} else ",
223 		parseid->val,
224 		ckv->val);
225 }
226 
output_number(FILE * outputf,struct keyval * parseid,struct keyval_list * kvlist)227 void output_number(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist)
228 {
229 	struct keyval *ckv = kvlist->item[0];
230 	int ident_count;
231 
232 	fprintf(outputf,
233 		"if (token->type == CSS_TOKEN_NUMBER) {\n"
234 		"\t\tcss_fixed num = 0;\n"
235 		"\t\tsize_t consumed = 0;\n\n"
236 		"\t\tnum = css__number_from_lwc_string(token->idata, %s, &consumed);\n"
237 		"\t\t/* Invalid if there are trailing characters */\n"
238 		"\t\tif (consumed != lwc_string_length(token->idata)) {\n"
239 		"\t\t\t*ctx = orig_ctx;\n"
240 		"\t\t\treturn CSS_INVALID;\n"
241 		"\t\t}\n",
242 		ckv->key);
243 
244 	for (ident_count = 1 ; ident_count < kvlist->count; ident_count++) {
245 		struct keyval *ulkv = kvlist->item[ident_count];
246 
247 		if (strcmp(ulkv->key, "RANGE") == 0) {
248 			fprintf(outputf,
249 				"\t\tif (%s) {\n"
250 				"\t\t\t*ctx = orig_ctx;\n"
251 				"\t\t\treturn CSS_INVALID;\n"
252 				"\t\t}\n\n",
253 				ulkv->val);
254 		}
255 
256 	}
257 
258 	fprintf(outputf,
259 		"\t\terror = css__stylesheet_style_appendOPV(result, %s, 0, %s);\n"
260 		"\t\tif (error != CSS_OK) {\n"
261 		"\t\t\t*ctx = orig_ctx;\n"
262 		"\t\t\treturn error;\n"
263 		"\t\t}\n\n"
264 		"\t\terror = css__stylesheet_style_append(result, num);\n"
265 		"\t} else ",
266 		parseid->val,
267 		ckv->val);
268 }
269 
output_color(FILE * outputf,struct keyval * parseid,struct keyval_list * kvlist)270 void output_color(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist)
271 {
272 	fprintf(outputf,
273 		"{\n"
274 		"\t\tuint16_t value = 0;\n"
275 		"\t\tuint32_t color = 0;\n"
276 		"\t\t*ctx = orig_ctx;\n\n"
277 		"\t\terror = css__parse_colour_specifier(c, vector, ctx, &value, &color);\n"
278 		"\t\tif (error != CSS_OK) {\n"
279 		"\t\t\t*ctx = orig_ctx;\n"
280 		"\t\t\treturn error;\n"
281 		"\t\t}\n\n"
282 		"\t\terror = css__stylesheet_style_appendOPV(result, %s, 0, value);\n"
283 		"\t\tif (error != CSS_OK) {\n"
284 		"\t\t\t*ctx = orig_ctx;\n"
285 		"\t\t\treturn error;\n"
286 		"\t\t}\n"
287 		"\n"
288 		"\t\tif (value == COLOR_SET)\n"
289 		"\t\t\terror = css__stylesheet_style_append(result, color);\n"
290 		"\t}\n\n",
291 		parseid->val);
292 }
293 
output_length_unit(FILE * outputf,struct keyval * parseid,struct keyval_list * kvlist)294 void output_length_unit(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist)
295 {
296 	struct keyval *ckv = kvlist->item[0];
297 	int ident_count;
298 
299 
300 	fprintf(outputf,
301 		"{\n"
302 		"\t\tcss_fixed length = 0;\n"
303 		"\t\tuint32_t unit = 0;\n"
304 		"\t\t*ctx = orig_ctx;\n\n"
305 		"\t\terror = css__parse_unit_specifier(c, vector, ctx, %s, &length, &unit);\n"
306 		"\t\tif (error != CSS_OK) {\n"
307 		"\t\t\t*ctx = orig_ctx;\n"
308 		"\t\t\treturn error;\n"
309 		"\t\t}\n\n",
310 		ckv->key);
311 
312 	for (ident_count = 1 ; ident_count < kvlist->count; ident_count++) {
313 		struct keyval *ulkv = kvlist->item[ident_count];
314 
315 		if (strcmp(ulkv->key, "ALLOW") == 0) {
316 			fprintf(outputf,
317 				"\t\tif ((%s) == false) {\n"
318 				"\t\t\t*ctx = orig_ctx;\n"
319 				"\t\t\treturn CSS_INVALID;\n"
320 				"\t\t}\n\n",
321 				ulkv->val);
322 		} else if (strcmp(ulkv->key, "DISALLOW") == 0) {
323 			fprintf(outputf,
324 				"\t\tif (%s) {\n"
325 				"\t\t\t*ctx = orig_ctx;\n"
326 				"\t\t\treturn CSS_INVALID;\n"
327 				"\t\t}\n\n",
328 				ulkv->val);
329 		} else if (strcmp(ulkv->key, "RANGE") == 0) {
330 			fprintf(outputf,
331 				"\t\tif (length %s) {\n"
332 				"\t\t\t*ctx = orig_ctx;\n"
333 				"\t\t\treturn CSS_INVALID;\n"
334 				"\t\t}\n\n",
335 				ulkv->val);
336 		}
337 
338 	}
339 
340 	fprintf(outputf,
341 		"\t\terror = css__stylesheet_style_appendOPV(result, %s, 0, %s);\n"
342 		"\t\tif (error != CSS_OK) {\n"
343 		"\t\t\t*ctx = orig_ctx;\n"
344 		"\t\t\treturn error;\n"
345 		"\t\t}\n"
346 		"\n"
347 		"\t\terror = css__stylesheet_style_vappend(result, 2, length, unit);\n"
348 		"\t}\n\n",
349 		parseid->val,
350 		ckv->val);
351 }
352 
353 void
output_ident_list(FILE * outputf,struct keyval * parseid,struct keyval_list * kvlist)354 output_ident_list(FILE *outputf,
355 		  struct keyval *parseid,
356 		  struct keyval_list *kvlist)
357 {
358 	struct keyval *ckv = kvlist->item[0]; /* list type : opv value */
359 	struct keyval *ikv;
360 
361 	if (strcmp(ckv->key, "STRING_OPTNUM") != 0) {
362 		fprintf(stderr, "unknown IDENT list type %s\n", ckv->key);
363 		exit(4);
364 	}
365 
366 	if (kvlist->count < 2) {
367 		fprintf(stderr, "Not enough parameters to IDENT list type %s\n", ckv->key);
368 		exit(4);
369 	}
370 
371 	/* list of IDENT and optional numbers */
372 	ikv = kvlist->item[1]; /* numeric default : end condition */
373 
374 	fprintf(outputf,
375 		"{\n"
376 		"\t\terror = css__stylesheet_style_appendOPV(result, %s, 0, %s);\n"
377 		"\t\tif (error != CSS_OK) {\n"
378 		"\t\t\t*ctx = orig_ctx;\n"
379 		"\t\t\treturn error;\n"
380 		"\t\t}\n\n"
381 		"\t\twhile ((token != NULL) && (token->type == CSS_TOKEN_IDENT)) {\n"
382 		"\t\t\tuint32_t snumber;\n"
383 		"\t\t\tcss_fixed num;\n"
384 		"\t\t\tint pctx;\n\n"
385 		"\t\t\terror = css__stylesheet_string_add(c->sheet, lwc_string_ref(token->idata), &snumber);\n"
386 		"\t\t\tif (error != CSS_OK) {\n"
387 		"\t\t\t\t*ctx = orig_ctx;\n"
388 		"\t\t\t\treturn error;\n"
389 		"\t\t\t}\n\n"
390 		"\t\t\terror = css__stylesheet_style_append(result, snumber);\n"
391 		"\t\t\tif (error != CSS_OK) {\n"
392 		"\t\t\t\t*ctx = orig_ctx;\n"
393 		"\t\t\t\treturn error;\n"
394 		"\t\t\t}\n\n"
395 		"\t\t\tconsumeWhitespace(vector, ctx);\n\n"
396 		"\t\t\tpctx = *ctx;\n"
397 		"\t\t\ttoken = parserutils_vector_iterate(vector, ctx);\n"
398 		"\t\t\tif ((token != NULL) && (token->type == CSS_TOKEN_NUMBER)) {\n"
399 		"\t\t\t\tsize_t consumed = 0;\n\n"
400 		"\t\t\t\tnum = css__number_from_lwc_string(token->idata, true, &consumed);\n"
401 		"\t\t\t\tif (consumed != lwc_string_length(token->idata)) {\n"
402 		"\t\t\t\t\t*ctx = orig_ctx;\n"
403 		"\t\t\t\t\treturn CSS_INVALID;\n"
404 		"\t\t\t\t}\n"
405 		"\t\t\t\tconsumeWhitespace(vector, ctx);\n\n"
406 		"\t\t\t\tpctx = *ctx;\n"
407 		"\t\t\t\ttoken = parserutils_vector_iterate(vector, ctx);\n"
408 		"\t\t\t} else {\n"
409 		"\t\t\t\tnum = INTTOFIX(%s);\n"
410 		"\t\t\t}\n\n"
411 		"\t\t\terror = css__stylesheet_style_append(result, num);\n"
412 		"\t\t\tif (error != CSS_OK) {\n"
413 		"\t\t\t\t*ctx = orig_ctx;\n"
414 		"\t\t\t\treturn error;\n"
415 		"\t\t\t}\n\n"
416 		"\t\t\tif (token == NULL)\n"
417 		"\t\t\t\tbreak;\n\n"
418 		"\t\t\tif (token->type == CSS_TOKEN_IDENT) {\n"
419 		"\t\t\t\terror = css__stylesheet_style_append(result, %s);\n"
420 		"\t\t\t\tif (error != CSS_OK) {\n"
421 		"\t\t\t\t\t*ctx = orig_ctx;\n"
422 		"\t\t\t\t\treturn error;\n"
423 		"\t\t\t\t}\n"
424 		"\t\t\t} else {\n"
425 		"\t\t\t\t*ctx = pctx; /* rewind one token back */\n"
426 		"\t\t\t}\n"
427 		"\t\t}\n\n"
428 		"\t\terror = css__stylesheet_style_append(result, %s);\n"
429 		"\t}\n\n",
430 		parseid->val,
431 		ckv->val,
432 		ikv->key,
433 		ckv->val,
434 		ikv->val);
435 }
436 
output_invalidcss(FILE * outputf)437 void output_invalidcss(FILE *outputf)
438 {
439 	fprintf(outputf, "{\n\t\terror = CSS_INVALID;\n\t}\n\n");
440 }
441 
output_footer(FILE * outputf)442 void output_footer(FILE *outputf)
443 {
444 	fprintf(outputf,
445 		"	if (error != CSS_OK)\n"
446 		"		*ctx = orig_ctx;\n"
447 		"	\n"
448 		"	return error;\n"
449 		"}\n\n");
450 }
451 
output_wrap(FILE * outputf,struct keyval * parseid,struct keyval_list * WRAP)452 void output_wrap(FILE *outputf, struct keyval *parseid, struct keyval_list *WRAP)
453 {
454 	struct keyval *ckv = WRAP->item[0];
455 	fprintf(outputf,
456 		"	return %s(c, vector, ctx, result, %s);\n}\n",
457 		ckv->val,
458 		parseid->val);
459 }
460 
461 char str_INHERIT[] = "INHERIT";
462 
463 struct keyval ident_inherit = {
464 	.key = str_INHERIT,
465 };
466 
main(int argc,char ** argv)467 int main(int argc, char **argv)
468 {
469 	char *descriptor;
470 	char *curpos; /* current position in input string */
471 	struct keyval *parser_id; /* the parser we are creating output for */
472 	FILE *outputf;
473 	struct keyval *rkv; /* current read key:val */
474 	struct keyval_list *curlist;
475 	bool do_token_check = true; /* if the check for valid tokens is done */
476 	bool only_ident = true; /* if the only token type is ident */
477 	bool is_generic = false;
478 
479 	struct keyval_list base;
480 	struct keyval_list IDENT;
481 	struct keyval_list IDENT_LIST;
482 	struct keyval_list LENGTH_UNIT;
483 	struct keyval_list URI;
484 	struct keyval_list WRAP;
485 	struct keyval_list NUMBER;
486 	struct keyval_list COLOR;
487 
488 
489 	if (argc < 2) {
490 		fprintf(stderr,"Usage: %s [-o <filename>] <descriptor>\n", argv[0]);
491 		return 1;
492 	}
493 
494 	if ((argv[1][0] == '-') && (argv[1][1] == 'o')) {
495 		if (argc != 4) {
496 			fprintf(stderr,"Usage: %s [-o <filename>] <descriptor>\n", argv[0]);
497 			return 1;
498 		}
499 		outputf = fopen(argv[2], "w");
500 		if (outputf == NULL) {
501 			perror("unable to open file");
502 			return 2; /* exit on output file output error */
503 		}
504 		descriptor = strdup(argv[3]);
505 	} else {
506 		outputf = stdout;
507 		descriptor = strdup(argv[1]);
508 	}
509 	curpos = descriptor;
510 
511 	base.count = 0;
512 	IDENT.count = 0;
513 	URI.count = 0;
514 	WRAP.count = 0;
515 	NUMBER.count = 0;
516 	COLOR.count = 0;
517 	LENGTH_UNIT.count = 0;
518 	IDENT_LIST.count = 0;
519 
520 	curlist = &base;
521 
522 	while (*curpos != 0) {
523 		rkv = get_keyval(&curpos);
524 		if (rkv == NULL) {
525 			fprintf(stderr,"Token error at offset %ld\n",
526 					(long)(curpos - descriptor));
527 			fclose(outputf);
528 			return 2;
529 		}
530 
531 		if (strcmp(rkv->key, "WRAP") == 0) {
532 			WRAP.item[WRAP.count++] = rkv;
533 			only_ident = false;
534 		} else if (strcmp(rkv->key, "NUMBER") == 0) {
535 			if (rkv->val[0] == '(') {
536 				curlist = &NUMBER;
537 			} else if (rkv->val[0] == ')') {
538 				curlist = &base;
539 			} else {
540 				NUMBER.item[NUMBER.count++] = rkv;
541 			}
542 			only_ident = false;
543 		} else if (strcmp(rkv->key, "IDENT") == 0) {
544 			if (rkv->val[0] == '(') {
545 				curlist = &IDENT;
546 			} else if (rkv->val[0] == ')') {
547 				curlist = &base;
548 			} else if (strcmp(rkv->val, str_INHERIT) == 0) {
549 				IDENT.item[IDENT.count++] = &ident_inherit;
550 			}
551 		} else if (strcmp(rkv->key, "IDENT_LIST") == 0) {
552 			if (rkv->val[0] == '(') {
553 				curlist = &IDENT_LIST;
554 			} else if (rkv->val[0] == ')') {
555 				curlist = &base;
556 			}
557 		} else if (strcmp(rkv->key, "LENGTH_UNIT") == 0) {
558 			if (rkv->val[0] == '(') {
559 				curlist = &LENGTH_UNIT;
560 			} else if (rkv->val[0] == ')') {
561 				curlist = &base;
562 			}
563 			only_ident = false;
564 			do_token_check = false;
565 		} else if (strcmp(rkv->key, "COLOR") == 0) {
566 			COLOR.item[COLOR.count++] = rkv;
567 			do_token_check = false;
568 			only_ident = false;
569 		} else if (strcmp(rkv->key, "URI") == 0) {
570 			URI.item[URI.count++] = rkv;
571 			only_ident = false;
572 		} else if (strcmp(rkv->key, "GENERIC") == 0) {
573 			is_generic = true;
574 		} else {
575 			/* just append to current list */
576 			curlist->item[curlist->count++] = rkv;
577 		}
578 	}
579 
580 	if (base.count != 1) {
581 		fprintf(stderr,"Incorrect base element count (got %d expected 1)\n", base.count);
582 		fclose(outputf);
583 		return 3;
584 	}
585 
586 
587 	/* header */
588 output_header(outputf, descriptor, base.item[0], is_generic);
589 
590 	if (WRAP.count > 0) {
591 		output_wrap(outputf, base.item[0], &WRAP);
592 	} else {
593 		/* check token type is correct */
594 		output_token_type_check(outputf, do_token_check,  &IDENT, &URI, &NUMBER);
595 
596 		if (IDENT.count > 0)
597 			output_ident(outputf, only_ident, base.item[0], &IDENT);
598 
599 		if (URI.count > 0)
600 			output_uri(outputf, base.item[0], &URI);
601 
602 		if (NUMBER.count > 0)
603 			output_number(outputf, base.item[0], &NUMBER);
604 
605 		/* terminal blocks, these end the ladder ie no trailing else */
606 		if (COLOR.count > 0) {
607 			output_color(outputf, base.item[0], &COLOR);
608 		} else if (LENGTH_UNIT.count > 0) {
609 			output_length_unit(outputf, base.item[0], &LENGTH_UNIT);
610 		} else if (IDENT_LIST.count > 0) {
611 			output_ident_list(outputf, base.item[0], &IDENT_LIST);
612 		} else {
613 			output_invalidcss(outputf);
614 		}
615 
616 		output_footer(outputf);
617 
618 	}
619 
620 	fclose(outputf);
621 
622 	return 0;
623 }
624