summaryrefslogtreecommitdiff
path: root/src/parse/properties/css_property_parser_gen.c
diff options
context:
space:
mode:
authorVincent Sanders <vince@netsurf-browser.org>2011-01-19 23:12:37 +0000
committerVincent Sanders <vince@netsurf-browser.org>2011-01-19 23:12:37 +0000
commit6a50bef84ae6a0a67e03ac1356f8d85d15fe09d6 (patch)
tree01f78f04b22517899f603787f6005f70b359271e /src/parse/properties/css_property_parser_gen.c
parent63c21aca7c77b1d37cb64ad2b1fa76d6b0b92f48 (diff)
downloadlibcss-6a50bef84ae6a0a67e03ac1356f8d85d15fe09d6.tar.gz
libcss-6a50bef84ae6a0a67e03ac1356f8d85d15fe09d6.tar.bz2
Merge parser autogeneration and string handling refactor branch r=jmb,kinnison,vince
svn path=/trunk/libcss/; revision=11408
Diffstat (limited to 'src/parse/properties/css_property_parser_gen.c')
-rw-r--r--src/parse/properties/css_property_parser_gen.c613
1 files changed, 613 insertions, 0 deletions
diff --git a/src/parse/properties/css_property_parser_gen.c b/src/parse/properties/css_property_parser_gen.c
new file mode 100644
index 0000000..a348c6a
--- /dev/null
+++ b/src/parse/properties/css_property_parser_gen.c
@@ -0,0 +1,613 @@
+/*
+ * This file generates parts of LibCSS.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2010 Vincent Sanders <vince@netsurf-browser.org>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+/* Descriptors are space separated key:value pairs brackets () are
+ * used to quote in values.
+ *
+ * Examples:
+ * list_style_image:CSS_PROP_LIST_STYLE_IMAGE IDENT:( INHERIT: NONE:0,LIST_STYLE_IMAGE_NONE IDENT:) URI:LIST_STYLE_IMAGE_URI
+ *
+ * list_style_position:CSS_PROP_LIST_STYLE_POSITION IDENT:( INHERIT: INSIDE:0,LIST_STYLE_POSITION_INSIDE OUTSIDE:0,LIST_STYLE_POSITION_OUTSIDE IDENT:)
+*/
+
+struct keyval {
+ char *key;
+ char *val;
+};
+
+struct keyval_list {
+ struct keyval *item[100];
+ int count;
+};
+
+struct keyval *get_keyval(char **pos)
+{
+ char *endpos;
+ struct keyval *nkeyval;
+ int kvlen;
+
+ endpos = strchr(*pos, ' '); /* single space separated pairs */
+ if (endpos == NULL) {
+ /* no space, but might be the end of the input */
+ kvlen = strlen(*pos);
+ if (kvlen == 0)
+ return NULL;
+ endpos = *pos + kvlen;
+ } else {
+ kvlen = (endpos - *pos);
+ }
+ nkeyval = calloc(1, sizeof(struct keyval) + kvlen + 1);
+
+ memcpy(nkeyval + 1, *pos, kvlen);
+
+ nkeyval->key = (char *)nkeyval + sizeof(struct keyval);
+
+ endpos = strchr(nkeyval->key, ':'); /* split key and value on : */
+ if (endpos != NULL) {
+ endpos[0] = 0; /* change : to null terminator */
+ nkeyval->val = endpos + 1; /* skip : */
+ }
+
+ *pos += kvlen; /* update position */
+
+ /* skip spaces */
+ while ((*pos[0] != 0) &&
+ (*pos[0] == ' ')) {
+ (*pos)++;
+ }
+
+ return nkeyval;
+}
+
+void output_header(FILE *outputf, const char *descriptor, struct keyval *parser_id, bool is_generic)
+{
+ fprintf(outputf,
+ "/*\n"
+ " * This file was generated by LibCSS gen_parser \n"
+ " * \n"
+ " * Generated from:\n"
+ " *\n"
+ " * %s\n"
+ " * \n"
+ " * Licensed under the MIT License,\n"
+ " * http://www.opensource.org/licenses/mit-license.php\n"
+ " * Copyright 2010 The NetSurf Browser Project.\n"
+ " */\n"
+ "\n"
+ "#include <assert.h>\n"
+ "#include <string.h>\n"
+ "\n"
+ "#include \"bytecode/bytecode.h\"\n"
+ "#include \"bytecode/opcodes.h\"\n"
+ "#include \"parse/properties/properties.h\"\n"
+ "#include \"parse/properties/utils.h\"\n"
+ "\n"
+ "/**\n"
+ " * Parse %s\n"
+ " *\n"
+ " * \\param c Parsing context\n"
+ " * \\param vector Vector of tokens to process\n"
+ " * \\param ctx Pointer to vector iteration context\n"
+ " * \\param result resulting style\n"
+ "%s"
+ " * \\return CSS_OK on success,\n"
+ " * CSS_NOMEM on memory exhaustion,\n"
+ " * CSS_INVALID if the input is not valid\n"
+ " *\n"
+ " * Post condition: \\a *ctx is updated with the next token to process\n"
+ " * If the input is invalid, then \\a *ctx remains unchanged.\n"
+ " */\n"
+ "css_error parse_%s(css_language *c,\n"
+ " const parserutils_vector *vector, int *ctx,\n"
+ " css_style *result%s)\n"
+ "{\n",
+ descriptor,
+ parser_id->key,
+ is_generic ? " * \\param op Bytecode OpCode for CSS property to encode\n" : "",
+ parser_id->key,
+ is_generic ? ", enum css_properties_e op" : "");
+}
+
+
+void output_token_type_check(FILE *outputf, bool do_token_check, struct keyval_list *IDENT, struct keyval_list *URI, struct keyval_list *NUMBER)
+{
+ fprintf(outputf,
+ " int orig_ctx = *ctx;\n"
+ " css_error error;\n"
+ " const css_token *token;\n"
+ " bool match;\n\n"
+ " token = parserutils_vector_iterate(vector, ctx);\n"
+ " if ((token == NULL)");
+
+ if (do_token_check) {
+ bool prev = false; /* there was a previous check - add && */
+ fprintf(outputf," || (");
+
+ if (IDENT->count > 0) {
+ fprintf(outputf,"(token->type != CSS_TOKEN_IDENT)");
+ prev = true;
+ }
+ if (URI->count > 0) {
+ if (prev) fprintf(outputf," && ");
+ fprintf(outputf,"(token->type != CSS_TOKEN_URI)");
+ prev = true;
+ }
+ if (NUMBER->count > 0) {
+ if (prev) fprintf(outputf," && ");
+ fprintf(outputf,"(token->type != CSS_TOKEN_NUMBER)");
+ prev = true;
+ }
+
+ fprintf(outputf,")");
+ }
+
+ fprintf(outputf,
+ ") {\n"
+ "\t\t*ctx = orig_ctx;\n"
+ "\t\treturn CSS_INVALID;\n"
+ "\t}\n\n\t");
+}
+
+void output_ident(FILE *outputf, bool only_ident, struct keyval *parseid, struct keyval_list *IDENT)
+{
+ int ident_count;
+
+ for (ident_count = 0 ; ident_count < IDENT->count; ident_count++) {
+ struct keyval *ckv = IDENT->item[ident_count];
+
+ fprintf(outputf,
+ "if (");
+ if (!only_ident) {
+ fprintf(outputf,
+ "(token->type == CSS_TOKEN_IDENT) && ");
+ }
+ fprintf(outputf,
+ "(lwc_string_caseless_isequal(token->idata, c->strings[%s], &match) == lwc_error_ok && match)) {\n",
+ ckv->key);
+ if (strcmp(ckv->key,"INHERIT") == 0) {
+ fprintf(outputf,
+ "\t\t\terror = css_stylesheet_style_inherit(result, %s);\n",
+ parseid->val);
+ } else {
+ fprintf(outputf,
+ "\t\t\terror = css_stylesheet_style_appendOPV(result, %s, %s);\n",
+ parseid->val,
+ ckv->val);
+ }
+ fprintf(outputf,
+ "\t} else ");
+ }
+}
+
+void output_uri(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist)
+{
+ struct keyval *ckv = kvlist->item[0];
+
+ fprintf(outputf,
+ "if (token->type == CSS_TOKEN_URI) {\n"
+ " lwc_string *uri = NULL;\n"
+ " uint32_t uri_snumber;\n"
+ "\n"
+ " error = c->sheet->resolve(c->sheet->resolve_pw,\n"
+ " c->sheet->url,\n"
+ " token->idata, &uri);\n"
+ " if (error != CSS_OK) {\n"
+ " *ctx = orig_ctx;\n"
+ " return error;\n"
+ " }\n"
+ "\n"
+ " error = css_stylesheet_string_add(c->sheet, uri, &uri_snumber);\n"
+ " if (error != CSS_OK) {\n"
+ " *ctx = orig_ctx;\n"
+ " return error;\n"
+ " }\n"
+ "\n"
+ " error = css_stylesheet_style_appendOPV(result, %s, 0, %s);\n"
+ " if (error != CSS_OK) {\n"
+ " *ctx = orig_ctx;\n"
+ " return error;\n"
+ " }\n"
+ "\n"
+ " error = css_stylesheet_style_append(result, uri_snumber);\n"
+ " } else ",
+ parseid->val,
+ ckv->val);
+}
+
+void output_number(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist)
+{
+ struct keyval *ckv = kvlist->item[0];
+ int ident_count;
+
+ fprintf(outputf,
+ "if (token->type == CSS_TOKEN_NUMBER) {\n"
+ "\t\tcss_fixed num = 0;\n"
+ "\t\tsize_t consumed = 0;\n\n"
+ "\t\tnum = number_from_lwc_string(token->idata, %s, &consumed);\n"
+ "\t\t/* Invalid if there are trailing characters */\n"
+ "\t\tif (consumed != lwc_string_length(token->idata)) {\n"
+ "\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\treturn CSS_INVALID;\n"
+ "\t\t}\n",
+ ckv->key);
+
+ for (ident_count = 1 ; ident_count < kvlist->count; ident_count++) {
+ struct keyval *ulkv = kvlist->item[ident_count];
+
+ if (strcmp(ulkv->key, "RANGE") == 0) {
+ fprintf(outputf,
+ "\t\tif (%s) {\n"
+ "\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\treturn CSS_INVALID;\n"
+ "\t\t}\n\n",
+ ulkv->val);
+ }
+
+ }
+
+ fprintf(outputf,
+ "\t\terror = css_stylesheet_style_appendOPV(result, %s, 0, %s);\n"
+ "\t\tif (error != CSS_OK) {\n"
+ "\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\treturn error;\n"
+ "\t\t}\n\n"
+ "\t\terror = css_stylesheet_style_append(result, num);\n"
+ "\t} else ",
+ parseid->val,
+ ckv->val);
+}
+
+void output_color(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist)
+{
+ struct keyval *ckv = kvlist->item[0];
+
+ fprintf(outputf,
+ "{\n"
+ "\t\tuint32_t color = 0;\n"
+ "\t\t*ctx = orig_ctx;\n\n"
+ "\t\terror = parse_colour_specifier(c, vector, ctx, &color);\n"
+ "\t\tif (error != CSS_OK) {\n"
+ "\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\treturn error;\n"
+ "\t\t}\n\n"
+ "\t\terror = css_stylesheet_style_appendOPV(result, %s, 0, %s);\n"
+ "\t\tif (error != CSS_OK) {\n"
+ "\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\treturn error;\n"
+ "\t\t}\n"
+ "\n"
+ "\t\terror = css_stylesheet_style_append(result, color);\n"
+ "\t}\n\n",
+ parseid->val,
+ ckv->val);
+}
+
+void output_length_unit(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist)
+{
+ struct keyval *ckv = kvlist->item[0];
+ int ident_count;
+
+
+ fprintf(outputf,
+ "{\n"
+ "\t\tcss_fixed length = 0;\n"
+ "\t\tuint32_t unit = 0;\n"
+ "\t\t*ctx = orig_ctx;\n\n"
+ "\t\terror = parse_unit_specifier(c, vector, ctx, %s, &length, &unit);\n"
+ "\t\tif (error != CSS_OK) {\n"
+ "\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\treturn error;\n"
+ "\t\t}\n\n",
+ ckv->key);
+
+ for (ident_count = 1 ; ident_count < kvlist->count; ident_count++) {
+ struct keyval *ulkv = kvlist->item[ident_count];
+
+ if (strcmp(ulkv->key, "ALLOW") == 0) {
+ fprintf(outputf,
+ "\t\tif ((%s) == false) {\n"
+ "\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\treturn CSS_INVALID;\n"
+ "\t\t}\n\n",
+ ulkv->val);
+ } else if (strcmp(ulkv->key, "DISALLOW") == 0) {
+ fprintf(outputf,
+ "\t\tif (%s) {\n"
+ "\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\treturn CSS_INVALID;\n"
+ "\t\t}\n\n",
+ ulkv->val);
+ } else if (strcmp(ulkv->key, "RANGE") == 0) {
+ fprintf(outputf,
+ "\t\tif (length %s) {\n"
+ "\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\treturn CSS_INVALID;\n"
+ "\t\t}\n\n",
+ ulkv->val);
+ }
+
+ }
+
+ fprintf(outputf,
+ "\t\terror = css_stylesheet_style_appendOPV(result, %s, 0, %s);\n"
+ "\t\tif (error != CSS_OK) {\n"
+ "\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\treturn error;\n"
+ "\t\t}\n"
+ "\n"
+ "\t\terror = css_stylesheet_style_vappend(result, 2, length, unit);\n"
+ "\t}\n\n",
+ parseid->val,
+ ckv->val);
+}
+
+void output_ident_list(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist)
+{
+ struct keyval *ckv = kvlist->item[0]; /* list type : opv value */
+ if (strcmp(ckv->key, "STRING_OPTNUM") == 0) {
+ /* list of IDENT and optional numbers */
+ struct keyval *ikv = kvlist->item[1]; /* numeric default : end condition */
+
+ fprintf(outputf,
+ "{\n"
+ "\t\terror = css_stylesheet_style_appendOPV(result, %s, 0, %s);\n"
+ "\t\tif (error != CSS_OK) {\n"
+ "\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\treturn error;\n"
+ "\t\t}\n\n"
+ "\t\twhile ((token != NULL) && (token->type == CSS_TOKEN_IDENT)) {\n"
+ "\t\t\tuint32_t snumber;\n"
+ "\t\t\tcss_fixed num;\n"
+ "\t\t\tint pctx;\n\n"
+ "\t\t\terror = css_stylesheet_string_add(c->sheet, lwc_string_ref(token->idata), &snumber);\n"
+ "\t\t\tif (error != CSS_OK) {\n"
+ "\t\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\t\treturn error;\n"
+ "\t\t\t}\n\n"
+ "\t\t\terror = css_stylesheet_style_append(result, snumber);\n"
+ "\t\t\tif (error != CSS_OK) {\n"
+ "\t\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\t\treturn error;\n"
+ "\t\t\t}\n\n"
+ "\t\t\tconsumeWhitespace(vector, ctx);\n\n"
+ "\t\t\tpctx = *ctx;\n"
+ "\t\t\ttoken = parserutils_vector_iterate(vector, ctx);\n"
+ "\t\t\tif ((token != NULL) && (token->type == CSS_TOKEN_NUMBER)) {\n"
+ "\t\t\t\tsize_t consumed = 0;\n\n"
+ "\t\t\t\tnum = number_from_lwc_string(token->idata, true, &consumed);\n"
+ "\t\t\t\tif (consumed != lwc_string_length(token->idata)) {\n"
+ "\t\t\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\t\t\treturn CSS_INVALID;\n"
+ "\t\t\t\t}\n"
+ "\t\t\t\tconsumeWhitespace(vector, ctx);\n\n"
+ "\t\t\t\tpctx = *ctx;\n"
+ "\t\t\t\ttoken = parserutils_vector_iterate(vector, ctx);\n"
+ "\t\t\t} else {\n"
+ "\t\t\t\tnum = INTTOFIX(%s);\n"
+ "\t\t\t}\n\n"
+ "\t\t\terror = css_stylesheet_style_append(result, num);\n"
+ "\t\t\tif (error != CSS_OK) {\n"
+ "\t\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\t\treturn error;\n"
+ "\t\t\t}\n\n"
+ "\t\t\tif (token == NULL)\n"
+ "\t\t\t\tbreak;\n\n"
+ "\t\t\tif (token->type == CSS_TOKEN_IDENT) {\n"
+ "\t\t\t\terror = css_stylesheet_style_append(result, %s);\n"
+ "\t\t\t\tif (error != CSS_OK) {\n"
+ "\t\t\t\t\t*ctx = orig_ctx;\n"
+ "\t\t\t\t\treturn error;\n"
+ "\t\t\t\t}\n"
+ "\t\t\t} else {\n"
+ "\t\t\t\t*ctx = pctx; /* rewind one token back */\n"
+ "\t\t\t}\n"
+ "\t\t}\n\n"
+ "\t\terror = css_stylesheet_style_append(result, %s);\n"
+ "\t}\n\n",
+ parseid->val,
+ ckv->val,
+ ikv->key,
+ ckv->val,
+ ikv->val);
+
+ } else {
+ fprintf(stderr, "unknown IDENT list type %s\n",ckv->key);
+ exit(4);
+ }
+
+}
+
+void output_invalidcss(FILE *outputf)
+{
+ fprintf(outputf, "{\n\t\terror = CSS_INVALID;\n\t}\n\n");
+}
+
+void output_footer(FILE *outputf)
+{
+ fprintf(outputf,
+ " if (error != CSS_OK)\n"
+ " *ctx = orig_ctx;\n"
+ " \n"
+ " return error;\n"
+ "}\n\n");
+}
+
+void output_wrap(FILE *outputf, struct keyval *parseid, struct keyval_list *WRAP)
+{
+ struct keyval *ckv = WRAP->item[0];
+ fprintf(outputf,
+ " return %s(c, vector, ctx, result, %s);\n}\n",
+ ckv->val,
+ parseid->val);
+}
+
+char str_INHERIT[] = "INHERIT";
+
+struct keyval ident_inherit = {
+ .key = str_INHERIT,
+};
+
+int main(int argc, char **argv)
+{
+ char *descriptor;
+ char *curpos; /* current position in input string */
+ struct keyval *parser_id; /* the parser we are creating output for */
+ FILE *outputf;
+ struct keyval *rkv; /* current read key:val */
+ struct keyval_list *curlist;
+ bool do_token_check = true; /* if the check for valid tokens is done */
+ bool only_ident = true; /* if the only token type is ident */
+ bool is_generic = false;
+
+ struct keyval_list base;
+ struct keyval_list IDENT;
+ struct keyval_list IDENT_LIST;
+ struct keyval_list LENGTH_UNIT;
+ struct keyval_list URI;
+ struct keyval_list WRAP;
+ struct keyval_list NUMBER;
+ struct keyval_list COLOR;
+
+
+ if (argc < 2) {
+ fprintf(stderr,"Usage: %s [-o <filename>] <descriptor>\n", argv[0]);
+ return 1;
+ }
+
+ if ((argv[1][0] == '-') && (argv[1][1] == 'o')) {
+ if (argc != 4) {
+ fprintf(stderr,"Usage: %s [-o <filename>] <descriptor>\n", argv[0]);
+ return 1;
+ }
+ outputf = fopen(argv[2], "w");
+ if (outputf == NULL) {
+ perror("unable to open file");
+ }
+ descriptor = strdup(argv[3]);
+ } else {
+ outputf = stdout;
+ descriptor = strdup(argv[1]);
+ }
+ curpos = descriptor;
+
+ base.count = 0;
+ IDENT.count = 0;
+ URI.count = 0;
+ WRAP.count = 0;
+ NUMBER.count = 0;
+ COLOR.count = 0;
+ LENGTH_UNIT.count = 0;
+ IDENT_LIST.count = 0;
+
+ curlist = &base;
+
+ while (*curpos != 0) {
+ rkv = get_keyval(&curpos);
+ if (rkv == NULL) {
+ fprintf(stderr,"Token error at offset %ld\n", curpos - descriptor);
+ fclose(outputf);
+ return 2;
+ }
+
+ if (strcmp(rkv->key, "WRAP") == 0) {
+ WRAP.item[WRAP.count++] = rkv;
+ only_ident = false;
+ } else if (strcmp(rkv->key, "NUMBER") == 0) {
+ if (rkv->val[0] == '(') {
+ curlist = &NUMBER;
+ } else if (rkv->val[0] == ')') {
+ curlist = &base;
+ } else {
+ NUMBER.item[NUMBER.count++] = rkv;
+ }
+ only_ident = false;
+ } else if (strcmp(rkv->key, "IDENT") == 0) {
+ if (rkv->val[0] == '(') {
+ curlist = &IDENT;
+ } else if (rkv->val[0] == ')') {
+ curlist = &base;
+ } else if (strcmp(rkv->val, str_INHERIT) == 0) {
+ IDENT.item[IDENT.count++] = &ident_inherit;
+ }
+ } else if (strcmp(rkv->key, "IDENT_LIST") == 0) {
+ if (rkv->val[0] == '(') {
+ curlist = &IDENT_LIST;
+ } else if (rkv->val[0] == ')') {
+ curlist = &base;
+ }
+ } else if (strcmp(rkv->key, "LENGTH_UNIT") == 0) {
+ if (rkv->val[0] == '(') {
+ curlist = &LENGTH_UNIT;
+ } else if (rkv->val[0] == ')') {
+ curlist = &base;
+ }
+ only_ident = false;
+ do_token_check = false;
+ } else if (strcmp(rkv->key, "COLOR") == 0) {
+ COLOR.item[COLOR.count++] = rkv;
+ do_token_check = false;
+ only_ident = false;
+ } else if (strcmp(rkv->key, "URI") == 0) {
+ URI.item[URI.count++] = rkv;
+ only_ident = false;
+ } else if (strcmp(rkv->key, "GENERIC") == 0) {
+ is_generic = true;
+ } else {
+ /* just append to current list */
+ curlist->item[curlist->count++] = rkv;
+ }
+ }
+
+ if (base.count != 1) {
+ fprintf(stderr,"Incorrect base element count (got %d expected 1)\n", base.count);
+ fclose(outputf);
+ return 3;
+ }
+
+
+ /* header */
+output_header(outputf, descriptor, base.item[0], is_generic);
+
+ if (WRAP.count > 0) {
+ output_wrap(outputf, base.item[0], &WRAP);
+ } else {
+ /* check token type is correct */
+ output_token_type_check(outputf, do_token_check, &IDENT, &URI, &NUMBER);
+
+ if (IDENT.count > 0)
+ output_ident(outputf, only_ident, base.item[0], &IDENT);
+
+ if (URI.count > 0)
+ output_uri(outputf, base.item[0], &URI);
+
+ if (NUMBER.count > 0)
+ output_number(outputf, base.item[0], &NUMBER);
+
+ /* terminal blocks, these end the ladder ie no trailing else */
+ if (COLOR.count > 0) {
+ output_color(outputf, base.item[0], &COLOR);
+ } else if (LENGTH_UNIT.count > 0) {
+ output_length_unit(outputf, base.item[0], &LENGTH_UNIT);
+ } else if (IDENT_LIST.count > 0) {
+ output_ident_list(outputf, base.item[0], &IDENT_LIST);
+ } else {
+ output_invalidcss(outputf);
+ }
+
+ output_footer(outputf);
+
+ }
+
+ fclose(outputf);
+
+ return 0;
+}