#include #include #include #include "internal.h" #include "dnsconf.m" extern CONFIG_FILE f_conf; PUBLIC BIND8_LEXPARSE::BIND8_LEXPARSE ( CONFIG_FILE &_cfg, SSTRING &_dir) : cfg (_cfg) { tbf[0].fin = cfg.fopen ("r"); tbf[0].path.setfrom (cfg.getpath()); tbf[0].noline = 0; nofile = 0; buf[0] = '\0'; ptbuf = buf; err = false; dir = &_dir; } PUBLIC BIND8_LEXPARSE::~BIND8_LEXPARSE () { for (int i=nofile; i>=0; i--){ if (tbf[i].fin != NULL) fclose (tbf[i].fin); } } PUBLIC bool BIND8_LEXPARSE::isok() { return tbf[0].fin != NULL; } PRIVATE int BIND8_LEXPARSE::fillbuf() { int ret = -1; while (nofile >= 0){ if (fgets(buf,sizeof(buf)-1,tbf[nofile].fin)!=NULL){ tbf[nofile].noline++; ptbuf = buf; ret = 0; break; }else{ fclose (tbf[nofile].fin); tbf[nofile].fin = NULL; nofile--; } } return ret; } /* Is this a special lexical character */ static bool bind8_isspecial(char car) { return car == '{' || car == ';' || car == '}' || car == '/'; } /* Retrieve one token from the named.conf file */ PUBLIC const char *BIND8_LEXPARSE::gettoken( bool keepquote) // The the " around the token { comment.setfrom (""); const char *ret = NULL; while (1){ const char *start = ptbuf; ptbuf = str_skip(ptbuf); while (ptbuf[0] == '\0'){ if (fillbuf()==-1) return NULL; start = buf; ptbuf = str_skip(ptbuf); } char car = ptbuf[0]; if (car == '/' && ptbuf[1] == '/'){ comment.append (start); if (fillbuf()==-1) return NULL; }else if (car == '#'){ comment.append (start); if (fillbuf()==-1) return NULL; }else if (car == '/' && ptbuf[1] == '*'){ while (1){ if (ptbuf[0] == '\0'){ comment.append (start); if (fillbuf()==-1) return NULL; start = buf; }else if (ptbuf[0] == '*' && ptbuf[1] == '/'){ ptbuf[0] = '\0'; comment.append (start); comment.append ("*/"); ptbuf += 2; break; }else{ ptbuf++; } } }else{ if (bind8_isspecial(car)){ token[0] = *ptbuf++; token[1] = '\0'; }else if (car == '"'){ if (keepquote){ char *ptt = token; *ptt++ = *ptbuf++; while (*ptbuf != '\0'){ car = *ptbuf++; *ptt++ = car; if (car == '"') break; } *ptt = '\0'; }else{ ptbuf = str_copyquote(token,ptbuf); } }else{ char *pt = token; while (*ptbuf > ' ' && !bind8_isspecial(*ptbuf)){ *pt++ = *ptbuf++; } *pt = '\0'; } if (strcmp(token,"include")==0){ const char *incl = getarg1(); if (incl == NULL){ break; }else{ if (nofile < (int)(sizeof(tbf)/sizeof(tbf[0]))){ char abspath[PATH_MAX],tmppath[PATH_MAX]; if (incl[0] != '/'){ snprintf (tmppath,sizeof(tmppath)-1,"%s/%s",dir->get(),incl); incl = tmppath; } context_setabspath (incl,abspath); FILE_CFG *newfin = fopen_cfg (abspath,"r"); if (newfin != NULL){ nofile++; tbf[nofile].path.setfrom (abspath); tbf[nofile].fin = newfin; tbf[nofile].noline = 0; fillbuf(); }else{ error (MSG_U(E_INCLUDE,"Can't open include file %s") ,abspath); } }else{ error (MSG_U(E_TOOMANYINCL,"Too many include files")); } } }else{ ret = token; break; } } } return ret; } /* Retrieve one token from the named.conf file */ PUBLIC const char *BIND8_LEXPARSE::gettoken() { return gettoken(false); } /* Return the path of the file currently processed. */ PUBLIC const char *BIND8_LEXPARSE::getfpath() { return tbf[nofile].path.get(); } PUBLIC void BIND8_LEXPARSE::error(const char *ctl, ...) { char errbuf[1000]; va_list list; va_start (list,ctl); vsnprintf (errbuf,sizeof(errbuf)-1,ctl,list); va_end (list); xconf_error (MSG_U(E_BIND8LEX,"%s\nfile %s line %d") ,errbuf,getfpath(),tbf[nofile].noline); err = true; } /* Get the next token and make sure it is followed by a ; Signal an error and return NULL if not. It also accept "token/token ;" and will return the 3 token as a single one. It also accept ! in front and will return the sequence as a single token. */ PUBLIC const char *BIND8_LEXPARSE::getarg1() { const char *ret = NULL; const char *tok = gettoken(); if (tok != NULL){ const char *not_string = ""; if (strcmp(tok,"!")==0){ not_string = "!"; tok = gettoken(); } if (tok != NULL){ const char *key_string = ""; if (strcmp(tok,"key")==0){ key_string = " key "; tok = gettoken(); } if (tok != NULL){ char tmp[sizeof(token)]; strcpy (tmp,tok); tok = gettoken(); if (tok != NULL){ if (strcmp(tok,";")==0){ snprintf (token,sizeof(token)-1,"%s%s%s" ,not_string,key_string,tmp); ret = token; }else if (strcmp(tok,"/")==0){ tok = gettoken(); if (tok != NULL){ char tmp2[sizeof(token)]; strcpy (tmp2,tok); tok = gettoken(); if (strcmp(tok,";")==0){ snprintf (token,sizeof(token)-1,"%s%s%s/%s" ,not_string,key_string,tmp,tmp2); ret = token; } } } } } } } if (ret == NULL){ error (MSG_U(E_EXPECTARG1,"Expect argument followed by a semi-colon")); } return ret; } /* Get the next token and make sure it is followed by a ; Assume it is either a yes or a no. Return true or false for yes and no. */ PUBLIC bool BIND8_LEXPARSE::getarg_yesno() { bool ret = false; const char *tok = getarg1(); if (tok != NULL && strcmp(tok,"yes")==0) ret = true; return ret; } /* Return true if there was at least one error */ PUBLIC bool BIND8_LEXPARSE::waserr() { return err; } /* Check if the next token is specific string. Signal an error if not. Return -1 if not. */ PUBLIC int BIND8_LEXPARSE::expect (const char *s) { int ret = -1; const char *tok = gettoken(); if (tok != NULL && strcmp(tok,s)==0){ ret = 0; }else{ error (MSG_U(E_EXPECTED,"Expected token %s"),s); } return ret; } /* Get the comment before the token last returned */ PUBLIC const char *BIND8_LEXPARSE::getcomment () { return comment.get(); }