/* * Copyright (c) 2004 Teodor Sigaev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "tlog.h" #include "tmalloc.h" #include "prs_inf.h" #define INF_WAIT 1 #define INF_COMMENT 2 #define INF_SECTION 3 #define INF_KEY 4 #define INF_WAITVAL 5 #define INF_INQVAL 6 #define INF_INVAL 7 #define INF_QESCAPE 8 #define INF_ESCAPE 9 #define INF_WAITDELIM 10 #define CHECKBUF do { \ if (bufptr-buf+1>=buflen) { \ int diff = bufptr-buf; \ buflen*=2; \ buf=trealloc(buf,buflen); \ bufptr=buf+diff; \ } \ } while(0) #define CHECKMAP do { \ if (mapptr-map+1>=maplen) { \ int diff = mapptr-map; \ maplen*=2; \ map=trealloc(map,maplen); \ mapptr=map+diff; \ } \ } while(0) #define ISKEYNAME(c) ( (c)=='_' || isalnum(c) ) static void clrbackspace(char *ptr, char *buf) { while(ptr>=buf && (*ptr==' '||*ptr=='\t') ) { *ptr='\0'; ptr--; } } InfMap* INFParse(char *file) { FILE *in; int maplen=32, buflen=32; InfMap *mapptr,*map; int state=INF_WAIT, c; char *buf,*bufptr; int lineno=1; if ( (in=fopen(file,"r"))==NULL ) tlog(TL_ALARM|TL_EXIT,"Can't open inf file '%s': %s", file, strerror(errno)); map=mapptr=(InfMap*)tmalloc(sizeof(InfMap)*maplen); buf = bufptr = (char*)tmalloc(buflen); mapptr->section=NULL; while( (c=fgetc(in))!=EOF ) { CHECKBUF; CHECKMAP; if (c=='\r') continue; if ( state==INF_WAIT ) { if ( c=='\n' ) lineno++; else if ( c=='[' ) { bufptr=buf; state=INF_SECTION; } else if ( c=='#' ) state=INF_COMMENT; else if ( ISKEYNAME(c) ) { if ( mapptr->section==NULL ) tlog(TL_ALARM|TL_EXIT, "Undefined section name at line %d, file %s", lineno, file); bufptr=buf; *bufptr=c; bufptr++; state=INF_KEY; } } else if ( state==INF_SECTION ) { if ( c==']' ) { if ( bufptr==buf ) { tlog(TL_ALARM|TL_EXIT, "Void section name at line %d, file %s", lineno, file); } else { if ( mapptr->section ) tfree(mapptr->section); *bufptr='\0'; mapptr->section = tstrdup(buf); bufptr=buf; } state=INF_WAIT; } else if ( ISKEYNAME(c) ) { *bufptr=c; bufptr++; } else tlog( TL_ALARM|TL_EXIT,"Syntax error at line %d, file %s", lineno, file); } else if ( state==INF_COMMENT ) { if (c=='\n') { lineno++; state=INF_WAIT; } } else if ( state==INF_KEY ) { if (ISKEYNAME(c)) { *bufptr=c; bufptr++; } else if (c=='=') { *bufptr='\0'; mapptr->key = tstrdup(buf); bufptr=buf; state=INF_WAITVAL; } else if (c==' ' || c=='\t') { *bufptr='\0'; mapptr->key = tstrdup(buf); bufptr=buf; state=INF_WAITDELIM; } else tlog( TL_ALARM|TL_EXIT,"Syntax error at line %d, file %s", lineno, file); } else if ( state==INF_WAITDELIM ) { if (c=='=') state=INF_WAITVAL; else if (!(c==' ' || c=='\t')) tlog( TL_ALARM|TL_EXIT,"Syntax error at line %d, file %s", lineno, file); } else if ( state==INF_WAITVAL ) { if ( c=='\n' ) { bufptr=buf; *bufptr='\0'; mapptr->value=tstrdup(buf); mapptr++; mapptr->section = tstrdup((mapptr-1)->section); state=INF_WAIT; lineno++; } else if ( c=='\\' ) { bufptr=buf; state=INF_ESCAPE; } else if ( c=='"' ) { bufptr=buf; state=INF_INQVAL; } else if ( !(c==' ' || c=='\t') ) { bufptr=buf; *bufptr=c; bufptr++; state=INF_INVAL; } } else if ( state==INF_ESCAPE ) { *bufptr=c; bufptr++; state=INF_INVAL; if (c=='\n') lineno++; } else if ( state==INF_QESCAPE ) { *bufptr=c; bufptr++; state=INF_INQVAL; if (c=='\n') lineno++; } else if ( state==INF_INVAL ) { if ( c=='#' ) { *bufptr=' '; clrbackspace(bufptr,buf); mapptr->value=tstrdup(buf); mapptr++; mapptr->section = tstrdup((mapptr-1)->section); bufptr=buf; state=INF_COMMENT; } else if (c=='\n') { *bufptr=' '; clrbackspace(bufptr,buf); mapptr->value=tstrdup(buf); mapptr++; mapptr->section = tstrdup((mapptr-1)->section); bufptr=buf; state=INF_WAIT; lineno++; } else if (c=='\\') { state=INF_ESCAPE; } else { *bufptr=c; bufptr++; } } else if ( state==INF_INQVAL ) { if (c=='\\') { state=INF_QESCAPE; } else if ( c=='"' ) { *bufptr='\0'; mapptr->value=tstrdup(buf); mapptr++; mapptr->section = tstrdup((mapptr-1)->section); bufptr=buf; state=INF_WAIT; } else { *bufptr=c; bufptr++; if (c=='\n') lineno++; } } else tlog( TL_CRIT|TL_EXIT,"INFParse: internal error, unknown state %d", state ); } if ( state==INF_INVAL ) { *bufptr=' '; clrbackspace(bufptr,buf); mapptr->value=tstrdup(buf); mapptr++; mapptr->section=NULL; bufptr=buf; } else if ( state!=INF_WAIT ) { tlog( TL_ALARM|TL_EXIT,"Unexpected end of file %s", file); } else if (mapptr->section) { tfree(mapptr->section); mapptr->section=NULL; } tfree(buf); fclose(in); return map; } void INFFree(InfMap *inf) { InfMap *ptr=inf; while(ptr && ptr->section) { tfree(ptr->section); if (ptr->key) tfree(ptr->key); if (ptr->value) tfree(ptr->value); ptr++; } tfree(inf); } InfMap* INFFindInfMap(InfMap *inf, char *sect, char *key) { while(inf && inf->section) { if ( (sect==NULL || strcmp(inf->section,sect)==0) && (key==NULL || strcmp(inf->key,key)==0) ) return inf; inf++; } return NULL; } int INFGetInt(InfMap *inf, char *sect, char *key, int *val) { inf = INFFindInfMap(inf, sect, key); if (inf) { *val=atoi(inf->value); return 0; } return 1; } int INFGetUint(InfMap *inf, char *sect, char *key, u_int32_t *val) { inf = INFFindInfMap(inf, sect, key); if (inf) { *val=strtoul(inf->value, NULL,0); return 0; } return 1; } int INFGetFloat(InfMap *inf, char *sect, char *key, float *val) { inf = INFFindInfMap(inf, sect, key); if (inf) { *val=strtof(inf->value, NULL); return 0; } return 1; } int INFGetDouble(InfMap *inf, char *sect, char *key, double *val) { inf = INFFindInfMap(inf, sect, key); if (inf) { *val=strtod(inf->value, NULL); return 0; } return 1; } int INFGetString(InfMap *inf, char *sect, char *key, char **val) { inf = INFFindInfMap(inf, sect, key); if (inf) { *val=tstrdup(inf->value); return 0; } return 1; } static int parseBool(char *str) { struct { char *key; int val; } bdata[] = { {"1", 1}, {"0", 0}, {"on", 1}, {"off", 0}, {"enable", 1}, {"disable", 0}, {"true", 1}, {"false", 0}, {"yes", 1}, {"no", 0} }; int i; while(*str && isspace(*str)) str++; for(i=0;ivalue); return 0; } return 1; }