/* \file apconf.c
*
* \brief Very simple scanner and parser for limited apache-like configuration
* files.
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <regex.h>
#include <string.h>
#include <stdlib.h>
#include "logger.h"
#include "apconf.h"
#define TOKEN_COUNT 6
#define MATCH_MAX 100
typedef enum {
TOKEN_SERVER,
TOKEN_ORDER,
TOKEN_MATCH,
TOKEN_CLOSE,
TOKEN_COMMENT,
TOKEN_BLANK,
TOKEN_EOF
} token;
char *token_string[TOKEN_COUNT]={
"[ \t]*<[ \t]*server[ \t]+([^>\n]+)>\n",
"[ \t]*order[ \t]+([^\n]+)[ \t]*\n",
"[ \t]*match[ \t]+([^\n]+)[ \t]*\n",
"[ \t]*<[ \t]*/[ \t]*server[ \t]*>[ \t]*\n",
"[ \t]*#.*\n",
"[ \t]*\n"};
regex_t token_regex[TOKEN_COUNT];
/* GLOBALS */
int line_no;
char scanner_text[1024];
section *apconf_getsec(apconf *a, char *name) {
int i;
for(i=0;i<a->count;++i) {
if(!strcmp(name, a->s[i].name)) {
return &(a->s[i]);
}
}
return NULL;
}
int compile_re() {
int i;
for(i=0;i<TOKEN_COUNT;i++) {
int ec=regcomp(&token_regex[i], token_string[i], REG_EXTENDED);
if(ec) {
char err[1024];
regerror(ec, &token_regex[i], err, 1024);
logger(LOG_ERR, "Regex Error: %s", err);
return 1;
}
}
return 0;
}
token scan_string(char *s) {
int i;
regmatch_t r[MATCH_MAX];
compile_re();
for(i=0;i<TOKEN_COUNT;i++) {
int m=regexec(&token_regex[i], s , MATCH_MAX, r, 0);
if(!m) {
memset(scanner_text, 0, 1024);
strncpy(scanner_text, s+r[1].rm_so,
r[1].rm_eo-r[1].rm_so > 1024 ?
1024 : r[1].rm_eo-r[1].rm_so);
return i;
}
}
return -1;
}
token scan(FILE *f) {
char buff[1024];
memset(buff, 0, 1024);
if(!fgets(buff, 1024, f))
return TOKEN_EOF;
line_no++;
return(scan_string(buff));
}
apc_param *parse_rule_apc_param(FILE *f) {
static apc_param p;
token t;
t=scan(f);
switch(t) {
case TOKEN_MATCH:
p.t=PARAM_MATCH;
p.value=strdup(scanner_text);
break;
case TOKEN_ORDER:
p.t=PARAM_ORDER;
p.value=strdup(scanner_text);
break;
case TOKEN_CLOSE:
p.t=PARAM_END;
break;
default:
logger(LOG_ERR, "Parse error at line %d.\n", line_no);
return NULL;
}
return &p;
}
section *parse_rule_section(FILE *f) {
static section s;
apc_param *p;
token t;
t=scan(f);
if(t==TOKEN_COMMENT || t==TOKEN_BLANK) {
s.t=SECTION_IGNORE;
return &s;
}
if(t==TOKEN_EOF) {
s.t=SECTION_EOF;
return &s;
}
if(t!=TOKEN_SERVER) {
logger(LOG_ERR, "Parse error at line %d.\n", line_no);
return NULL;
}
s.t=SECTION_STANZA;
s.name=strdup(scanner_text);
while(p=parse_rule_apc_param(f), p->t!=PARAM_END) {
switch(p->t) {
case PARAM_ORDER:
s.order=strdup(p->value);
break;
case PARAM_MATCH:
s.match=strdup(p->value);
break;
default:
logger(LOG_ERR, "SERIOUS COCK-UP in apconf.c");
return NULL;
}
}
return &s;
}
apconf *parse_rule_top(FILE *f) {
apconf *a;
section *s;
a=malloc(sizeof(a));
if(!a) {
logger(LOG_ERR, "Out of memory.");
return NULL;
}
memset(a, 0, sizeof(a));
while(!feof(f)) {
s=parse_rule_section(f);
if(s == NULL)
return NULL;
if(s->t == SECTION_EOF)
return a;
if(s->t == SECTION_STANZA) {
if(a->count == SECTION_MAX) {
logger(LOG_ERR, "Too many sections in file");
return NULL;
}
a->s[a->count++] = *s;
}
}
return a;
}
apconf *apconf_read(char *filename) {
FILE *f;
apconf *a;
f=fopen(filename, "r");
if(f==NULL) {
logger(LOG_ERR, "Unable to open %s for reading.", filename);
return NULL;
}
line_no=0;
if(compile_re()) {
return NULL;
}
a=parse_rule_top(f);
fclose(f);
return a;
}
syntax highlighted by Code2HTML, v. 0.9.1