From ecc2abe9d0b6834303db0983a0a81ba17de44475 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Wed, 7 Feb 2007 11:33:47 +0100 Subject: [PATCH] Initial commit. --- src/oconfig.c | 165 +++++++++++++++++++++++++++++++++++++++++++++ src/oconfig.h | 67 +++++++++++++++++++ src/parser.lex | 52 +++++++++++++++ src/parser.y | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 492 insertions(+) create mode 100644 src/oconfig.c create mode 100644 src/oconfig.h create mode 100644 src/parser.lex create mode 100644 src/parser.y diff --git a/src/oconfig.c b/src/oconfig.c new file mode 100644 index 0000000..6ba77a0 --- /dev/null +++ b/src/oconfig.c @@ -0,0 +1,165 @@ +/** + * octo's object oriented config library. + * Copyright (C) 2006 Florian octo Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2, as published + * by the Free Software Foundation. + * + * This program 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 + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include "oconfig.h" + +/* + * private structures + */ +struct oconfig_obj +{ + oconfig_item_obj_t *items; +}; + +struct oconfig_item_obj +{ + char *key; + char *value; + + oconfig_item_obj_t *child; + oconfig_item_obj_t *sibling; +}; + +/* + * private functions + */ +static oconfig_item_obj_t *oconfig_item_alloc (const char *key, const char *value) +{ + oconfig_item_obj_t *ret; + + ret = calloc (1, sizeof (oconfig_item_obj_t)); + + if ((ret->key = strdup (key)) == NULL) + { + free (ret); + return (NULL); + } + + if ((ret->value = strdup (value)) == NULL) + { + free (ret->key); + free (ret); + return (NULL); + } + + return (ret); +} + +static void oconfig_item_free (oconfig_item_obj_t *item) +{ + /* This temporary variable is used to prevent endless loops. They + * should not exist, but it doesn't cost much, so what the heck.. */ + oconfig_item_obj_t *temp; + + if (item->child != NULL) + { + temp = item->child; + item->child = NULL; + oconfig_item_free (temp); + } + + if (item->sibling != NULL) + { + temp = item->sibling; + item->sibling = NULL; + oconfig_item_free (temp); + } + + if (item->key != NULL) + free (item->key); + + if (item->value != NULL) + free (item->value); + + free (item); +} + +static oconfig_item_obj_t *oconfig_item_parse_line (char *buffer) +{ + char *key; + char *value; + size_t value_len; + + key = strtok (buffer, " \t\n\r"); + if (key == NULL) + return (NULL); + + value = strtok (NULL, " \t\n\r"); + if (value == NULL) + return (NULL); + + value_len = strlen (value); + while (value_len > 0) + { + if ((value[value_len - 1] == ' ') + || (value[value_len - 1] == '\t') + || (value[value_len - 1] == '\n') + || (value[value_len - 1] == '\r')) + { + value[value_len - 1] = '\0'; + value_len--; + continue; + } + + break; + } + + if (value_len == 0) + return (NULL); + + return (oconfig_item_alloc (key, value)); +} + +/* + * constructor and destructor + */ +oconfig_obj_t *oconfig_construct (const char *file) +{ + oconfig_obj_t *ret; + + ret = calloc (1, sizeof (oconfig_obj_t)); + + /* FIXME: Implement the actual functionality */ + + return (ret); +} + +void oconfig_destroy (oconfig_obj_t *obj) +{ + assert (obj != NULL); + + if (obj->items != NULL) + oconfig_item_free (obj->items); + + free (obj); +} + +/* + * public methods + */ +oconfig_item_obj_t *oconfig_item_get (oconfig_obj_t *obj); +oconfig_item_obj_t *oconfig_item_get_child (oconfig_item_obj_t *item); +oconfig_item_obj_t *oconfig_item_get_sibling (oconfig_item_obj_t *item); + +const char *oconfig_item_get_key (oconfig_item_obj_t *); +size_t oconfig_item_get_value (oconfig_item_obj_t *, void *buffer, size_t *buffer_size); diff --git a/src/oconfig.h b/src/oconfig.h new file mode 100644 index 0000000..29a6429 --- /dev/null +++ b/src/oconfig.h @@ -0,0 +1,67 @@ +#ifndef OCONFIG_H +#define OCONFIG_H 1 + +#include + +/** + * oconfig - src/oconfig.h + * Copyright (C) 2006,2007 Florian octo Forster + * + * This program 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; only version 2 of the License is applicable. + * + * This program 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 + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Types + */ +#define OCONFIG_TYPE_STRING 0 +#define OCONFIG_TYPE_NUMBER 1 +#define OCONFIG_TYPE_BOOLEAN 2 + +struct oconfig_value_s +{ + union + { + char *string; + double number; + int boolean; + } value; + int type; +}; +typedef struct oconfig_value_s oconfig_value_t; + +struct oconfig_item_s; +typedef struct oconfig_item_s oconfig_item_t; +struct oconfig_item_s +{ + char *key; + oconfig_value_t *values; + int values_num; + + oconfig_item_t *parent; + oconfig_item_t *children; + int children_num; +}; + +/* + * Functions + */ +oconfig_item_t *oconfig_parse_fh (FILE *fh); +oconfig_item_t *oconfig_parse_file (const char *file); + +void oconfig_free (oconfig_item_t *ci); + +/* + * vim: shiftwidth=2:tabstop=8:softtabstop=2 + */ +#endif /* OCONFIG_H */ diff --git a/src/parser.lex b/src/parser.lex new file mode 100644 index 0000000..3a7c466 --- /dev/null +++ b/src/parser.lex @@ -0,0 +1,52 @@ +WHITE_SPACE [\ \t\b] +ALNUM [A-Za-z0-9_] +QUOTED_STRING \"([^\"]+|\\.)*\" +UNQUOTED_STRING {ALNUM}+ +HEX_NUMBER 0[xX][0-9a-fA-F]+ +OCT_NUMBER 0[0-7]+ +DEC_NUMBER [\+\-]?[0-9]+ +FLOAT_NUMBER [\+\-]?[0-9]*\.[0-9]+([eE][\+\-][0-9]+)? +NUMBER ({FLOAT_NUMBER}|{HEX_NUMBER}|{OCT_NUMBER}|{DEC_NUMBER}) +BOOL_TRUE (true|yes|on) +BOOL_FALSE (false|no|off) +COMMENT #.* + +%% +{WHITE_SPACE} | +{COMMENT} {/* nothing */} + +\n {return (EOL);} +"/" {return (SLASH);} +"<" {return (OPENBRAC);} +">" {return (CLOSEBRAC);} +{NUMBER} {yylval.number = strtod (yytext, NULL); return (NUMBER);} +{BOOL_TRUE} {yylval.boolean = 1; return (TRUE);} +{BOOL_FALSE} {yylval.boolean = 0; return (FALSE);} + +{QUOTED_STRING} {yylval.string = strdup (yytext); return (QUOTED_STRING);} +{UNQUOTED_STRING} {yylval.string = strdup (yytext); return (UNQUOTED_STRING);} + +%% +/* +static char *unquote (const char *orig) +{ + char *ret = strdup (orig); + int len; + int i; + + if (ret == NULL) + return (NULL); + + len = strlen (ret); + for (i = 0; i < len; i++) + { + if (ret[i] == '\\') + { + memmove (ret + i; ret + (i + 1); len - (i + 1)); + len--; + } + } + + return (ret); +} +*/ diff --git a/src/parser.y b/src/parser.y new file mode 100644 index 0000000..911363c --- /dev/null +++ b/src/parser.y @@ -0,0 +1,208 @@ +%{ +#include +#include +#include "oconfig.h" + +static oconfig_item_t *ci_root; +static oconfig_item_t *ci_current; + +static oconfig_item_t *statement_list; +static int statement_list_num; + +static oconfig_value_t *argument_list; +static int argument_list_num; + +struct statement_list_s +{ + oconfig_item_t *statement; + int statement_num; +}; +typedef struct statement_list_s statement_list_t; + +struct argument_list_s +{ + oconfig_value_t *argument; + int argument_num; +}; +typedef struct argument_list_s argument_list_t; + +static void dump_ci (oconfig_item_t *ci, int shift); +%} + +%start entire_file + +%union { + double number; + int boolean; + char *string; + oconfig_value_t cv; + oconfig_value_t *cvp; + oconfig_item_t ci; + argument_list_t al; + statement_list_t sl; +} + +%token NUMBER +%token TRUE FALSE +%token QUOTED_STRING UNQUOTED_STRING +%token SLASH OPENBRAC CLOSEBRAC EOL + +%type string +%type identifier +%type block_end +%type argument +%type argument_list +%type block_begin +%type block +%type option +%type statement +%type statement_list + +%% +string: + QUOTED_STRING {$$ = $1;} + | UNQUOTED_STRING {$$ = $1;} + ; + +argument: + NUMBER {$$.value.number = $1; $$.type = OCONFIG_TYPE_NUMBER;} + | TRUE {$$.value.boolean = 1; $$.type = OCONFIG_TYPE_BOOLEAN;} + | FALSE {$$.value.boolean = 0; $$.type = OCONFIG_TYPE_BOOLEAN;} + | string {$$.value.string = $1; $$.type = OCONFIG_TYPE_STRING;} + ; + +argument_list: + argument_list argument + { + $$ = $1; + $$.argument_num++; + $$.argument = realloc ($$.argument, $$.argument_num * sizeof (argument_list_t)); + $$.argument[$$.argument_num-1] = $2; + } + | argument + { + $$.argument = malloc (sizeof (argument_list_t)); + $$.argument[0] = $1; + $$.argument_num = 1; + } + ; + +identifier: + UNQUOTED_STRING {$$ = $1;} + ; + +option: + identifier argument_list EOL + { + memset (&$$, '\0', sizeof ($$)); + $$.key = $1; + $$.values = $2.argument; + $$.values_num = $2.argument_num; + printf ("Option `%s' has %i arguments\n", $$.key, $$.values_num); + } + ; + +block_begin: + OPENBRAC identifier argument_list CLOSEBRAC EOL + { + memset (&$$, '\0', sizeof ($$)); + $$.key = $2; + $$.values = $3.argument; + $$.values_num = $3.argument_num; + printf ("Begin block `%s'\n", $2); + } + ; + +block_end: + OPENBRAC SLASH identifier CLOSEBRAC EOL {$$ = $3; printf ("End block `%s'\n", $3);} + ; + +block: + block_begin statement_list block_end + { + if (strcmp ($1.key, $3) != 0) + yyerror ("Block %s not closed..\n", $1); + $$ = $1; + $$.children = $2.statement; + } + ; + +statement: + option {$$ = $1;} + | block {$$ = $1;} + | EOL {/* ignore */} + ; + +statement_list: + statement_list statement + { + $$ = $1; + $$.statement_num++; + $$.statement = realloc ($$.statement, $$.statement_num * sizeof (statement_list_t)); + $$.statement[$$.statement_num-1] = $2; + printf ("statement_list: length = %i\n", $$.statement_num); + } + | statement + { + $$.statement = malloc (sizeof (statement_list_t)); + $$.statement[0] = $1; + $$.statement_num = 1; + } + ; + +entire_file: + statement_list + { + int i; + for (i = 0; i < $1.statement_num; i++) + dump_ci ($1.statement + i, 0); + } + ; + +%% +#include "lex.yy.c" + +/* +void yyerror (char *s) +{ + fprintf (stderr, "%s\n", s); +} + +int yylex (void) +{ + return (getc (stdin)); +} +*/ + +int main (int argc, char **argv) +{ + yyparse (); + return (0); +} + +static void dump_ci (oconfig_item_t *ci, int shift) +{ + int i; + + if (shift > 0) + printf ("%*s", "", shift); + + printf ("%s", ci->key); + for (i = 0; i < ci->values_num; i++) + { + oconfig_value_t cv = ci->values[i]; + + if (cv.type == OCONFIG_TYPE_STRING) + printf (" `%s'", cv.value.string); + else if (cv.type == OCONFIG_TYPE_NUMBER) + printf (" %lf", cv.value.number); + else if (cv.type == OCONFIG_TYPE_BOOLEAN) + printf (" %s", cv.value.boolean ? "true" : "false"); + else + printf ("", cv.type); + } + printf ("\n"); + + for (i = 0; i < ci->children_num; i++) + dump_ci (ci->children + i, shift + 1); +} -- 2.11.0