--- /dev/null
+/**
+ * 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);
--- /dev/null
+#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 */
--- /dev/null
+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);
+}
+*/
--- /dev/null
+%{
+#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);
+}