Subversion Repositories Kolibri OS

Rev

Rev 4364 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

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