Initial commit.
authorFlorian Forster <sifnfors@faui02k.informatik.uni-erlangen.de>
Wed, 7 Feb 2007 10:33:47 +0000 (11:33 +0100)
committerFlorian Forster <sifnfors@faui02k.informatik.uni-erlangen.de>
Wed, 7 Feb 2007 10:33:47 +0000 (11:33 +0100)
src/oconfig.c [new file with mode: 0644]
src/oconfig.h [new file with mode: 0644]
src/parser.lex [new file with mode: 0644]
src/parser.y [new file with mode: 0644]

diff --git a/src/oconfig.c b/src/oconfig.c
new file mode 100644 (file)
index 0000000..6ba77a0
--- /dev/null
@@ -0,0 +1,165 @@
+/**
+ * octo's object oriented config library.
+ * Copyright (C) 2006  Florian octo Forster <octo at verplant.org>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#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 (file)
index 0000000..29a6429
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef OCONFIG_H
+#define OCONFIG_H 1
+
+#include <stdio.h>
+
+/**
+ * oconfig - src/oconfig.h
+ * Copyright (C) 2006,2007  Florian octo Forster <octo at verplant.org>
+ *
+ * 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 (file)
index 0000000..3a7c466
--- /dev/null
@@ -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 (file)
index 0000000..911363c
--- /dev/null
@@ -0,0 +1,208 @@
+%{
+#include <stdlib.h>
+#include <string.h>
+#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> NUMBER
+%token <boolean> TRUE FALSE
+%token <string> QUOTED_STRING UNQUOTED_STRING
+%token SLASH OPENBRAC CLOSEBRAC EOL
+
+%type <string> string
+%type <string> identifier
+%type <string> block_end
+%type <cv> argument
+%type <al> argument_list
+%type <ci> block_begin
+%type <ci> block
+%type <ci> option
+%type <ci> statement
+%type <sl> 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 ("<unknown type %i>", cv.type);
+       }
+       printf ("\n");
+
+       for (i = 0; i < ci->children_num; i++)
+               dump_ci (ci->children + i, shift + 1);
+}