+++ /dev/null
-obcl.lo
-libobcl.la
-.libs
+++ /dev/null
-CFLAGS=-ansi -pedantic -Wall `pkg-config --cflags glib-2.0`
-LIBS=`pkg-config --libs glib-2.0` -ll
-
-targets = cltest
-
-sources = obcl.c main.c parse.c lex.c process.c
-headers = obcl.h
-
-.PHONY: all clean
-
-all: $(targets)
-
-$(targets): $(sources:.c=.o)
- $(CC) -o $@ $^ $(LIBS)
-
-parse.c: parse.y
- $(YACC) -d -o$@ $^
-
-lex.c: lex.l
- $(LEX) -o$@ $^
-
-clean:
- $(RM) $(targets) *.o core *~ lex.c parse.c parse.h
+++ /dev/null
-Note: this is not really a README but more of a thought dump, for now.
-
-overall
--------
-
-obcl wants to be a generic configuration file loader. generic not in
-the sense that it will parse every single configuration format on the
-planet, but in the sense that it will parse a versatile, multi purpose
-format.
-
-parser
-------
-
-this is the part of obcl that when given a configuration file, it will
-return a parse tree. the parse tree can be mucked with by the
-programmer, or it can be checked and processed using the handy checker
-and processor. (for the most part; the programmer will do some
-processing work.)
-
- GList *config = cl_parse_file("foo.conf");
-
-checker
--------
-
-the checker is supposed to help the programmer/application ensure that
-the configuration file is in the correct format. since obcl has a very
-general, the parser itself cannot guarantee that the user will enter a
-correct config file:
-
- foo { }
- fpp { }
-
-will both be parsed, but 'fpp' might be a mistake. the checker is
-intended to fix this.
-
- foo 5;
- blef "foo";
- bar 5, "foo", "hi", 43.4;
-
- woop "hello" {
- foo 5;
- }
-
- CLChecker *check = cl_checker_new();
- cl_checker_add(check, "foo", CL_NUM, 0);
- cl_checker_add(check, "blef", CL_STRING, 0);
- cl_checker_add(check, "bar", CL_NUM, CL_STRING, CL_STRING, CL_NUM, 0);
- cl_checker_add(check, "woop", CL_STRING, CL_BLOCK, 0);
- cl_checker_add_checker(check, "woop", check); /* add checker for block */
-
- int val = cl_check(checker, config, stderr); /* write errors to stderr */
- if (!val) {
- fprintf(stderr, "Parse errors found. Loading default settings\n");
- ...
- }
-
- cl_checker_free(check);
-
-processor
----------
-
-the processor is intended to be run after the checker, to do actual
-'stuff' with the parse tree. once the parse tree has been checked, we
-know that we can just access stuff in the parse tree willy nilly
-without sprinkling asserts all over the code. the processing is done
-via callbacks.
-
- typedef gpointer (*CLCallback)(CLNode *node, gpointer val);
-
- gpointer handle_foo(CLNode *node, gpointer conf)
- {
- /* here numval is a macro that expands to something like
- node->u.num. we know we can access this safely since the checker
- has verified that 'foo' nodes indeed contain numbers.
- same with NTH. it expands to somethign that we don't have to
- worry about. */
- ((Config*)conf)->foo = NUMVAL(NTH(node, 1));
- return 0;
- }
-
- gpointer handle_woop(CLNode *node, gpointer conf, CLProc *proc)
- {
- Config *conf1 = new_conf();
- conf1->name = STRVAL(NTH(node,1));
- cl_process(proc, BLOCK(node), conf1);
- conf_add_child((Config*)conf, conf1);
- return 0;
- }
-
- ...
-
- Config *process_config_file(char *file)
- {
- Config *conf;
- GList *parse_tree;
- CLProc *proc;
- CLChecker *check;
- int err;
-
- config = new_conf();
- parse_tree = cl_parse_file(file);
-
- if (!parse_tree) {
- fprintf(stderr, "your config file is completely borked. loading defaults\n");
- conf_load_defaults(conf);
- return conf;
- }
-
- checker = checker_new();
- ...
- /* add checker stuff to checker, as per above */
-
- err = cl_check(checker, parse_tree);
-
- if (err) {
- fprintf(stderr, "you fucked up. loading defaults\n");
- config_load_defaults(conf);
- return conf;
- }
-
- CLProc *proc = cl_proc_new();
- cl_proc_add(proc, "foo", handle_foo, conf); /* conf will be passed to callback */
- ...
- cl_proc_add_block(proc, "woop", handle_woop, conf, proc);
- cl_process(proc, parse_tree);
-
- return conf;
- }
-
-something like that. lalala.
+++ /dev/null
-foo "marius", 23;
-foo "kyle", 15;
-foo "soren", 7;
-bah "blef","bummy";
-meh {
- foo "marius", 24;
- foo "blef", 542;
- bah "hi";
-}
+++ /dev/null
-%{
-#include "obcl.h"
-#include "parse.h"
-%}
-
-%option yylineno
-
-DGT [0-9]
-ID [a-zA-Z_][a-zA-Z_\.\-0-9]*
-
-
- /* string bummy */
-%x str
-%%
-
- char str_buf[1024];
- char *str_buf_ptr;
- int str_char;
-
- /* begin a string */
-[\"\'] {
- str_buf_ptr = str_buf;
- str_char = yytext[0];
- BEGIN(str);
- }
-
- /* end a string */
-<str>[\"\'] {
- if (yytext[0] == str_char) {
- BEGIN(INITIAL);
- *str_buf_ptr = '\0';
- yylval.string = g_strdup(str_buf);
- return TOK_STRING;
- } else {
- *str_buf_ptr++ = yytext[0];
- }
- }
-
- /* can't have newlines in strings */
-<str>\n {
- printf("Error: Unterminated string constant.\n");
- BEGIN(INITIAL);
- }
-
- /* handle \" and \' */
-<str>"\\"[\"\'] {
- if (yytext[1] == str_char)
- *str_buf_ptr++ = yytext[1];
- else {
- *str_buf_ptr++ = yytext[0];
- *str_buf_ptr++ = yytext[1];
- }
- }
-
- /* eat valid string contents */
-<str>[^\\\n\'\"]+ {
- char *yptr = yytext;
- while (*yptr) {
- *str_buf_ptr++ = *yptr++;
- }
- }
-
- /* numberz */
-{DGT}+ {
- yylval.num = atof(yytext);
- return TOK_NUM;
- }
-
- /* real numbers */
-{DGT}+"."{DGT}* {
- yylval.num = atof(yytext);
- return TOK_NUM;
- }
-
- /* identifiers -- names without spaces and other crap in them */
-{ID} {
- yylval.string = g_strdup(yytext);
- return TOK_ID;
- }
-
- /* skip comments */
-"#".*\n ;
- /* skip other whitespace */
-[ \n\t]+ ;
-. { return yytext[0]; }
-%%
+++ /dev/null
-#include "obcl.h"
-
-void process_foo(CLNode *node)
-{
- if (CL_IS_NODE(node)) {
- printf("foo name: %s\n"
- "foo age: %.2f\n",
- CL_STRVAL(CL_LIST_NTH(node,0)),
- CL_NUMVAL(CL_LIST_NTH(node,1)));
- }
-}
-
-void process_bah(CLNode *node)
-{
- printf("handling bah\n");
-}
-
-int main()
-{
- GList *lst = cl_parse("foo.conf");
-/* cl_tree_print(lst,0); */
-/* cl_tree_free(lst); */
-
-
- CLProc *p = cl_proc_new();
- cl_proc_add_handler_func(p, "foo", process_foo);
- cl_proc_add_handler_func(p, "bah", process_bah);
- cl_proc_add_handler_proc(p,"meh",p);
-
- cl_process(lst, p);
-
- return 0;
-}
+++ /dev/null
-#include "obcl.h"
-
-void cl_tree_free(GList *tree)
-{
- CLNode *tmp;
-
- if (!tree) return;
-
- for (; tree; tree = tree->next) {
- tmp = (CLNode*)tree->data;
- switch(tmp->type) {
- case CL_ID:
- case CL_STR:
- g_free(tmp->u.str);
- break;
- case CL_LIST:
- case CL_BLOCK:
- case CL_LISTBLOCK:
- g_free(tmp->u.lb.id);
- cl_tree_free(tmp->u.lb.list);
- cl_tree_free(tmp->u.lb.block);
- break;
- default:
- break;
- }
- g_free(tmp);
- }
- g_list_free(tree);
-}
-
-GList *cl_parse(gchar *file)
-{
- FILE *fh = fopen(file, "r");
- GList *ret = NULL;
-
- if (fh) {
- ret = cl_parse_fh(fh);
- fclose(fh);
- } else {
- perror(file);
- }
-
- return ret;
-}
-
-void cl_tree_print(GList *tree, int depth)
-{
- CLNode *tmp;
- int tmpd = depth;
-
- for (; tree; tree = tree->next) {
- tmp = (CLNode*)tree->data;
-
- while (tmpd-- > 0)
- printf(" ");
- tmpd = depth;
-
- switch(tmp->type) {
- case CL_ID:
- printf("[ID] '%s'\n", tmp->u.str);
- break;
- case CL_STR:
- printf("[STR] '%s'\n", tmp->u.str);
- break;
- case CL_NUM:
- printf("[NUM] %.2f\n", tmp->u.num);
- break;
- case CL_LIST:
- printf("[LIST] '%s'\n", tmp->u.lb.id);
- cl_tree_print(tmp->u.lb.list, depth+2);
- break;
- case CL_BLOCK:
- printf("[BLOCK] '%s'\n", tmp->u.lb.id);
- cl_tree_print(tmp->u.lb.block, depth+2);
- break;
- case CL_LISTBLOCK:
- printf("[LISTBLOCK] %s\n", tmp->u.lb.id);
- cl_tree_print(tmp->u.lb.list, depth+2);
- printf("\n");
- cl_tree_print(tmp->u.lb.block, depth+2);
- break;
- }
- }
-}
+++ /dev/null
-#ifndef __obcl_h
-#define __obcl_h
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <stdarg.h>
-
-/* TEH MACROS FROM MOUNT DOOM */
-
-#define CL_IS_NODE(X) \
- (((CLNode*)(X))->type == CL_LIST || \
- ((CLNode*)(X))->type == CL_BLOCK || \
- ((CLNode*)(X))->type == CL_LISTBLOCK)
-#define CL_NODE(X) ((CLNode*)(X))
-#define CL_ID(X) (((CLNode*)(X))->u.lb.id)
-#define CL_LIST(X) (((CLNode*)(X))->u.lb.list)
-#define CL_BLOCK(X) (((CLNode*)(X))->u.lb.block)
-#define CL_NUMVAL(X) (((CLNode*)(X))->u.num)
-#define CL_STRVAL(X) (((CLNode*)(X))->u.str)
-#define CL_LINE(X) (((CLNode*)(X))->lineno)
-
-#define CL_ASSERT_NODE(X) \
- g_assert(CL_IS_NODE(X))
-#define CL_ASSERT_NUM(X) \
- g_assert(((CLNode*)(X))->type == CL_NUM)
-#define CL_ASSERT_STR(X) \
- g_assert(((CLNode*)(X))->type == CL_STR)
-
-#define CL_LIST_NTH(X,Y)\
- CL_NODE(g_list_nth(CL_LIST(X),(Y))->data)
-
-typedef enum CLNodeType {
- CL_ID,
- CL_NUM,
- CL_STR,
- CL_LIST,
- CL_BLOCK,
- CL_LISTBLOCK
-} CLNodeType;
-
-typedef struct CLNode {
- CLNodeType type;
- int lineno;
- union {
- struct {
- gchar *id;
- GList *list;
- GList *block;
- } lb;
- double num;
- gchar *str;
- } u;
-
-} CLNode;
-
-typedef void (*CLProcFunc)(CLNode *);
-
-struct CLProcHandler;
-
-typedef struct CLProc {
- GHashTable *table;
- struct CLProcHandler *default_h;
-} CLProc;
-
-typedef enum CLProcHandlerType {
- CLPROC_FUNC,
- CLPROC_PROC
-} CLProcHandlerType;
-
-typedef struct CLProcHandler {
- CLProcHandlerType type;
- union {
- CLProcFunc func;
- CLProc *proc;
- } u;
-} CLProcHandler;
-
-GList *cl_parse(gchar *file);
-GList *cl_parse_fh(FILE *file);
-
-void cl_tree_free(GList *tree);
-void cl_tree_print(GList *tree, int depth);
-
-CLProcHandler *cl_proc_handler_new_func(CLProcFunc f);
-CLProcHandler *cl_proc_handler_new_proc(CLProc *cp);
-CLProc *cl_proc_new(void);
-void cl_proc_free(CLProc *proc);
-void cl_proc_add_handler(CLProc *proc, gchar *str,
- CLProcHandler *handler);
-void cl_proc_add_handler_func(CLProc *proc, gchar *str,
- CLProcFunc func);
-void cl_proc_add_handler_proc(CLProc *proc, gchar *str,
- CLProc *hproc);
-void cl_proc_set_default(CLProc *proc, CLProcHandler *pf);
-void cl_proc_register_keywords(CLProc *proc, ...);
-void cl_process(GList *tree, CLProc *proc);
-
-#endif /* __obcl_h */
+++ /dev/null
-%{
-#include "obcl.h"
-
-int yylex(void);
-void yyerror(char *msg, ...);
-
-extern int yylineno;
-extern char *yytext;
-GList *config; /* this is what we parse into */
-
-%}
-
-%union {
- double num;
- gchar *string;
- CLNode *node;
- GList *glist;
-};
-
-%token <num> TOK_NUM
-%token <string> TOK_ID TOK_STRING
-%token TOK_SEP
-
-%type <glist> config
-%type <glist> stmts
-%type <node> stmt
-%type <glist> list
-%type <glist> block
-%type <node> value
-
-%expect 2 /* for now */
-
-%%
-
-config: stmts
- {
- config = $$ = $1;
- }
- ;
-
-stmts:
- { $$ = NULL; }
- | stmt
- { $$ = g_list_append(NULL, $1); }
- | stmts stmt
- { $$ = g_list_append($1, $2); }
- ;
-
-stmt: TOK_ID list ';'
- {
- CLNode *s = g_new(CLNode,1);
- s->type = CL_LIST;
- s->u.lb.list = $2;
- s->u.lb.block = NULL;
- s->u.lb.id = $1;
- s->lineno = yylineno;
- $$ = s;
- }
- | TOK_ID list block
- {
- CLNode *s = g_new(CLNode,1);
- s->type = CL_LISTBLOCK;
- s->u.lb.list = $2;
- s->u.lb.block = $3;
- s->u.lb.id = $1;
- s->lineno = yylineno;
- $$ = s;
- }
- | TOK_ID block
- {
- CLNode *s = g_new(CLNode,1);
- s->type = CL_BLOCK;
- s->u.lb.block = $2;
- s->u.lb.list = NULL;
- s->u.lb.id = $1;
- s->lineno = yylineno;
- $$ = s;
- }
- ;
-
-list: value
- {
- $$ = g_list_append(NULL, $1);
- }
- | list ',' value
- {
- $$ = g_list_append($1, $3);
- }
- ;
-
-block: '{' stmts '}'
- {
- $$ = $2;
- }
- ;
-
-value: TOK_ID
- {
- CLNode *node = g_new(CLNode,1);
- node->type = CL_ID;
- node->u.str = $1;
- node->lineno = yylineno;
- $$ = node;
- }
- | TOK_STRING
- {
- CLNode *node = g_new(CLNode,1);
- node->type = CL_STR;
- node->u.str = $1;
- node->lineno = yylineno;
- $$ = node;
- }
- | TOK_NUM
- {
- CLNode *node = g_new(CLNode,1);
- node->type = CL_NUM;
- node->u.num = $1;
- node->lineno = yylineno;
- $$ = node;
- }
- ;
-
-%%
-
-int yywrap()
-{
- return 1;
-}
-
-/* void yyerror(const char *err) */
-/* { */
-/* fprintf(stderr, "Parse error on line %d, near '%s': %s\n", */
-/* yylineno, yytext, err); */
-/* } */
-
-void yyerror(char *msg, ...)
-{
- va_list args;
- va_start(args,msg);
-
- fprintf(stderr, "Error on line %d, near '%s': ", yylineno, yytext);
- vfprintf(stderr, msg, args);
- fprintf(stderr,"\n");
-
- va_end(args);
-}
-
-GList *cl_parse_fh(FILE *fh)
-{
- extern FILE *yyin;
- yyin = fh;
- yyparse();
- return config;
-}
+++ /dev/null
-#include "obcl.h"
-
-static void cl_proc_intern_handler(CLNode *node)
-{
- CL_ASSERT_NODE(node);
- g_warning("Unhandled node %s on line %d\n",
- CL_ID(node), CL_LINE(node));
-}
-
-static CLProcHandler *default_handler(void)
-{
- static CLProcHandler *ph = 0;
- if (!ph)
- ph = cl_proc_handler_new_func(cl_proc_intern_handler);
- return ph;
-}
-
-CLProcHandler *cl_proc_handler_new_func(CLProcFunc f)
-{
- CLProcHandler *cph = g_new(CLProcHandler,1);
- cph->type = CLPROC_FUNC;
- cph->u.func = f;
- return cph;
-}
-
-CLProcHandler *cl_proc_handler_new_proc(CLProc *cp)
-{
- CLProcHandler *cph = g_new(CLProcHandler,1);
- cph->type = CLPROC_PROC;
- cph->u.proc = cp;
- return cph;
-}
-
-CLProc *cl_proc_new(void)
-{
- CLProc *ret = g_new(CLProc,1);
- ret->table = g_hash_table_new(g_str_hash,g_str_equal);
- ret->default_h = default_handler();
- return ret;
-}
-
-void cl_proc_free(CLProc *proc)
-{
-
-}
-
-void cl_proc_add_handler(CLProc *proc, gchar *str,
- CLProcHandler *handler)
-{
- g_assert(proc != NULL);
- g_hash_table_replace(proc->table, str, handler);
-}
-
-void cl_proc_add_handler_func(CLProc *proc, gchar *str,
- CLProcFunc func)
-{
- CLProcHandler *ph;
-
- g_assert(proc != NULL);
- ph = cl_proc_handler_new_func(func);
- cl_proc_add_handler(proc, str, ph);
-}
-
-void cl_proc_add_handler_proc(CLProc *proc, gchar *str,
- CLProc *hproc)
-{
- CLProcHandler *ph;
-
- g_assert(proc != NULL);
- ph = cl_proc_handler_new_proc(hproc);
- cl_proc_add_handler(proc, str, ph);
-}
-
-void cl_proc_set_default(CLProc *proc, CLProcHandler *ph)
-{
- g_assert(proc != NULL);
- proc->default_h = ph;
-}
-
-void cl_proc_register_keywords(CLProc *proc, ...)
-{
- va_list args;
- g_assert(proc != NULL);
-
- va_start(args,proc);
- for (;;) {
- gchar *k = va_arg(args, gchar*);
- if (k == NULL)
- break;
- if (g_hash_table_lookup(proc->table, k) != NULL)
- g_hash_table_insert(proc->table, k, default_handler());
- }
- va_end(args);
-}
-
-void cl_process(GList *tree, CLProc *proc)
-{
- GList *lst;
- CLProcHandler *handler;
-
- g_assert(proc != NULL);
-
- if (!tree) return;
-
- for (lst = tree; lst != NULL; lst = lst->next) {
- CL_ASSERT_NODE(lst->data);
- handler = g_hash_table_lookup(proc->table, CL_ID(lst->data));
- if (!handler)
- handler = default_handler();
- if (handler->type == CLPROC_FUNC)
- handler->u.func(CL_NODE(lst->data));
- else
- cl_process(CL_BLOCK(lst->data), handler->u.proc);
- }
-}