diff options
Diffstat (limited to 'config_parser.c')
-rw-r--r-- | config_parser.c | 211 |
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; +} |