/* grecs - Gray's Extensible Configuration System Copyright (C) 2007-2011 Sergey Poznyakoff Grecs is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Grecs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grecs. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include const char * grecs_data_type_string(enum grecs_data_type type) { switch (type) { case grecs_type_void: return "void"; case grecs_type_string: return "string"; case grecs_type_short: case grecs_type_ushort: case grecs_type_int: case grecs_type_uint: case grecs_type_long: case grecs_type_ulong: case grecs_type_size: /*FIXME case grecs_type_off:*/ return "number"; case grecs_type_time: return "time"; case grecs_type_bool: return "boolean"; case grecs_type_ipv4: return "IPv4"; case grecs_type_cidr: return "CIDR"; case grecs_type_host: return "hostname"; case grecs_type_sockaddr: return "sock-addr"; case grecs_type_section: return "section"; } return "UNKNOWN?"; } static void format_level(unsigned level, FILE *stream) { while (level--) fprintf(stream, " "); } void grecs_format_docstring(const char *docstring, unsigned level, FILE *stream) { size_t len = strlen(docstring); int width = 78 - level * 2; if (width < 0) { width = 78; level = 0; } while (len) { size_t seglen; const char *p; for (seglen = 0, p = docstring; p < docstring + width && *p; p++) { if (*p == '\n') { seglen = p - docstring; break; } if (isspace(*p)) seglen = p - docstring; } if (seglen == 0 || *p == 0) seglen = p - docstring; format_level(level, stream); fprintf(stream, "# "); fwrite(docstring, seglen, 1, stream); fputc('\n', stream); len -= seglen; docstring += seglen; if (*docstring == '\n') { docstring++; len--; } else while (*docstring && isspace(*docstring)) { docstring++; len--; } } } void grecs_format_simple_statement(struct grecs_keyword *kwp, unsigned level, FILE *stream) { const char *argstr; if (kwp->docstring) grecs_format_docstring(kwp->docstring, level, stream); format_level(level, stream); if (kwp->argname) argstr = kwp->argname; else argstr = N_("arg"); if (strchr("<[", argstr[0])) fprintf(stream, "%s %s;\n", kwp->ident, gettext(argstr)); else if (strchr (argstr, ':')) fprintf(stream, "%s <%s>;\n", kwp->ident, gettext(argstr)); else { fprintf(stream, "%s <%s: ", kwp->ident, gettext(argstr)); if (GRECS_IS_LIST(kwp->type)) fprintf(stream, "list of %s", gettext(grecs_data_type_string( GRECS_TYPE (kwp->type)))); else fprintf(stream, "%s", gettext(grecs_data_type_string(kwp->type))); fprintf(stream, ">;\n"); } } void grecs_format_block_statement(struct grecs_keyword *kwp, unsigned level, FILE *stream) { if (kwp->docstring) grecs_format_docstring(kwp->docstring, level, stream); format_level(level, stream); fprintf(stream, "%s", kwp->ident); if (kwp->argname) fprintf(stream, " <%s>", gettext(kwp->argname)); fprintf(stream, " {\n"); grecs_format_statement_array(kwp->kwd, 0, level + 1, stream); format_level(level, stream); fprintf(stream, "}\n"); } void grecs_format_statement_array(struct grecs_keyword *kwp, unsigned n, unsigned level, FILE *stream) { for (; kwp->ident; kwp++, n++) { if (n) fputc('\n', stream); if (kwp->type == grecs_type_section) grecs_format_block_statement(kwp, level, stream); else grecs_format_simple_statement(kwp, level, stream); } } void grecs_format_locus(grecs_locus_t *locus, FILE *fp) { fprintf(fp, "%s:%d:", locus->file, locus->line); } void grecs_format_node_ident(struct grecs_node *node, int delim, FILE *fp) { if (node->up) grecs_format_node_ident(node->up, delim, fp); fputc(delim, fp); fprintf(fp, "%s", node->ident); if (node->type == grecs_node_block && !GRECS_VALUE_EMPTY_P(&node->value)) { fputc('=', fp); grecs_format_value(&node->value, fp); } } void grecs_format_value(struct grecs_value *val, FILE *fp) { int i; struct grecs_list_entry *ep; switch (val->type) { case GRECS_TYPE_STRING: fprintf(fp, "\"%s\"", val->v.string); /*FIXME: Quoting*/ break; case GRECS_TYPE_LIST: fputc('(', fp); for (ep = val->v.list->head; ep; ep = ep->next) { grecs_format_value(ep->data, fp); if (ep->next) { fputc(',', fp); fputc(' ', fp); } } fputc(')', fp); break; case GRECS_TYPE_ARRAY: for (i = 0; i < val->v.arg.c; i++) { if (i) fputc(' ', fp); grecs_format_value(&val->v.arg.v[i], fp); } } } void grecs_format_node(struct grecs_node *node, int flags, FILE *fp) { int delim = flags & 0xff; if (!delim) delim = '.'; switch (node->type) { case grecs_node_block: for (node = node->down; node; node = node->next) { grecs_format_node(node, flags, fp); if (node->next) fputc('\n', fp); } break; case grecs_node_stmt: if (flags & GRECS_NODE_FLAG_LOCUS) { grecs_format_locus(&node->locus, fp); fputc(' ', fp); } grecs_format_node_ident(node, delim, fp); fputc(':', fp); fputc(' ', fp); grecs_format_value(&node->value, fp); } }