summaryrefslogtreecommitdiffstats
path: root/config_parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'config_parser.c')
-rw-r--r--config_parser.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/config_parser.c b/config_parser.c
new file mode 100644
index 0000000..0bd3e5b
--- /dev/null
+++ b/config_parser.c
@@ -0,0 +1,211 @@
+/*
+ *
+ * File : config_parser.c
+ *
+ * Author : Zurcher Jeremy
+ *
+ * Date :
+ *
+ * Purpose :
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "config_parser.h"
+
+#define COMMENT '#'
+#define STREND '\0'
+#define NEWLINE '\n'
+#define TABULATION '\t'
+#define SPACE ' '
+
+enum { NOPE, UNFINISHED_LINE, UNFINISHED_COMMENT };
+
+struct config_reader {
+ int fd;
+ int last;
+ char *pos;
+ char *end;
+ int state;
+ int current_line;
+ char buffer[BUFFLEN];
+};
+
+static struct config_reader reader = { 0 };
+
+#ifdef _DEBUG_
+static void debug_buffer() {
+ printf("\tBUFFER : ");
+ int i;
+ for (i=0; i<BUFFLEN; i++) {
+ char ch = reader.buffer[i];
+ if(ch==NEWLINE)printf("*");
+ else if(ch==STREND)printf("@");
+ else printf("%c",ch);
+ }
+ printf("\n\tpos : %c[%d]\n",*reader.pos,(reader.pos-reader.buffer));
+ printf("\tend : %c[%d]\n",*reader.end,(reader.end-reader.buffer));
+}
+#endif /* _DEBUG_ */
+
+static int feed_buffer(int fd, char *buffer, int len)
+{
+ int ret;
+ if(reader.last) return 0;
+ ret = read(fd,buffer,len);
+ if(ret==-1) return -1;
+ if(ret<len) reader.last = 1;
+ buffer[ret] = STREND;
+ reader.pos = buffer;
+ reader.end = &buffer[ret];
+ return ret;
+}
+
+static char* eat_comment(char *from)
+{
+ int ret;
+ char *tmp;
+ for(;;) {
+ tmp = strchr(from, NEWLINE);
+ if(tmp!=NULL) {
+ reader.current_line++;
+ return tmp;
+ }
+ ret = feed_buffer(reader.fd, reader.buffer, BUFFLEN-1);
+ if(ret==-1) return (char*)-1;
+ if(ret==0) return NULL;
+ from = reader.pos;
+ }
+}
+
+static char* clean_tail(char *str)
+{
+ char *tmp = strchr(str, COMMENT);
+ if(tmp!=NULL) {
+ *tmp=STREND;
+ reader.state = UNFINISHED_COMMENT;
+ } else {
+ reader.state = UNFINISHED_LINE;
+ }
+ tmp = strchr(str, STREND);
+ for(;;) {
+ tmp--;
+ if(*tmp!=SPACE && *tmp!=TABULATION) break;
+ }
+ tmp++;
+ *tmp=STREND;
+ return tmp;
+}
+
+static char* prepare_line()
+{
+ int len;
+ int ret;
+ char *cret;
+ char *tmp;
+ tmp = strchr(reader.pos, NEWLINE);
+ if(tmp!=NULL) {
+ *tmp=STREND;
+ cret = reader.pos;
+ reader.pos = tmp+1;
+ clean_tail(cret);
+ reader.state = NOPE;
+ return cret;
+ }
+ len = (reader.end-reader.pos);
+ memmove(reader.buffer,reader.pos,len);
+ reader.pos = reader.buffer+len;
+ ret = feed_buffer(reader.fd, reader.pos, reader.end-reader.pos);
+ if(ret==-1) return (char*)-1;
+ tmp = strchr(reader.pos, NEWLINE);
+ if(tmp!=NULL) {
+ *tmp=STREND;
+ reader.pos = tmp+1;
+ clean_tail(reader.buffer);
+ reader.state = NOPE;
+ }
+ else {
+ clean_tail(reader.pos);
+ }
+ return reader.buffer;
+}
+
+static char* find_next_token()
+{
+ int ret;
+ char *end;
+ char *tmp = reader.pos;
+ if(reader.state==UNFINISHED_COMMENT){
+ tmp=eat_comment(reader.pos);
+ if(tmp==(char*)-1) return (char*)-1;
+ if(tmp==NULL) return NULL;
+ reader.state=NOPE;
+ }
+ else if (reader.state==UNFINISHED_LINE) {
+ ret = feed_buffer(reader.fd, reader.buffer, BUFFLEN-1);
+ if(ret==-1) return (char*)-1;
+ if(ret==0) return NULL;
+ reader.state=NOPE;
+ return prepare_line();
+ }
+ end = reader.end;
+ reader.current_line++;
+ for(;;) {
+ if(tmp==end) {
+ int ret = feed_buffer(reader.fd, reader.buffer, BUFFLEN-1);
+ if(ret==-1) return (char*)-1;
+ if(ret==0) return NULL;
+ tmp = reader.pos;
+ end = reader.end;
+ }
+ if(*tmp==NEWLINE) {
+ reader.current_line++;
+ }
+ else if(*tmp==COMMENT) {
+ tmp = eat_comment(tmp);
+ if(tmp==(char*)-1) return (char*)-1;
+ if(tmp==NULL) return NULL;
+ end = reader.end;
+ }
+ else if(*tmp!=SPACE || *tmp!=TABULATION) {
+ reader.pos = tmp;
+ return prepare_line();
+ }
+ tmp++;
+ }
+}
+
+static int init(char *filename)
+{
+ if(reader.fd) close(reader.fd);
+ reader.fd = open(filename,O_RDONLY);
+ if(reader.fd==-1) return 1;
+ reader.state = NOPE;
+ reader.last = 0;
+ reader.current_line = 0;
+ reader.pos = reader.end = reader.buffer;
+ return 0;
+}
+
+int read_config(char *filename, config_callback callback)
+{
+ int ret = EXIT_SUCCESS;
+ char *token;
+ if(init(filename)) return EXIT_FAILURE;
+ for(;;) {
+ token = find_next_token();
+ if(token==NULL) break;
+ if(token==(char*)-1) { ret=EXIT_FAILURE; break; }
+ ret = callback(token,reader.state!=NOPE);
+ if(ret) break;
+ }
+ close(reader.fd);
+ reader.fd = -1;
+ return ret;
+}